Spring restTemplate是一個很好的http請求代替方案,當你對HttpClient等其他框架厭倦的時候。
其原本的api已經足夠許多場景的http調用,但在實際應用中仍然可能會有一些自定義的場景。
例如這樣的情況,出於安全性的考慮,我們對http請求進行了加解密的約定。
但是我們在程序的調用中又期望加解密透明,即封裝該層加解密,這時我們需要對restTemplate進行自定義。
翻閱Spring restTemplate的源碼,我們發現:
RestTemplate類中有如下方法:
public <T> T execute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor)
通過分析exchange方法的實現,我們可以知道,請求頭及請求體是由RequestCallback來處理的,請求結果是由ResponseExtractor來處理,這時就很明朗了,我們只需要調用該execute函數,傳入我們的RequestCallback和ResponseExtractor即可。這時候發現這兩個接口的實現類都是私有的,因此我們需要實現這兩個接口,並且做我們想做的事情。
於是解決思路如下:
1.新建UserCenterRequestCallBack類,實現RequestCallback接口
2.新建UserCenterResponseExec類,實現ResponseExtractor接口
3.新建UCRequestTemplate類,繼承RestTemplate,寫一個我們最終調用的工具方法
4.測試結果
所有代碼如下:
1.UserCenterRequestCallBack類
package com.test.util;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
/**
* @Author: Lxx
* @Description:
* @Date: Created in 11:12 2018/6/10
*/
public class UserCenterRequestCallBack implements RequestCallback {
private RestTemplate restTemplate;
private List<HttpMessageConverter<?>> messageConverters;
private HttpEntity requestEntity;
public UserCenterRequestCallBack(RestTemplate restTemplate,HttpEntity requestEntity){
this.restTemplate = restTemplate;
this.messageConverters = restTemplate.getMessageConverters();
this.requestEntity = requestEntity;
}
@Override
public void doWithRequest(ClientHttpRequest clientHttpRequest) throws IOException {
if (!requestEntity.hasBody()) {
HttpHeaders httpHeaders = clientHttpRequest.getHeaders();
HttpHeaders requestHeaders = requestEntity.getHeaders();
if (!requestHeaders.isEmpty()) {
httpHeaders.putAll(requestHeaders);
}
if (httpHeaders.getContentLength() < 0L) {
httpHeaders.setContentLength(0L);
}
}else {
Object requestBody = requestEntity.getBody();
Iterator iterator = messageConverters.iterator();
while (iterator.hasNext()) {
Class<?> requestBodyClass = requestBody.getClass();
Type requestBodyType = requestEntity instanceof RequestEntity ? ((RequestEntity) requestEntity).getType() : requestBodyClass;
HttpHeaders requestHeadersx = requestEntity.getHeaders();
MediaType requestContentType = requestHeadersx.getContentType();
HttpMessageConverter<Object> messageConverter = (HttpMessageConverter) iterator.next();
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<Object> genericMessageConverter = (GenericHttpMessageConverter) messageConverter;
if (genericMessageConverter.canWrite((Type) requestBodyType, requestBodyClass, requestContentType)) {
if (!requestHeadersx.isEmpty()) {
clientHttpRequest.getHeaders().putAll(requestHeadersx);
}
genericMessageConverter.write(requestBody, (Type) requestBodyType, requestContentType, clientHttpRequest);
return;
}
} else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
if (!requestHeadersx.isEmpty()) {
clientHttpRequest.getHeaders().putAll(requestHeadersx);
}
messageConverter.write(requestBody, requestContentType, clientHttpRequest);
return;
}
}
}
}
}
2.UserCenterResponseExec類:
package com.test.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.HttpMessageConverterExtractor;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.lang.reflect.Type;
/**
* @Author: Lxx
* @Description:
* @Date: Created in 11:12 2018/6/10
*/
public class UserCenterResponseExec<T> implements ResponseExtractor<ResponseEntity<T>> {
private HttpMessageConverterExtractor<String> delegate;
private String password;
private Class<T> type;
public UserCenterResponseExec(RestTemplate restTemplate){
Type responseType = String.class;
if (responseType != null && Void.class != responseType) {
this.delegate = new HttpMessageConverterExtractor(responseType, restTemplate.getMessageConverters());
} else {
this.delegate = null;
}
}
public UserCenterResponseExec(RestTemplate restTemplate,String key,Class<T> responseType){
this.password = key;
this.type = responseType;
Type rt = String.class;
if (rt != null && Void.class != rt) {
this.delegate = new HttpMessageConverterExtractor(rt, restTemplate.getMessageConverters());
} else {
this.delegate = null;
}
}
@Override
public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
if (this.delegate != null) {
Object body = this.delegate.extractData(response);
if(StringUtils.isNotEmpty(password)){
body = AESCryptUtil.decryptByPassword(password, (String) body);
}
if(type != null && !type.getName().equalsIgnoreCase("java.lang.String")){
body = new ObjectMapper().readValue((String)body, type);
}
return new ResponseEntity(body, response.getHeaders(), response.getStatusCode());
} else {
return new ResponseEntity(response.getHeaders(), response.getStatusCode());
}
}
}
3.UCRequestTemplate類:
package com.test.util;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Lxx
* @Description:
* @Date: Created in 11:12 2018/6/10
*/
public class UCRequestTemplate extends RestTemplate {
public <T> ResponseEntity<T> execute(String url, String api,HttpMethod method, Map<String, Object> requestParams, Class<T> responseType) throws RestClientException {
String appVersion = "5.0";
String username = "lixiaoxin";
String password = "asdfasdf+SDFASDF/asdfaDsdfasdf==";
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type","application/json");
headers.set("api",api);
headers.set("username",username);
headers.set("app-version",appVersion);
String xContent = requestParams.toString();
String content = AESCryptUtil.encryptByPassword(password, xContent);
JSONObject obj = new JSONObject();
obj.put("ct", content);
HttpEntity<?> requestEntity = new HttpEntity(obj.toString(),headers);
RequestCallback requestCallback = new UserCenterRequestCallBack(this,requestEntity);
ResponseExtractor<T> responseExtractor = new UserCenterResponseExec(this,password,responseType);
return (ResponseEntity)this.execute(url, method, requestCallback, responseExtractor);
}
public static void main(String [] args){
String url = "http://192.168.111.233/gtwy.do";
String api = "generatorToken";
UCRequestTemplate restTemplate = new UCRequestTemplate();
Map<String,Object> requestParams = new HashMap<>();
requestParams.put("userId","FasdfasdfasdfYALKSDJFASDF");
try {
ResponseEntity<String> response = restTemplate.execute(url, api,HttpMethod.POST,requestParams,String.class);
System.out.println(response.getBody());
}catch (Exception e){
}
}
}
至此,一個附帶加解密的http已經封裝好了,下次調用只需要new UCRequestTemplate().execute()調用即可。
代碼已經經過測試。