在最近项目中,使用Springboot给外部提供接口,同时提供调用接口的SDK。
为了方便,直接使用SpringBoot中的RestTemplate来调用接口。
对接的时候翻车了,rest默认返回的是LinkedHashMap,我直接返回实体给他们,结果可想而知。
RestTemplate中属性
private final List> messageConverters = new ArrayList<>();
包含了默认的消息转换,我们可以添加json、stream、html等消息转换。
@Configuration
public class RestTemplateConfig {
@Resource
private RightsProperties rightsProperties;
@Bean
public RestTemplate restTemplate(@Qualifier("simpleClientHttpRequestFactory") ClientHttpRequestFactory factory){
RestTemplate restTemplate = new RestTemplate(factory);
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_OCTET_STREAM,
MediaType.TEXT_HTML));
restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//单位为ms
factory.setReadTimeout(rightsProperties.getReadTimeout());
//单位为ms
factory.setConnectTimeout(rightsProperties.getConnectTimeout());
return factory;
}
}
public static HttpEntity
/**
* get 请求并返回实体
* @param uri uri
* @param map 参数
* @param token token
* @param typeRef 返回实体类型
* @param 实体
* @return T 实体信息
*/
public Result sendGetEntity(String uri, Map map, String token,
ParameterizedTypeReference> typeRef) {
ResponseEntity> responseEntity = restTemplate.exchange(
rightsProperties.getPreUri() + uri,
HttpMethod.GET,
generatePostJson(null, token),
typeRef,
// 参数组装成map
map);
return responseEntity.getBody();
}
post方法要将参数设置在请求的body中
/**
* POST方法调用
* @param uri uri
* @param map 参数
* @param token token
* @param typeRef 返回类型
* @param 实体
* @return 返回实体
*/
public Result sendPostEntity(String uri, Map map, String token,
ParameterizedTypeReference> typeRef) {
ResponseEntity> responseEntity = restTemplate.exchange(
rightsProperties.getPreUri() + uri,
HttpMethod.POST,
// 参数需要设置在body中
generatePostJson(map, token),
typeRef);
return responseEntity.getBody();
}
// GET调用
@Override
public Result> getCanUseList(Integer type, String token) {
Map map = Collections.singletonMap("type", type);
ParameterizedTypeReference>> typeRef =
new ParameterizedTypeReference>>() {};
return restSendService.sendGetEntity(RequestConstant.GET_CAN_USE_LIST_URI, map, token, typeRef);
}
// POST调用
@Override
public Result issuedToCustomer(IssuedDTO param, String token) {
Map map = JsonUtils.objectToMap(param);
ParameterizedTypeReference> typeRef =
new ParameterizedTypeReference>() {};
return restSendService.sendPostEntity(RequestConstant.ISSUED_TO_CUSTOMER_URI, map, token, typeRef);
}
跟踪源码看到无论调用get 还是 post 最终都会执行doExecute方法,而根据typeRef会用构造一个ResponseExtractor
public ResponseEntityResponseExtractor(@Nullable Type responseType) {
if (responseType != null && Void.class != responseType) {
this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
}
else {
this.delegate = null;
}
}
@Nullable
protected T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
//
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}