引入依赖
2.3.5版本引入了@Logging注解,更加方便
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.5</version>
</dependency>
启动类加入注解
@SpringBootApplication
@RetrofitScan("com.mason.api")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
定义鉴权 (无需鉴权的可以跳过)
@RetrofitClient(baseUrl = "${business.baseUrl}")
public interface IAuthService {
/**
* 假如鉴权是如下接口路由
*/
@POST("/auth/token")
InterfaceResponse<TokenDto> getToken(@Body TokenQo tokenQo);
}
定义被调用的接口
@RetrofitClient(baseUrl = "${business.baseUrl}")
@Sign(clientId = "${business.clientId}", clientSecret = "${business.clientSecret}", handler = SignInterceptor.class)
public interface IBusinessService {
/**
*
* @return Integer
*/
@GET("/order")
InterfaceResponse<OrderDto> getOrder(@Query("orderSn") String orderSn);
@Sign的代码内容
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
/**
* 密钥key
* 支持占位符形式配置。
*
* @return String
*/
String clientId();
/**
* 密钥
* 支持占位符形式配置。
*
* @return String
*/
String clientSecret();
/**
* 拦截器匹配路径
*
* @return String[]
*/
String[] include() default {"/**"};
/**
* 拦截器排除匹配,排除指定路径拦截
*
* @return String[]
*/
String[] exclude() default {};
/**
* 处理该注解的拦截器类
* 优先从spring容器获取对应的Bean,如果获取不到,则使用反射创建一个!
*
* @return Class
*/
Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}
对应@Sign的SignInterceptor拦截器
@Component
public class SignInterceptor extends BasePathMatchInterceptor {
private String clientId;
private String clientSecret;
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@Resource
private IAuthService authService;
@Override
public Response doIntercept(Chain chain) throws IOException {
TokenQo tokenQo = new TokenQo();
tokenQo.setClientId(clientId);
tokenQo.setClientSecret(clientSecret);
InterfaceResponse<TokenDto> tokenResponse = authService.getToken(tokenQo);
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer " + tokenResponse.getData().getAccess_token())
.build();
// 发起请求
return chain.proceed(newReq);
}
}
注意, 别忘了加这个bean,防止序列化和反序列化出现问题
@Bean
@ConditionalOnMissingBean
public JacksonConverterFactory jacksonConverterFactory() {
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
JsonMapper mapper = JsonMapper.builder()
.findAndAddModules()
.addModule(timeModule)
.addModule(simpleModule)
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.serializationInclusion(JsonInclude.Include.NON_NULL)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
return JacksonConverterFactory.create(mapper);
}