当前位置: 代码网 > it编程>编程语言>Java > springboot整合retrofit实现本地接口调用远程服务方式

springboot整合retrofit实现本地接口调用远程服务方式

2025年06月24日 Java 我要评论
一、简介okhttp是一款由square公司开源的java版本http客户端工具。square公司还开源了基于okhttp进一步封装的retrofit工具,用来支持通过接口的方式发起http请求。re

一、简介

okhttp是一款由square公司开源的java版本http客户端工具。

square公司还开源了基于okhttp进一步封装的retrofit工具,用来支持通过接口的方式发起http请求。

retrofit-spring-boot-starter实现了retrofit与springboot框架快速整合,并且支持了部分功能增强,从而极大的简化spring-boot项目下http接口调用开发

二、springboot整合retrofit

1.导入依赖

        <dependency>
            <groupid>com.github.lianjiatech</groupid>
            <artifactid>retrofit-spring-boot-starter</artifactid>
            <version>2.2.22</version>
        </dependency>

2.编写远程测试接口

package com.hl.springbootmybatis.controller;

import cn.hutool.core.collection.listutil;
import cn.hutool.json.jsonutil;
import lombok.data;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.multipartfile;
import java.util.list;
import java.util.map;

/**
 *  测试远程被调用的retrofit接口
 */
@restcontroller
@requestmapping("/test/retrofit/remote")
public class remoteretrofitcontroller {
    
    @getmapping("/t1")
    public list<string> t1(@requestparam("name") string name) {
        return listutil.of(name);
    }

    @deletemapping("/t2/{name}")
    public list<string> t2(@pathvariable("name") string name) {
        return listutil.of(name);
    }

    @postmapping("/t3")
    public map<string, object> t3(@requestbody map<string, object> params) {
        return params;
    }

    @putmapping("/t4")
    public map<string, object> t4(@requestbody map<string, object> params) {
        return params;
    }

    @postmapping("/t5")
    public map<string, object> t5(@requestparam map<string, object> params) {
        return params;
    }

    @postmapping("/t6")
    public string t6(retrofittestmodel model) {
        return jsonutil.tojsonstr(model);
    }

    @postmapping("/t7")
    public string t7(string name) {
        return name;
    }

    @postmapping("/t8")
    public string t8(@requestheader("name") string name) {
        return name;
    }

    @postmapping("/t9")
    public string t9(@requestheader("name") string name, @requestheader("token") string token) {
        return name + ";" + token;
    }

	@getmapping("/t10/{name}")
    public list<string> t10(@pathvariable("name") string name) {
        return listutil.of(name);
    }

    @data
    public static class retrofittestmodel {
        private string name;
    }

}

3.编写本地测试接口

3.1 retrofit的配置信息

###############retrofit配置###############
#连接池相关配置
retrofit.global-connect-timeout-ms= 5000
retrofit.pool.test.max-idle-connection=3
retrofit.pool.test.keep-alive-second=100
#日志打印拦截器配置,可以继承baselogginginterceptor实现自己的日志记录方式
retrofit.logging-interceptor=com.github.lianjiatech.retrofit.spring.boot.interceptor.defaultlogginginterceptor
#异常格式化处理,可以继承basehttpexceptionmessageformatter,实现自己的异常格式化
retrofit。http-exception-message-formatter=com.github.lianjiatech.retrofit.spring.boot.interceptor.defaulthttpexceptionmessageformatter

3.2 本地和测试接口

新建接口,添加@retrofitclient注解,配置baseurl和poolnamepoolname对应上一步的配置

package com.yolo.springbootretrofit.config;

import com.github.lianjiatech.retrofit.spring.boot.annotation.retrofitclient;
import retrofit2.http.*;
import java.util.list;
import java.util.map;

@retrofitclient(baseurl = "http://localhost:9093/",poolname = "test")
public interface httpclient {

    @get("test/retrofit/remote/t1")
    list<string> t1(@query("name") string name);

    /**路径中传参 /{}*/
    @delete("test/retrofit/remote/t2/{name}")
    string t2(@path("name") string name);

    /**使用请求体传送json*/
    @post("test/retrofit/remote/t3")
    map<string, object> t3(@body map<string, object> params);

    /**put请求使用请求体传送json*/
    @put("test/retrofit/remote/t4")
    map<string, object> t4(@body map<string, object> params);

    /**多个url参数使用map传递*/
    @post("test/retrofit/remote/t5")
    map<string, object> t5(@querymap map<string, object> params);

    /**form表单传送数据,多个参数使用map传递*/
    @formurlencoded
    @post("test/retrofit/remote/t6")
    map<string, object> t6(@fieldmap map<string, object> model);

    /**form表单传送数据,多个参数一个一个传递*/
    @formurlencoded
    @post("test/retrofit/remote/t7")
    string t7(@field("name") string name);

    /**header传送数据,多个参数一个一个传递*/
    @post("test/retrofit/remote/t8")
    string t8(@header("name") string name);

    /**header传送数据,多个参数一起传递*/
    @post("test/retrofit/remote/t9")
    @headers({"name:zhangsan", "token:lisi"})
    string t9();

	/**自定义全路径,避免重新写一个httpclient **/
    @get()
    list<string> t10(@url string url) ;

}

3.3 测试

package com.yolo.springbootretrofit.controller;

import com.yolo.springbootretrofit.config.httpclient;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

import javax.annotation.resource;
import java.util.hashmap;
import java.util.list;
import java.util.map;


@restcontroller
@requestmapping("/test/retrofit")
public class retrofittestcontroller {

    @resource
    private httpclient httpclient;

    @getmapping("/t1")
    public list<string> t1() {
        return httpclient.t1("zhangsan");
    }

    @getmapping("t2")
    public string t2() {
        return httpclient.t2("zhangsan");
    }

    @getmapping("t3")
    public map<string, object> t3() {
        map<string, object> map = new hashmap<>();
        map.put("name", "zhangsan");
        return httpclient.t3(map);
    }

    @getmapping("t4")
    public map<string, object> t4() {
        map<string, object> map = new hashmap<>();
        map.put("name", "zhangsan");
        return httpclient.t4(map);
    }

    @getmapping("t5")
    public map<string, object> t5() {
        map<string, object> map = new hashmap<>();
        map.put("name", "zhangsan");
        return httpclient.t5(map);
    }

    @getmapping("t6")
    public map<string, object> t6() {
        map<string, object> map = new hashmap<>();
        map.put("name", "zhangsan");
        return httpclient.t6(map);
    }

    @getmapping("t7")
    public string t7() {
        return httpclient.t7("zhangsan");
    }

    @getmapping("t8")
    public string t8() {
        return httpclient.t8("zhangsan");
    }

    @getmapping("t9")
    public string t9() {
        return httpclient.t9();
    }

	@getmapping("t10")
    public list<string> t10() {
        string s = "http://localhost:9093/test/retrofit/remote/t10/lisi";
        return httpclient.t10(s);
    }
}

4.编写拦截器

可是通过编写拦截器来拦截retrofit的请求,在请求中添加一些统一的处理,拦截器需要继承basepathmatchinterceptor并重写dointercept方法

接口上使用@intercept进行标注

package com.yolo.springbootretrofit.config;

import com.github.lianjiatech.retrofit.spring.boot.interceptor.basepathmatchinterceptor;
import okhttp3.headers;
import okhttp3.httpurl;
import okhttp3.request;
import okhttp3.response;
import org.springframework.stereotype.component;
import java.io.ioexception;


@component
public class simpleinterceptor extends basepathmatchinterceptor {
    @override
    protected response dointercept(chain chain) throws ioexception {
        request request = chain.request();
        httpurl url = request.url();
        url = url.newbuilder().addqueryparameter("time", string.valueof(system.currenttimemillis()))
                .build();
        headers headers = request.headers();
        headers = headers.newbuilder().add("add-header", "lalala").build();
        request = request.newbuilder().headers(headers)
                .url(url).build();
        return chain.proceed(request);
    }
}

在接口类中添加@interceptor注解,handler属性为上面定义的拦截器,include属性为拦截的url,exclude为不拦截的url

@intercept(handler = simpleinterceptor.class, include = {"/demo/test/**"}) //添加拦截器

5.自定义注解拦截器

注意必须添加@interceptmark

package com.yolo.springbootretrofit.config;

import com.github.lianjiatech.retrofit.spring.boot.annotation.interceptmark;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.basepathmatchinterceptor;
import java.lang.annotation.*;

@retention(retentionpolicy.runtime)
@target(elementtype.type)
@documented
@interceptmark //必须加这个注解
public @interface sign {
    /**
     * 密钥key
     * 支持占位符形式配置。
     *
     * @return
     */
    string accesskeyid();

    /**
     * 密钥
     * 支持占位符形式配置。
     *
     * @return
     */
    string accesskeysecret();

    /**
     * 拦截器匹配路径
     *
     * @return
     */
    string[] include() default {"/**"};

    /**
     * 拦截器排除匹配,排除指定路径拦截
     *
     * @return
     */
    string[] exclude() default {};

    /**
     * 处理该注解的拦截器类
     * 优先从spring容器获取对应的bean,如果获取不到,则使用反射创建一个!
     *
     * @return
     */
    class<? extends basepathmatchinterceptor> handler() default signinterceptor.class;
}

accesskeyidaccesskeysecret字段值会依据@sign注解的accesskeyid()accesskeysecret()值自动注入,如果@sign指定的是占位符形式的字符串,则会取配置属性值进行注入。

另外,accesskeyidaccesskeysecret字段必须提供setter方法

package com.yolo.springbootretrofit.config;

import com.github.lianjiatech.retrofit.spring.boot.interceptor.basepathmatchinterceptor;
import okhttp3.request;
import okhttp3.response;
import org.springframework.stereotype.component;

import java.io.ioexception;

@component
public class signinterceptor extends basepathmatchinterceptor {

    private string accesskeyid;

    private string accesskeysecret;

    public void setaccesskeyid(string accesskeyid) {
        this.accesskeyid = accesskeyid;
    }

    public void setaccesskeysecret(string accesskeysecret) {
        this.accesskeysecret = accesskeysecret;
    }

    @override
    public response dointercept(chain chain) throws ioexception {
        request request = chain.request();
        request newreq = request.newbuilder()
                .addheader("accesskeyid", accesskeyid)
                .addheader("accesskeysecret", accesskeysecret)
                .build();
        return chain.proceed(newreq);
    }
}

接口上使用@sign

@retrofitclient(baseurl = "${test.baseurl}")
@sign(accesskeyid = "${test.accesskeyid}", accesskeysecret = "${test.accesskeysecret}", exclude = {"/api/test/person"})
public interface httpapi {

    @get("person")
    result<person> getperson(@query("id") long id);

    @post("saveperson")
    result<person> saveperson(@body person person);
}

三、连接池管理

默认情况下,所有通过retrofit发送的http请求都会使用max-idle-connections=5 keep-alive-second=300的默认连接池。当然,我们也可以在配置文件中配置多个自定义的连接池,然后通过@retrofitclientpoolname属性来指定使用。比如我们要让某个接口下的请求全部使用poolname=test1的连接池

1.配置连接池

retrofit:
    # 连接池配置
    pool:
        test1:
        max-idle-connections: 3
        keep-alive-second: 100
        test2:
        max-idle-connections: 5
        keep-alive-second: 50

2.通过@retrofitclientpoolname属性来指定使用的连接池

@retrofitclient(baseurl = "${test.baseurl}", poolname="test1")
public interface httpapi {
    @get("person")
    result<person> getperson(@query("id") long id);
}

四、日志打印

很多情况下,我们希望将http请求日志记录下来。通过@retrofitclientloglevellogstrategy属性,您可以指定每个接口的日志打印级别以及日志打印策略。

retrofit-spring-boot-starter支持了5种日志打印级别(error, warn, info, debug, trace),默认info;支持了4种日志打印策略(none, basic, headers, body),默认basic

4种日志打印策略含义如下:

  • none:no logs.
  • basic:logs request and response lines.
  • headers:logs request and response lines and their respective headers.
  • body:logs request and response lines and their respective headers and bodies (if present)

retrofit-spring-boot-starter默认使用了defaultlogginginterceptor执行真正的日志打印功能,其底层就是okhttp原生的httplogginginterceptor

当然,你也可以自定义实现自己的日志打印拦截器,只需要继承baselogginginterceptor(具体可以参考defaultlogginginterceptor的实现),然后在配置文件中进行相关配置即可。

retrofit:
  # 日志打印拦截器
  logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.defaultlogginginterceptor

五、http异常信息格式化器

当出现http请求异常时,原始的异常信息可能阅读起来并不友好,因此retrofit-spring-boot-starter提供了http异常信息格式化器,用来美化输出http请求参数,默认使用defaulthttpexceptionmessageformatter进行请求数据格式化。

你也可以进行自定义,只需要继承basehttpexceptionmessageformatter,再进行相关配置即可

retrofit:
  # http异常信息格式化器
  http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.defaulthttpexceptionmessageformatter

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com