如何自定義Spring restTemplate請求及回調

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()調用即可。

代碼已經經過測試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章