如何自定义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()调用即可。

代码已经经过测试。

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