영문문서
신속한 통합과 기능 향상을 지원하는 개조용 Spring-boot-starter입니다 .
프로젝트는 계속해서 최적화되고 반복되고 있으며 누구나 문제와 PR을 제출할 수 있습니다! 별점을 주세요. 귀하의 별은 지속적인 업데이트의 원동력이 됩니다!
Github 프로젝트 주소: https://github.com/LianjiaTech/retrofit-spring-boot-starter
gitee 프로젝트 주소: https://gitee.com/lianjiatech/retrofit-spring-boot-starter
샘플 데모: https://github.com/ismart-yuxi/retrofit-spring-boot-demo
이 프로젝트의 샘플 데모를 작성해주신
@ismart-yuxi
에게 감사드립니다.
< dependency >
< groupId >com.github.lianjiatech</ groupId >
< artifactId >retrofit-spring-boot-starter</ artifactId >
< version >3.1.3</ version >
</ dependency >
시작에 실패하면 종속성 충돌이 있을 가능성이 높습니다. 관련 종속성을 도입하거나 제외하세요 .
인터페이스는 @RetrofitClient
주석으로 표시되어야 합니다 ! HTTP 관련 정보는 공식 문서: 개조 공식 문서를 참조하세요.
@ RetrofitClient ( baseUrl = "${test.baseUrl}" )
public interface UserService {
/**
* 根据id查询用户姓名
*/
@ POST ( "getName" )
String getName ( @ Query ( "id" ) Long id );
}
참고: 메소드 요청 경로는 주의해서
/
로 시작해야 합니다 .Retrofit
의 경우baseUrl=http://localhost:8080/api/test/
이고 메서드 요청 경로가person
인 경우 메서드의 전체 요청 경로는http://localhost:8080/api/test/person
입니다. 메서드 요청 경로가/person
인 경우 메서드의 전체 요청 경로는http://localhost:8080/person
입니다.
인터페이스를 다른 서비스에 삽입하고 사용하세요!
@ Service
public class BusinessService {
@ Autowired
private UserService userService ;
public void doBusiness () {
// call userService
}
}
기본적으로 SpringBoot
검색 경로는 RetrofitClient
등록에 자동으로 사용됩니다 . 구성 클래스에 @RetrofitScan
추가하여 스캔 경로를 수동으로 지정할 수도 있습니다.
HTTP
요청과 관련된 주석은 모두 Retrofit
기본 주석을 사용합니다. 다음은 간단한 설명입니다.
주석 분류 | 지원되는 주석 |
---|---|
요청 방법 | @GET @HEAD @POST @PUT @DELETE @OPTIONS @HTTP |
요청 헤더 | @Header @HeaderMap @Headers |
쿼리 매개변수 | @Query @QueryMap @QueryName |
경로 매개변수 | @Path |
양식으로 인코딩된 매개변수 | @Field @FieldMap @FormUrlEncoded |
요청 본문 | @Body |
파일 업로드 | @Multipart @Part @PartMap |
URL 매개변수 | @Url |
자세한 내용은 공식 문서 개조 공식 문서를 참조하세요.
구성요소는 다양한 비즈니스 시나리오에 대처하기 위해 여러 구성 가능한 속성을 지원합니다. 지원되는 특정 구성 속성 및 기본값은 다음과 같습니다.
참고: 애플리케이션은 변경할 구성 항목만 구성하면 됩니다 !
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
# 是否聚合打印请求日志
aggregate : true
# 全局重试配置
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
사용자 정의하여 수행할 수 있습니다. 단계는 다음과 같습니다.
SourceOkHttpClientRegistrar
인터페이스를 구현하고 SourceOkHttpClientRegistry#register()
메서드를 호출하여 OkHttpClient
등록합니다.
@ Component
public class CustomOkHttpClientRegistrar implements SourceOkHttpClientRegistrar {
@ Override
public void register ( SourceOkHttpClientRegistry registry ) {
// 注册customOkHttpClient,超时时间设置为1s
registry . register ( "customOkHttpClient" , new OkHttpClient . Builder ()
. connectTimeout ( Duration . ofSeconds ( 1 ))
. writeTimeout ( Duration . ofSeconds ( 1 ))
. readTimeout ( Duration . ofSeconds ( 1 ))
. addInterceptor ( chain -> chain . proceed ( chain . request ()))
. build ());
}
}
@RetrofitClient.sourceOkHttpClient
를 통해 현재 인터페이스에서 사용할 OkHttpClient
지정합니다.
@ RetrofitClient ( baseUrl = "${test.baseUrl}" , sourceOkHttpClient = "customOkHttpClient" )
public interface CustomOkHttpUserService {
/**
* 根据id查询用户信息
*/
@ GET ( "getUser" )
User getUser ( @ Query ( "id" ) Long id );
}
참고: 구성 요소는 지정된
OkHttpClient
직접 사용하지 않지만OkHttpClient
기반으로 새 구성 요소를 만듭니다.
구성 요소는 URL 경로 일치를 기반으로 가로채기를 지원하는 주석 인터셉터를 제공합니다. 사용 단계는 다음과 같습니다.
BasePathMatchInterceptor
상속@Intercept
주석을 사용하세요.여러 인터셉터를 사용해야 하는 경우 인터페이스에 여러
@Intercept
주석을 표시하면 됩니다.
BasePathMatchInterceptor
상속하세요. @ Component
public class PathMatchInterceptor extends BasePathMatchInterceptor {
@ Override
protected Response doIntercept ( Chain chain ) throws IOException {
Response response = chain . proceed ( chain . request ());
// response的Header加上path.match
return response . newBuilder (). header ( "path.match" , "true" ). build ();
}
}
기본적으로 구성요소는 BasePathMatchInterceptor
의 scope
자동으로 prototype
으로 설정합니다 . 이 기능은 retrofit.auto-set-prototype-scope-for-path-math-interceptor=false
통해 끌 수 있습니다. 닫은 후에는 scope
prototype
으로 수동으로 설정해야 합니다.
@ Component
@ Scope ( "prototype" )
public class PathMatchInterceptor extends BasePathMatchInterceptor {
}
@Intercept
사용하세요. @ RetrofitClient ( baseUrl = "${test.baseUrl}" )
@ Intercept ( handler = PathMatchInterceptor . class , include = { "/api/user/**" }, exclude = "/api/user/getUser" )
// @Intercept() 如果需要使用多个路径匹配拦截器,继续添加@Intercept即可
public interface InterceptorUserService {
/**
* 根据id查询用户姓名
*/
@ POST ( "getName" )
Response < String > getName ( @ Query ( "id" ) Long id );
/**
* 根据id查询用户信息
*/
@ GET ( "getUser" )
Response < User > getUser ( @ Query ( "id" ) Long id );
}
위의 @Intercept
구성은 InterceptorUserService
인터페이스( /api/user/getUser
제외) 아래 /api/user/**
경로에서 요청을 가로채고 가로채기 프로세서가 PathMatchInterceptor
사용함을 의미합니다.
때로는 "가로채기 주석"의 일부 매개변수를 동적으로 전달한 다음 가로챌 때 이러한 매개변수를 사용해야 합니다. 이때 "사용자 정의 차단 주석"을 사용할 수 있습니다. 단계는 다음과 같습니다.
@InterceptMark
표시를 사용해야 하며 주석에는 include、exclude、handler
필드가 포함되어야 합니다.BasePathMatchInterceptor
상속하세요. 예를 들어, "HTTP 요청을 시작하기 전에 accessKeyId
및 accessKeySecret
서명 정보를 요청 헤더에 동적으로 추가"해야 합니다. 이 경우 이를 달성하기 위해 @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
@ Setter
public class SignInterceptor extends BasePathMatchInterceptor {
private String accessKeyId ;
private String accessKeySecret ;
@ Override
public Response doIntercept ( Chain chain ) throws IOException {
Request request = chain . request ();
Request newReq = request . newBuilder ()
. addHeader ( "accessKeyId" , accessKeyId )
. addHeader ( "accessKeySecret" , accessKeySecret )
. build ();
Response response = chain . proceed ( newReq );
return response . newBuilder (). addHeader ( "accessKeyId" , accessKeyId )
. addHeader ( "accessKeySecret" , accessKeySecret ). build ();
}
}
참고:
accessKeyId
및accessKeySecret
필드는setter
메소드를 제공해야 합니다.
인터셉터의 accessKeyId
및 accessKeySecret
필드 값은 @Sign
주석의 accessKeyId()
및 accessKeySecret()
값을 기반으로 자동으로 주입됩니다. @Sign
자리 표시자 형식으로 문자열을 지정하는 경우 구성 속성 값은 주입에 사용됩니다.
@Sign
사용 @ RetrofitClient ( baseUrl = "${test.baseUrl}" )
@ Sign ( accessKeyId = "${test.accessKeyId}" , accessKeySecret = "${test.accessKeySecret}" , include = "/api/user/getAll" )
public interface InterceptorUserService {
/**
* 查询所有用户信息
*/
@ GET ( "getAll" )
Response < List < User >> getAll ();
}
구성 요소는 전역 로그 인쇄 및 선언적 로그 인쇄를 지원합니다.
기본적으로 전역 로그 인쇄가 활성화되어 있으며 기본 구성은 다음과 같습니다.
retrofit :
# 全局日志打印配置
global-log :
# 启用日志打印
enable : true
# 全局日志打印级别
log-level : info
# 全局日志打印策略
log-strategy : basic
# 是否聚合打印请求日志
aggregate : true
# 日志名称,默认为{@link LoggingInterceptor} 的全类名
logName : com.github.lianjiatech.retrofit.spring.boot.log.LoggingInterceptor
네 가지 로그 인쇄 전략의 의미는 다음과 같습니다.
NONE
: 로그가 없습니다.BASIC
: 요청 및 응답 라인을 기록합니다.HEADERS
: 요청 및 응답 줄과 해당 헤더를 기록합니다.BODY
: 요청 및 응답 줄과 해당 헤더 및 본문(있는 경우)을 기록합니다. 일부 요청에 대한 로그만 인쇄해야 하는 경우 관련 인터페이스 또는 메소드에서 @Logging
주석을 사용할 수 있습니다.
로그 인쇄 동작을 수정해야 하는 경우 LoggingInterceptor
상속하고 이를 Spring bean
으로 구성할 수 있습니다.
구성 요소 지원은 전역 재시도 및 선언적 재시도를 지원합니다.
Global retry는 기본적으로 해제되어 있으며, 기본 구성 항목은 다음과 같습니다.
retrofit :
# 全局重试配置
global-retry :
# 是否启用全局重试
enable : false
# 全局重试间隔时间
interval-ms : 100
# 全局最大重试次数
max-retries : 2
# 全局重试规则
retry-rules :
- response_status_not_2xx
- occur_io_exception
재시도 규칙은 세 가지 구성을 지원합니다.
RESPONSE_STATUS_NOT_2XX
: 응답 상태 코드가 2xx
가 아닌 경우 재시도OCCUR_IO_EXCEPTION
: IO 예외 발생 시 재시도 수행OCCUR_EXCEPTION
: 예외 발생 시 재시도 일부 요청만 재시도해야 하는 경우 해당 인터페이스나 메서드에서 @Retry
주석을 사용할 수 있습니다.
요청 재시도 동작을 수정해야 하는 경우 RetryInterceptor
상속하고 이를 Spring bean
으로 구성할 수 있습니다.
회로 차단기 다운그레이드는 기본적으로 꺼져 있으며 현재 sentinel
및 resilience4j
구현을 지원합니다.
retrofit :
# 熔断降级配置
degrade :
# 熔断降级类型。默认none,表示不启用熔断降级
degrade-type : 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全局配置
degrade-type=resilience4j
구성하여 활성화합니다. 그런 다음 관련 인터페이스나 메서드에서 @Resilience4jDegrade
선언합니다.
Resilience4j
종속성을 수동으로 도입해야 합니다.
< dependency >
< groupId >io.github.resilience4j</ groupId >
< artifactId >resilience4j-circuitbreaker</ artifactId >
< version >1.7.1</ version >
</ dependency >
Global resilience4j 회로 차단기 다운그레이드는 다음 구성을 통해 활성화할 수 있습니다.
retrofit :
# 熔断降级配置
degrade :
# 熔断降级类型。默认none,表示不启用熔断降级
degrade-type : resilience4j
# 全局resilience4j降级配置
global-resilience4j-degrade :
# 是否开启
enable : true
# 根据该名称从#{@link CircuitBreakerConfigRegistry}获取CircuitBreakerConfig,作为全局熔断配置
circuit-breaker-config-name : defaultCircuitBreakerConfig
회로 차단기 구성 관리:
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 ());
}
}
CircuitBreakerConfig
circuitBreakerConfigName
에 의해 지정됩니다. retrofit.degrade.global-resilience4j-degrade.circuit-breaker-config-name
또는 @Resilience4jDegrade.circuitBreakerConfigName
을 포함합니다.
사용자가 다른 회로 차단기 성능 저하 구현을 사용해야 하는 경우 BaseRetrofitDegrade
상속하고 이를 Spring Bean
구성합니다.
@RetrofitClient
fallback
또는 fallbackFactory
설정하지 않으면 회로 차단기가 트리거될 때 RetrofitBlockException
직접 발생합니다. 사용자는 fallback
또는 fallbackFactory
설정하여 융합이 발생할 때 메서드 반환 값을 사용자 정의할 수 있습니다.
참고:
fallback
클래스는 현재 인터페이스의 구현 클래스여야 하고,fallbackFactory
FallbackFactory<T>
구현 클래스여야 하며, 일반 매개변수 유형은 현재 인터페이스 유형이어야 합니다. 또한fallback
및fallbackFactory
인스턴스는Spring Bean
로 구성되어야 합니다.
fallback과 비교했을 때 fallbackFactory fallback
fallbackFactory
각 회로 차단기의 이상 원인(원인)을 감지할 수 있다는 점입니다. 참고 예는 다음과 같습니다.
@ 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()
주석에서 현재 인터페이스의 오류 디코더를 지정할 수 있습니다. 사용자 정의 오류 디코더는 ErrorDecoder
인터페이스를 구현해야 합니다.
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 ();
}
}
serviceId
및 path
지정 @ RetrofitClient ( serviceId = "user" , path = "/api/user" )
public interface ChooserOkHttpUserService {
/**
* 根据id查询用户信息
*/
@ GET ( "getUser" )
User getUser ( @ Query ( "id" ) Long id );
}
전체 시스템의 HTTP
요청에 대해 통합 차단 처리를 수행해야 하는 경우 전역 인터셉터인 GlobalInterceptor
구현하고 이를 spring Bean
으로 구성할 수 있습니다.
@ Component
public class MyGlobalInterceptor implements GlobalInterceptor {
@ Override
public Response intercept ( Chain chain ) throws IOException {
Response response = chain . proceed ( chain . request ());
// response的Header加上global
return response . newBuilder (). header ( "global" , "true" ). build ();
}
}
NetworkInterceptor
인터페이스를 구현하고 이를 spring Bean
으로 구성합니다.
Retrofit
CallAdapterFactory
통해 Call<T>
객체를 인터페이스 메서드의 반환 값 유형에 맞게 조정할 수 있습니다. 구성 요소는 일부 CallAdapterFactory
구현을 확장합니다.
BodyCallAdapterFactory
HTTP
요청을 동기적으로 실행하고 응답 본문 내용을 메서드의 반환 값 유형에 맞게 조정합니다.BodyCallAdapterFactory
사용할 수 있습니다.ResponseCallAdapterFactory
HTTP
요청을 동기적으로 실행하고 응답 본문 콘텐츠를 Retrofit.Response<T>
에 맞게 조정한 후 반환합니다.ResponseCallAdapterFactory
메서드 반환 값 유형이 Retrofit.Response<T>
인 경우에만 사용할 수 있습니다.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
지원)Completable
: Rxjava
응답형 반환 유형, HTTP
요청에는 응답 본문이 없습니다( Rxjava2/Rxjava3
지원). CallAdapter
CallAdapter.Factory
상속하여 확장할 수 있습니다.
이 구성 요소는 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
중에서 선택할 수 있습니다.
구성 요소는 retrofit.global-converter-factories
통해 전역 Converter.Factory
구성을 지원합니다. 기본값은 retrofit2.converter.jackson.JacksonConverterFactory
입니다.
Jackson
구성을 수정해야 하는 경우 JacksonConverterFactory
의 bean
구성을 직접 덮어쓰면 됩니다.
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 ;
}
@ 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 );
// 对文件名使用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 = { RetrofitBootApplication . 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을 구현할 수 있습니다. 이때 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
요청 본문 추가를 지원하지 않습니다. 소스 코드는 다음과 같습니다.
저자는 구체적인 이유를 제시했습니다. 다음을 참조하세요.
그러나 실제로 이 작업을 수행해야 하는 경우 @HTTP(method = "get", path = "/user/get", hasBody = true)
사용하고 소문자 get
사용하여 위의 제한 사항을 우회할 수 있습니다.
궁금한 점이 있으면 문제를 제기하거나 QQ 그룹에 참여하여 피드백을 받으세요.
그룹 번호: 806714302