一、引入依赖
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.0.0-beta4</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.0.0-beta4</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.1.2</version>
</dependency>
二、retrofit 用法示例
创建一个父类
@Slf4j
public class DdtClient {
protected Retrofit retrofit;
@Autowired
public DdtClient(String apiBaseUrl) {
retrofit = createRetrofit(apiBaseUrl);
}
private Retrofit createRetrofit(String apiBaseUrl) {
Interceptor interceptor = chain -> {
Request newRequest = chain.request().newBuilder().addHeader("jtoken", Utils.createTestToken("13100001234")).build();
return chain.proceed(newRequest);
};
X509TrustManager xtm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
HostnameVerifier DO_NOT_VERIFY = (hostname, session) -> true;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(interceptor);
//添加拦截器
builder.interceptors().add(new MonitorRequestInterceptor());
builder.interceptors().add(new LogRequestInterceptor());
builder.interceptors().add(new Retry(3));
assert sslContext != null;
OkHttpClient client = builder
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.sslSocketFactory(sslContext.getSocketFactory())
.hostnameVerifier(DO_NOT_VERIFY)
.build();
return new Retrofit
.Builder()
.baseUrl(apiBaseUrl)
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build();
}
/**
* 自定义的,重试N次的拦截器
* 通过:addInterceptor 设置
*/
public static class Retry implements Interceptor {
public int maxRetry;//最大重试次数
private int retryNum = 0;//假如设置为3次重试的话,则最大可能请求4次(默认1次+3次重试)
public Retry(int maxRetry) {
this.maxRetry = maxRetry;
}
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
while (!response.isSuccessful() && retryNum < maxRetry) {
retryNum++;
log.info("Retry num:"+retryNum);
response = chain.proceed(request);
}
return response;
}
}
}
创建接口类,存放rpc需要调用的接口
public interface CloudApi {
/**
* 获取客户明细
* @param page
* @param size
* @return
*/
@GET("/v1/customers")
Call<PageVO<CustomerVO>> findCustomersByPage(@Query("page") Integer page, @Query("size") Integer size);
}
三、创建拦截器类
1.日志拦截器
实现日志定制化。
@Slf4j
public class LogRequestInterceptor implements Interceptor {
@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
long tx = response.sentRequestAtMillis();
long rx = response.receivedResponseAtMillis();
long costMillis = rx-tx;
log(request, response, costMillis);
return response;
}
private void log(Request request,Response response, long costMillis) throws IOException {
String uri = request.url().toString();
String method = request.method();
int status = response.code();
String requestString = getRequestString(request);
LogRecord logRecord = new LogRecord()
.setUri(uri)
.setHttpMethod(method)
.setReqHeaders(getHttpHeader(request.headers()))
.setReqBody(requestString)
.setCostMillis((int) costMillis)
.setRespHeaders(getHttpHeader(response.headers()))
.setStatus(status)
.setRespBody(response.peekBody(500).string());
log.info("[AUDITLOG::RETROFITTHIRDPART] {}", JsonUtils.toJsonString(logRecord));
}
private HttpHeaders getHttpHeader(Headers headers) {
HttpHeaders httpHeaders = new HttpHeaders();
for (int i = 0, count = headers.size(); i < count; i++) {
String name = headers.name(i);
// Skip headers from the request body as they are explicitly logged above.
httpHeaders.set(name,headers.value(i));
}
return httpHeaders;
}
private String getRequestString(Request request) {
RequestBody requestBody = request.body();
if (ObjectUtil.isEmpty(requestBody)){
return null;
}
Buffer buffer = new Buffer();
try {
requestBody.writeTo(buffer);
} catch (IOException e) {
e.printStackTrace();
}
//编码设为UTF-8
Charset charset = StandardCharsets.UTF_8;
MediaType contentType = requestBody.contentType();
if (contentType != null) {
charset = contentType.charset(StandardCharsets.UTF_8);
}
//拿到request
return buffer.readString(charset);
}
@Data
@Accessors(chain = true)
public static class LogRecord {
private String httpMethod;
private String uri;
private HttpHeaders reqHeaders;
private String reqBody;
private Integer costMillis;
private HttpHeaders respHeaders;
private Integer status;
private String respBody;
}
}
2.监视器拦截器
@Slf4j
public class MonitorRequestInterceptor implements Interceptor {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
long tx = response.sentRequestAtMillis();
long rx = response.receivedResponseAtMillis();
MonitorThirdPartRequest.monitor(new RequestLatency()
.setCode(Objects.isNull(response) ? -1 : response.code())
.setMethod(request.method())
.setPath(request.url().encodedPath())
.setCostMillis(rx-tx)
);
return response;
}
}
四、创建接口实现类
创建接口实现类,继承retrofit类
@Component
@Slf4j
public class CustomCloudClient extends MiddleClient {
private CloudApi api;
@Autowired
public CustomCloudClient(@Value("${cloud.api.baseUrl}") String apiBaseUrl,
@Value("${token.user.url}") String apiToken) {
super(apiBaseUrl, apiToken);
api = retrofit.create(CloudApi.class);
}
public PageVO<CustomerVO> findCustomersByPage(User user,Integer page, Integer size) throws IOException {
createUserToken(user);
Call<PageVO<CustomerVO>> call = api.findCustomersByPage(page,size);
Response<PageVO<CustomerVO>> response = call.execute();
if (response.code() == 200) {
return response.body();
} else {
log.info("getCardsByTaskId, status:{}, message:{}", response.code(), response.message());
}
return null;
}
private String createUserToken(final User user) {
try {
return JwtUtils.createToken(user);
} catch (final IllegalAccessException e) {
log.error("", e);
throw new IllegalStateException("BUG: cannot create user token");
}
}
}
五、自定义Converter.Factory
Converter.Factory
,肯定是通过addConverterFactory
设置的
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(apiBaseUrl)
.addConverterFactory(StringConverterFactory.create())
.client(client)
.build();
创建一个converter类,继承Converter.Factory
public class StringConverterFactory extends Converter.Factory {
public static StringConverterFactory create() {
return new StringConverterFactory();
}
private StringConverterFactory() {
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new StringResponseBodyConverter();
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new StringRequestBodyConverter();
}
}
定义RequestBody
public class StringRequestBodyConverter implements Converter<String, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
StringRequestBodyConverter() {
}
@Override public RequestBody convert(String value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
writer.write(value);
writer.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
定义ResponseBody
public class StringResponseBodyConverter implements Converter<ResponseBody, String> {
@Override
public String convert(ResponseBody value) throws IOException {
try {
return value.string();
} finally {
value.close();
}
}
}
使用的时候呢,可以
Retrofit retrofit = new Retrofit.Builder()
.callFactory(new OkHttpClient()) .baseUrl("http://example/springmvc_users/user/")
//.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(new UserConverterFactory())
.build();
不同的converter,可以用不同的Client类