• Stars
    star
    1,762
  • Rank 26,426 (Top 0.6 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 4 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A spring-boot starter for retrofit, supports rapid integration and feature enhancements.(适用于retrofit的spring-boot-starter,支持快速集成和功能增强)

retrofit-spring-boot-starter

License Build Status Maven central GitHub release License License Author QQ-Group

English Document

适用于retrofit的spring-boot-starter,支持快速集成和功能增强

  1. Spring Boot 3.x 项目,请使用retrofit-spring-boot-starter 3.x
  2. Spring Boot 1.x/2.x 项目,请使用retrofit-spring-boot-starter 2.x

🚀项目持续优化迭代,欢迎大家提ISSUE和PR!麻烦大家能给一颗star,您的star是我们持续更新的动力!

github项目地址:https://github.com/LianjiaTech/retrofit-spring-boot-starter

gitee项目地址:https://gitee.com/lianjiatech/retrofit-spring-boot-starter

示例demo:https://github.com/ismart-yuxi/retrofit-spring-boot-demo

感谢@ismart-yuxi为本项目写的示例demo

功能特性

快速开始

引入依赖

<dependency>
    <groupId>com.github.lianjiatech</groupId>
   <artifactId>retrofit-spring-boot-starter</artifactId>
   <version>3.0.2</version>
</dependency>

如果启动失败,大概率是依赖冲突,烦请引入或者排除相关依赖

定义HTTP接口

接口必须使用@RetrofitClient注解标记!HTTP相关注解可参考官方文档:retrofit官方文档

@RetrofitClient(baseUrl = "${test.baseUrl}")
public interface HttpApi {

    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
}

注意:方法请求路径慎用/开头。对于Retrofit而言,如果baseUrl=http://localhost:8080/api/test/,方法请求路径如果是person,则该方法完整的请求路径是:http://localhost:8080/api/test/person。而方法请求路径如果是/person,则该方法完整的请求路径是:http://localhost:8080/person

注入使用

将接口注入到其它Service中即可使用!

@Service
public class TestService {

    @Autowired
    private HttpApi httpApi;

    public void test() {
       // 使用`httpApi`发起HTTP请求
    }
}

默认情况下,自动使用SpringBoot扫描路径进行RetrofitClient注册。你也可以在配置类加上@RetrofitScan手工指定扫描路径。

HTTP请求相关注解

HTTP请求相关注解,全部使用了Retrofit原生注解,以下是一个简单说明:

注解分类 支持的注解
请求方式 @GET @HEAD @POST @PUT @DELETE @OPTIONS @HTTP
请求头 @Header @HeaderMap @Headers
Query参数 @Query @QueryMap @QueryName
path参数 @Path
form-encoded参数 @Field @FieldMap @FormUrlEncoded
请求体 @Body
文件上传 @Multipart @Part @PartMap
url参数 @Url

详细信息可参考官方文档:retrofit官方文档

配置属性

组件支持了多个可配置的属性,用来应对不同的业务场景,具体可支持的配置属性及默认值如下:

注意:应用只需要配置要更改的配置项!

retrofit:
   # 全局转换器工厂
   global-converter-factories:
      - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
      - retrofit2.converter.jackson.JacksonConverterFactory
   # 全局调用适配器工厂(组件扩展的调用适配器工厂已经内置,这里请勿重复配置)
   global-call-adapter-factories:

   # 全局日志打印配置
   global-log:
      # 启用日志打印
      enable: true
      # 全局日志打印级别
      log-level: info
      # 全局日志打印策略
      log-strategy: basic

   # 全局重试配置
   global-retry:
      # 是否启用全局重试
      enable: false
      # 全局重试间隔时间
      interval-ms: 100
      # 全局最大重试次数
      max-retries: 2
      # 全局重试规则
      retry-rules:
         - response_status_not_2xx
         - occur_io_exception

   # 全局超时时间配置
   global-timeout:
      # 全局读取超时时间
      read-timeout-ms: 10000
      # 全局写入超时时间
      write-timeout-ms: 10000
      # 全局连接超时时间
      connect-timeout-ms: 10000
      # 全局完整调用超时时间
      call-timeout-ms: 0

   # 熔断降级配置
   degrade:
      # 熔断降级类型。默认none,表示不启用熔断降级
      degrade-type: none
      # 全局sentinel降级配置
      global-sentinel-degrade:
         # 是否开启
         enable: false
         # 各降级策略对应的阈值。平均响应时间(ms),异常比例(0-1),异常数量(1-N)
         count: 1000
         # 熔断时长,单位为 s
         time-window: 5
         # 降级策略(0:平均响应时间;1:异常比例;2:异常数量)
         grade: 0

      # 全局resilience4j降级配置
      global-resilience4j-degrade:
         # 是否开启
         enable: false
         # 根据该名称从#{@link CircuitBreakerConfigRegistry}获取CircuitBreakerConfig,作为全局熔断配置
         circuit-breaker-config-name: defaultCircuitBreakerConfig
   # 自动设置PathMathInterceptor的scope为prototype
   auto-set-prototype-scope-for-path-math-interceptor: true

高级功能

超时时间配置

如果仅仅需要修改OkHttpClient的超时时间,可以通过@RetrofitClient相关字段修改,或者全局超时配置修改。

自定义OkHttpClient

如果需要修改OkHttpClient其它配置,可以通过自定义OkHttpClient来实现,步骤如下:

  1. 实现SourceOkHttpClientRegistrar接口,调用SourceOkHttpClientRegistry#register()方法注册OkHttpClient

    @Slf4j
    @Component
    public class CustomSourceOkHttpClientRegistrar implements SourceOkHttpClientRegistrar {
    
        @Override
        public void register(SourceOkHttpClientRegistry registry) {
    
            // 添加testSourceOkHttpClient
            registry.register("testSourceOkHttpClient", new OkHttpClient.Builder()
                    .connectTimeout(Duration.ofSeconds(3))
                    .writeTimeout(Duration.ofSeconds(3))
                    .readTimeout(Duration.ofSeconds(3))
                    .addInterceptor(chain -> {
                        log.info("============use testSourceOkHttpClient=============");
                        return chain.proceed(chain.request());
                    })
                    .build());
        }
    }
  2. 通过@RetrofitClient.sourceOkHttpClient指定当前接口要使用的OkHttpClient

    @RetrofitClient(baseUrl = "${test.baseUrl}", sourceOkHttpClient = "testSourceOkHttpClient")
    public interface CustomOkHttpTestApi {
    
        @GET("person")
        Result<Person> getPerson(@Query("id") Long id);
    }

注意:组件不会直接使用指定的OkHttpClient,而是基于该OkHttpClient创建一个新的。

注解式拦截器

组件提供了注解式拦截器,支持基于url路径匹配拦截,使用的步骤如下:

  1. 继承BasePathMatchInterceptor
  2. 使用@Intercept注解指定要使用的拦截器

如果需要使用多个拦截器,在接口上标注多个@Intercept注解即可。

下面以"给指定请求的url后面拼接timestamp时间戳"为例,介绍下如何使用注解式拦截器。

继承BasePathMatchInterceptor编写拦截处理器

@Component
public class TimeStampInterceptor extends BasePathMatchInterceptor {

    @Override
    public Response doIntercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();
        long timestamp = System.currentTimeMillis();
        HttpUrl newUrl = url.newBuilder()
                .addQueryParameter("timestamp", String.valueOf(timestamp))
                .build();
        Request newRequest = request.newBuilder()
                .url(newUrl)
                .build();
        return chain.proceed(newRequest);
    }
}

默认情况下,组件会自动将BasePathMatchInterceptorscope设置为prototype。 可通过retrofit.auto-set-prototype-scope-for-path-math-interceptor=false关闭该功能。关闭之后,需要手动将scope设置为prototype

@Component
@Scope("prototype")
public class TimeStampInterceptor extends BasePathMatchInterceptor {

   @Override
   public Response doIntercept(Chain chain) throws IOException {
      // ...
   }
}

接口上使用@Intercept进行标注

@RetrofitClient(baseUrl = "${test.baseUrl}")
@Intercept(handler = TimeStampInterceptor.class, include = {"/api/**"}, exclude = "/api/test/savePerson")
@Intercept(handler = TimeStamp2Interceptor.class) // 需要多个,直接添加即可
public interface HttpApi {

    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);

    @POST("savePerson")
    Result<Person> savePerson(@Body Person person);
}

上面的@Intercept配置表示:拦截HttpApi接口下/api/**路径下(排除/api/test/savePerson)的请求,拦截处理器使用TimeStampInterceptor

自定义拦截注解

有的时候,我们需要在"拦截注解"动态传入一些参数,然后在拦截的时候使用这些参数。 这时候,我们可以使用"自定义拦截注解",步骤如下:

  1. 自定义注解。必须使用@InterceptMark标记,并且注解中必须包括include、exclude、handler字段。
  2. 继承BasePathMatchInterceptor编写拦截处理器
  3. 接口上使用自定义注解

例如,我们需要"在请求头里面动态加入accessKeyIdaccessKeySecret签名信息才能再发起HTTP请求",这时候可以自定义@Sign注解来实现。

自定义@Sign注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
    
    String accessKeyId();

    String accessKeySecret();

    String[] include() default {"/**"};

    String[] exclude() default {};

    Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}

@Sign注解中指定了使用的拦截器是SignInterceptor

实现SignInterceptor

@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);
    }
}

注意:accessKeyIdaccessKeySecret字段必须提供setter方法。

拦截器的accessKeyIdaccessKeySecret字段值会依据@Sign注解的accessKeyId()accessKeySecret()值自动注入,如果@Sign指定的是占位符形式的字符串,则会取配置属性值进行注入。

接口上使用@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:
   # 全局日志打印配置
   global-log:
      # 启用日志打印
      enable: true
      # 全局日志打印级别
      log-level: info
      # 全局日志打印策略
      log-strategy: basic

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

  1. NONE:No logs.
  2. BASIC:Logs request and response lines.
  3. HEADERS:Logs request and response lines and their respective headers.
  4. BODY:Logs request and response lines and their respective headers and bodies (if present).

声明式日志打印

如果只需要部分请求才打印日志,可以在相关接口或者方法上使用@Logging注解。

日志打印自定义扩展

如果需要修改日志打印行为,可以继承LoggingInterceptor,并将其配置成Spring bean

聚合日志打印

如果需要将同一个请求的日志聚合在一起打印,可配置AggregateLoggingInterceptor

@Bean
public LoggingInterceptor loggingInterceptor(RetrofitProperties retrofitProperties){
    return new AggregateLoggingInterceptor(retrofitProperties.getGlobalLog());
}

请求重试

组件支持支持全局重试和声明式重试。

全局重试

全局重试默认关闭,默认配置项如下:

retrofit:
  # 全局重试配置
  global-retry:
     # 是否启用全局重试
     enable: false
     # 全局重试间隔时间
     interval-ms: 100
     # 全局最大重试次数
     max-retries: 2
     # 全局重试规则
     retry-rules:
        - response_status_not_2xx
        - occur_io_exception

重试规则支持三种配置:

  1. RESPONSE_STATUS_NOT_2XX:响应状态码不是2xx时执行重试
  2. OCCUR_IO_EXCEPTION:发生IO异常时执行重试
  3. OCCUR_EXCEPTION:发生任意异常时执行重试

声明式重试

如果只有一部分请求需要重试,可以在相应的接口或者方法上使用@Retry注解。

请求重试自定义扩展

如果需要修改请求重试行为,可以继承RetryInterceptor,并将其配置成Spring bean

熔断降级

熔断降级默认关闭,当前支持sentinelresilience4j两种实现。

retrofit:
   # 熔断降级配置
   degrade:
      # 熔断降级类型。默认none,表示不启用熔断降级
      degrade-type: sentinel

Sentinel

配置degrade-type=sentinel开启,然后在相关接口或者方法上声明@SentinelDegrade注解即可。

记得手动引入Sentinel依赖:

<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-core</artifactId>
   <version>1.6.3</version>
</dependency>

此外,还支持全局Sentinel熔断降级:

retrofit:
  # 熔断降级配置
  degrade:
    # 熔断降级类型。默认none,表示不启用熔断降级
    degrade-type: sentinel
    # 全局sentinel降级配置
    global-sentinel-degrade:
      # 是否开启
      enable: true
      # ...其他sentinel全局配置

Resilience4j

配置degrade-type=resilience4j开启。然后在相关接口或者方法上声明@Resilience4jDegrade即可。

记得手动引入Resilience4j依赖:

<dependency>
   <groupId>io.github.resilience4j</groupId>
   <artifactId>resilience4j-circuitbreaker</artifactId>
   <version>1.7.1</version>
</dependency>

通过以下配置可开启全局resilience4j熔断降级:

retrofit:
   # 熔断降级配置
   degrade:
      # 熔断降级类型。默认none,表示不启用熔断降级
      degrade-type: resilience4j
      # 全局resilience4j降级配置
      global-resilience4j-degrade:
         # 是否开启
         enable: true
         # 根据该名称从#{@link CircuitBreakerConfigRegistry}获取CircuitBreakerConfig,作为全局熔断配置
         circuit-breaker-config-name: defaultCircuitBreakerConfig

熔断配置管理:

  1. 实现CircuitBreakerConfigRegistrar接口,注册CircuitBreakerConfig

    @Component
    public class CustomCircuitBreakerConfigRegistrar implements CircuitBreakerConfigRegistrar {
       @Override
       public void register(CircuitBreakerConfigRegistry registry) {
       
             // 替换默认的CircuitBreakerConfig
             registry.register(Constants.DEFAULT_CIRCUIT_BREAKER_CONFIG, CircuitBreakerConfig.ofDefaults());
       
             // 注册其它的CircuitBreakerConfig
             registry.register("testCircuitBreakerConfig", CircuitBreakerConfig.custom()
                     .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
                     .failureRateThreshold(20)
                     .minimumNumberOfCalls(5)
                     .permittedNumberOfCallsInHalfOpenState(5)
                     .build());
       }
    }
  2. 通过circuitBreakerConfigName指定CircuitBreakerConfig。包括retrofit.degrade.global-resilience4j-degrade.circuit-breaker-config-name或者@Resilience4jDegrade.circuitBreakerConfigName

扩展熔断降级

如果用户需要使用其他的熔断降级实现,继承BaseRetrofitDegrade,并将其配置Spring Bean

配置fallback或者fallbackFactory (可选)

如果@RetrofitClient不设置fallback或者fallbackFactory,当触发熔断时,会直接抛出RetrofitBlockException异常。 用户可以通过设置fallback或者fallbackFactory来定制熔断时的方法返回值。

注意:fallback类必须是当前接口的实现类,fallbackFactory必须是FallbackFactory<T> 实现类,泛型参数类型为当前接口类型。另外,fallbackfallbackFactory实例必须配置成Spring Bean

fallbackFactory相对于fallback,主要差别在于能够感知每次熔断的异常原因(cause),参考示例如下:

@Slf4j
@Service
public class HttpDegradeFallback implements HttpDegradeApi {

   @Override
   public Result<Integer> test() {
      Result<Integer> fallback = new Result<>();
      fallback.setCode(100)
              .setMsg("fallback")
              .setBody(1000000);
      return fallback;
   }
}
@Slf4j
@Service
public class HttpDegradeFallbackFactory implements FallbackFactory<HttpDegradeApi> {

   @Override
   public HttpDegradeApi create(Throwable cause) {
      log.error("触发熔断了! ", cause.getMessage(), cause);
      return new HttpDegradeApi() {
         @Override
         public Result<Integer> test() {
            Result<Integer> fallback = new Result<>();
            fallback.setCode(100)
                    .setMsg("fallback")
                    .setBody(1000000);
            return fallback;
         }
      };
   }
}

错误解码器

HTTP发生请求错误(包括发生异常或者响应数据不符合预期)的时候,错误解码器可将HTTP相关信息解码到自定义异常中。你可以在@RetrofitClient注解的errorDecoder() 指定当前接口的错误解码器,自定义错误解码器需要实现ErrorDecoder接口:

微服务之间的HTTP调用

继承ServiceInstanceChooser

用户可以自行实现ServiceInstanceChooser接口,完成服务实例的选取逻辑,并将其配置成Spring Bean。对于Spring Cloud 应用,可以使用如下实现。

@Service
public class SpringCloudServiceInstanceChooser implements ServiceInstanceChooser {
    
   private LoadBalancerClient loadBalancerClient;

   @Autowired
   public SpringCloudServiceInstanceChooser(LoadBalancerClient loadBalancerClient) {
      this.loadBalancerClient = loadBalancerClient;
   }

   /**
    * Chooses a ServiceInstance URI from the LoadBalancer for the specified service.
    *
    * @param serviceId The service ID to look up the LoadBalancer.
    * @return Return the uri of ServiceInstance
    */
   @Override
   public URI choose(String serviceId) {
      ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
      Assert.notNull(serviceInstance, "can not found service instance! serviceId=" + serviceId);
      return serviceInstance.getUri();
   }
}

指定serviceIdpath

@RetrofitClient(serviceId = "${jy-helicarrier-api.serviceId}", path = "/m/count")
public interface ApiCountService {}

全局拦截器

全局应用拦截器

如果我们需要对整个系统的的HTTP请求执行统一的拦截处理,可以实现全局拦截器GlobalInterceptor, 并配置成spring Bean

@Component
public class SourceGlobalInterceptor implements GlobalInterceptor {

   @Autowired
   private TestService testService;

   @Override
   public Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      Request newReq = request.newBuilder()
              .addHeader("source", "test")
              .build();
      testService.test();
      return chain.proceed(newReq);
   }
}

全局网络拦截器

实现NetworkInterceptor接口,并配置成spring Bean

调用适配器

Retrofit可以通过CallAdapterFactoryCall<T>对象适配成接口方法的返回值类型。组件扩展了一些CallAdapterFactory实现:

  1. BodyCallAdapterFactory
    • 同步执行HTTP请求,将响应体内容适配成方法的返回值类型。
    • 任意方法返回值类型都可以使用BodyCallAdapterFactory,优先级最低。
  2. ResponseCallAdapterFactory
    • 同步执行HTTP请求,将响应体内容适配成Retrofit.Response<T>返回。
    • 只有方法返回值类型为Retrofit.Response<T>,才可以使用ResponseCallAdapterFactory
  3. 响应式编程相关CallAdapterFactory

Retrofit会根据方法返回值类型选择对应的CallAdapterFactory执行适配处理,目前支持的返回值类型如下:

  • String:将Response Body适配成String返回。
  • 基础类型(Long/Integer/Boolean/Float/Double):将Response Body适配成上述基础类型
  • 任意Java类型: 将Response Body适配成对应的Java对象返回
  • CompletableFuture<T>: 将Response Body适配成CompletableFuture<T>对象返回
  • Void: 不关注返回类型可以使用Void
  • Response<T>: 将Response适配成Response<T>对象返回
  • Call<T>: 不执行适配处理,直接返回Call<T>对象
  • Mono<T>: Project Reactor响应式返回类型
  • Single<T>Rxjava响应式返回类型(支持Rxjava2/Rxjava3
  • CompletableRxjava响应式返回类型,HTTP请求没有响应体(支持Rxjava2/Rxjava3
@RetrofitClient(baseUrl = "${test.baseUrl}")
public interface HttpApi {

   @POST("getString")
   String getString(@Body Person person);

   @GET("person")
   Result<Person> getPerson(@Query("id") Long id);

   @GET("person")
   CompletableFuture<Result<Person>> getPersonCompletableFuture(@Query("id") Long id);

   @POST("savePerson")
   Void savePersonVoid(@Body Person person);

   @GET("person")
   Response<Result<Person>> getPersonResponse(@Query("id") Long id);

   @GET("person")
   Call<Result<Person>> getPersonCall(@Query("id") Long id);

   @GET("person")
   Mono<Result<Person>> monoPerson(@Query("id") Long id);
   
   @GET("person")
   Single<Result<Person>> singlePerson(@Query("id") Long id);
   
   @GET("ping")
   Completable ping();
}

可以通过继承CallAdapter.Factory扩展CallAdapter

组件支持通过retrofit.global-call-adapter-factories配置全局调用适配器工厂:

retrofit:
  # 全局转换器工厂(组件扩展的`CallAdaptorFactory`工厂已经内置,这里请勿重复配置)
  global-call-adapter-factories:
    # ...

针对每个Java接口,还可以通过@RetrofitClient.callAdapterFactories指定当前接口采用的CallAdapter.Factory

建议:将CallAdapter.Factory配置成Spring Bean

数据转码器

Retrofit使用Converter@Body注解的对象转换成Request Body,将Response Body转换成一个Java对象,可以选用以下几种Converter

  • Gson: com.squareup.Retrofit:converter-gson
  • Jackson: com.squareup.Retrofit:converter-jackson
  • Moshi: com.squareup.Retrofit:converter-moshi
  • Protobuf: com.squareup.Retrofit:converter-protobuf
  • Wire: com.squareup.Retrofit:converter-wire
  • Simple XML: com.squareup.Retrofit:converter-simplexml
  • JAXB: com.squareup.retrofit2:converter-jaxb
  • fastJson:com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory

组件支持通过retrofit.global-converter-factories配置全局Converter.Factory,默认的是retrofit2.converter.jackson.JacksonConverterFactory

如果需要修改Jackson配置,自行覆盖JacksonConverterFactorybean配置即可。

retrofit:
   # 全局转换器工厂
   global-converter-factories:
      - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
      - retrofit2.converter.jackson.JacksonConverterFactory

针对每个Java接口,还可以通过@RetrofitClient.converterFactories指定当前接口采用的Converter.Factory

建议:将Converter.Factory配置成Spring Bean

元注解

@RetrofitClient@Retry@Logging@Resilience4jDegrade等注解支持元注解、继承以及@AliasFor

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Logging(logLevel = LogLevel.WARN)
@Retry(intervalMs = 200)
public @interface MyRetrofitClient {

   @AliasFor(annotation = RetrofitClient.class, attribute = "converterFactories")
   Class<? extends Converter.Factory>[] converterFactories() default {GsonConverterFactory.class};

   @AliasFor(annotation = Logging.class, attribute = "logStrategy")
   LogStrategy logStrategy() default LogStrategy.BODY;
}

其他功能示例

form参数

@FormUrlEncoded
@POST("token/verify")
Object tokenVerify(@Field("source") String source,@Field("signature") String signature,@Field("token") String token);


@FormUrlEncoded
@POST("message")
CompletableFuture<Object> sendMessage(@FieldMap Map<String, Object> param);

文件上传

创建MultipartBody.Part

// 对文件名使用URLEncoder进行编码
public ResponseEntity importTerminology(MultipartFile file){
     String fileName=URLEncoder.encode(Objects.requireNonNull(file.getOriginalFilename()),"utf-8");
     okhttp3.RequestBody requestBody=okhttp3.RequestBody.create(MediaType.parse("multipart/form-data"),file.getBytes());
     MultipartBody.Part part=MultipartBody.Part.createFormData("file",fileName,requestBody);
     apiService.upload(part);
     return ok().build();
}

HTTP上传接口

@POST("upload")
@Multipart
Void upload(@Part MultipartBody.Part file);

文件下载

HTTP下载接口

@RetrofitClient(baseUrl = "https://img.ljcdn.com/hc-picture/")
public interface DownloadApi {

    @GET("{fileKey}")
    Response<ResponseBody> download(@Path("fileKey") String fileKey);
}

HTTP下载使用

@SpringBootTest(classes = RetrofitTestApplication.class)
@RunWith(SpringRunner.class)
public class DownloadTest {
    @Autowired
    DownloadApi downLoadApi;

    @Test
    public void download() throws Exception {
        String fileKey = "6302d742-ebc8-4649-95cf-62ccf57a1add";
        Response<ResponseBody> response = downLoadApi.download(fileKey);
        ResponseBody responseBody = response.body();
        // 二进制流
        InputStream is = responseBody.byteStream();

        // 具体如何处理二进制流,由业务自行控制。这里以写入文件为例
        File tempDirectory = new File("temp");
        if (!tempDirectory.exists()) {
            tempDirectory.mkdir();
        }
        File file = new File(tempDirectory, UUID.randomUUID().toString());
        if (!file.exists()) {
            file.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(file);
        byte[] b = new byte[1024];
        int length;
        while ((length = is.read(b)) > 0) {
            fos.write(b, 0, length);
        }
        is.close();
        fos.close();
    }
}

动态URL

使用@url注解可实现动态URL。此时,baseUrl配置任意合法url即可。例如: http://github.com/ 。运行时只会根据@Url地址发起请求。

注意:@url必须放在方法参数的第一个位置,另外,@GET@POST等注解上,不需要定义端点路径。

 @GET
 Map<String, Object> test3(@Url String url,@Query("name") String name);

DELETE请求添加请求体

@HTTP(method = "DELETE", path = "/user/delete", hasBody = true)

GET请求添加请求体

okhttp3自身不支持GET请求添加请求体,源码如下:

image

image

作者给出了具体原因,可以参考: issue

但是,如果实在需要这么做,可以使用:@HTTP(method = "get", path = "/user/get", hasBody = true),使用小写get绕过上述限制。

反馈建议

如有任何问题,欢迎提issue或者加QQ群反馈。

群号:806714302

QQ群图片

More Repositories

1

BELLE

BELLE: Be Everyone's Large Language model Engine(开源中文对话大模型)
HTML
7,841
star
2

bruno

An enterprise-class package of Flutter components for mobile applications. ( Bruno 是基于一整套设计体系的 Flutter 组件库。)
Dart
3,258
star
3

keframe

Components that optimize Flutter fluency.(Flutter 流畅度优化的通用方案,轻松解决卡顿问题)
Dart
935
star
4

fee

灯塔开源文档地址
JavaScript
875
star
5

hetu

低代码平台, 可视化编辑器,单手打代码,解放你的双手
TypeScript
795
star
6

sosotest

sosotest自动化测试平台
Python
509
star
7

kob

中心化的作业调度系统,定义了任务调度模型,实现了任务调度的统一管理和监控。
Java
423
star
8

d18n

d18n is a data desensitization tool for RDBMS.
Go
162
star
9

gson-plugin

辅助 Gson 库的 gradle 插件,防止 Json 数据解析类型异常。
Groovy
151
star
10

Beike_AspectD

Flutter AOP framework. Now compatible with Flutter v3.10.5
Dart
144
star
11

ProgressLayout

A simple Android library about progress layout
Java
89
star
12

flutter_fdb_package

Flutter应用的调试工具,协助采集性能优化、设计走查、QA测试等数据问题 ,提供UI拾取、UI标尺、取色器、内存信息、FPS检测和展示页面代码等功能。
Dart
85
star
13

LJRouter

Objective-C
83
star
14

lightning

lightning is a tool for binlog parsing. It can generate original SQL or flashback SQL.
Go
74
star
15

ke-ve

一站式的可视化服务集成平台
JavaScript
58
star
16

bk_flutter_image

flutter image,降低内存使用
Dart
48
star
17

flutter_ui_auto_test

贝壳 flutter UI 自动化测试
Dart
47
star
18

json-diff

A tool for find difference between two json-string. Support JSON string depth comparison, support JSON array unordered comparison. (用于比较两个JSON字符串的工具,支持JSON字符串深度比较,支持无序数组比较)
Java
46
star
19

dgraph-sql

Java
40
star
20

athena

An open-source implementation of sequence-to-sequence based speech processing engine
C++
38
star
21

Snap

网页截图
JavaScript
34
star
22

kbms

一个轻量级c++网络框架
C++
31
star
23

UIC

User Information Center
Go
30
star
24

flutter_beike_engine

C++
25
star
25

bucky-core

bucky框架核心模块
JavaScript
14
star
26

cicada-ci

TypeScript
12
star
27

BKFlutterWebNativeBridge

Flutter Web和Flutter Mobile桥接。
Objective-C
9
star
28

benchmark

Objective-C
8
star
29

newsboy

web platform to manage api, support mock service and api test
JavaScript
8
star
30

ked

ked 是基于 Ke Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
TypeScript
4
star
31

bucky-cli

bucky框架业务使用脚手架
JavaScript
3
star
32

Storm-Counter

Storm consumer command queue from Kafka, then parse and excute command to storage numbers into Hbase
Java
2
star
33

athena-model-zoo

Athena-model-zoo can provide a lot of kinds of pre-trained models to be used for others.
2
star
34

gson-plugin-sdk

gson-plugin依赖这个sdk
Java
1
star