RestTemplate封装http和https请求

Scroll Down

1. 背景

最近项目有需求封装统一的接口调用工具类。由于项目为Spring Boot所以使用spring推荐的RestTemplate。封装通用的http/https发送GET,POST请求。

2. pom引入

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

3. 通用RestTemplate封装

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }
    
    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        //30秒,单位为毫秒
        factory.setReadTimeout(3*10*1000);
        factory.setConnectTimeout(3*10*1000);
        return factory;
    }
    
    /**
     * 封装RestTemplate
     */
    @Bean(name = "restTemplateUtils")
    public RestTemplateUtils restTemplateUtils(RestTemplate restTemplate) {
        RestTemplateUtils restTemplateUtils = new RestTemplateUtils();
        restTemplateUtils.setRestTemplate(restTemplate);
        return restTemplateUtils;
    }
}

4. https请求工厂封装

@Slf4j
public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
        try {
            /*if (!(connection instanceof HttpsURLConnection)) {
                throw new RuntimeException("An instance of HttpsURLConnection is expected");
            }*/
            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;

            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) { }
                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) { }
                }
            };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));
    
            httpsConnection.setHostnameVerifier((s, sslSession) -> true);
            //30秒,单位为毫秒
            httpsConnection.setReadTimeout(3*10*1000);
            httpsConnection.setConnectTimeout(3*10*1000);
            super.prepareConnection(httpsConnection, httpMethod);
        } catch (Exception e) {
            log.error("HttpsURLConnection init exception",e);
            e.printStackTrace();
        }
    }
    
    // SSLSocketFactory用于创建 SSLSockets
    private static class MyCustomSSLSocketFactory extends SSLSocketFactory {
    
        private final SSLSocketFactory delegate;
    
        public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
            this.delegate = delegate;
        }
    
        // 返回默认启用的密码套件。除非一个列表启用,对SSL连接的握手会使用这些密码套件。
        // 这些默认的服务的最低质量要求保密保护和服务器身份验证
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }
    
        // 返回的密码套件可用于SSL连接启用的名字
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }
    
        @Override
        public Socket createSocket(final Socket socket, final String host, final int port,final boolean autoClose) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
            return overrideProtocol(underlyingSocket);
        }
    
        @Override
        public Socket createSocket(final String host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }
    
        @Override
        public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }
    
        @Override
        public Socket createSocket(final InetAddress host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }
    
        @Override
        public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }
    
        private Socket overrideProtocol(final Socket socket) {
            if (!(socket instanceof SSLSocket)) {
                throw new RuntimeException("An instance of SSLSocket is expected");
            }
            ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1"});
            return socket;
        }
    }
}

5. RestTemplate工具类

@Slf4j
public class RestTemplateUtils {
    @Autowired
    private RestTemplate restTemplate;

    private static RestTemplateUtils restTemplateUtils;
    /**
     * 接口地址前缀
     */
    public static String urlPrefix;
    
    @PostConstruct
    public void init() {
        restTemplateUtils = this;
        restTemplateUtils.restTemplate = this.restTemplate;
    }
    @Value("${customer.urlPrefix}")
    public void seturlPrefix(String urlPrefix){
        RestTemplateUtils.urlPrefix = urlPrefix;
    }
    
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

   

    /**
     *  带请求头的https post请求,适用于http/https请求
     * @param url
     * @param params
     * @return
     */
    public static String sendHttpsForPost(String url, Map<String,Object> params){
        try {
            url = urlPrefix + url;
            if(Constants.HTTPS.equals(url.substring(0,5))){
                restTemplateUtils.restTemplate = new RestTemplate(new HttpsClientRequestFactory());
            }
            HttpHeaders headers = new HttpHeaders();
            String clientId = StringUtils.getObjStr(params.get("clientId"));
            String reqUserid = StringUtils.getObjStr(params.get("reqUserid"));
            if(StringUtils.isEmpty(clientId) || StringUtils.isEmpty(reqUserid)){
                log.error("请求头未设置...");
            }
            headers.set("Authorization", StringUtils.getObjStr(params.get("clientId")));
            headers.set("reqUserid", StringUtils.getObjStr(params.get("reqUserid")));
            HttpEntity<Object> httpEntity = new HttpEntity<>(params,headers);
            return restTemplateUtils.restTemplate.exchange(url,HttpMethod.POST,httpEntity,String.class).getBody();
        }catch (Exception e){
            log.error("调用https post 请求异常:" + e);
            return null;
        }
    }


    /**
     * 带请求头的https get请求,适用于http/https请求
     * @param url 具体的oms接口地址
     * @param header  请求头
     * @return
     */
    public static String sendHttpsForGet(String url, Map<String,Object> header){
        try {
            url = urlPrefix + url;
            if(Constants.HTTPS.equals(url.substring(0,5))){
                restTemplateUtils.restTemplate = new RestTemplate(new HttpsClientRequestFactory());
            }
            HttpHeaders httpHeaders = new HttpHeaders();
            if(header.isEmpty()){
                log.error("的请求头未设置...");
            }
            httpHeaders.set("Authorization", header.get("clientId").toString());
            httpHeaders.set("reqUserid", header.get("reqUserid").toString());
            HttpEntity<?> requestEntity = new HttpEntity<>(httpHeaders);
            return restTemplateUtils.restTemplate.exchange(url, HttpMethod.GET,requestEntity,String.class).getBody();
        }catch (Exception e){
            log.error("调用https get请求异常:" + e);
            return null;
        }
    }


    /**
     * post 请求上传文件,适用于http/https请求
     * @param url url地址
     * @param fileName 文件名
     * @param bytes 二进制文件流
     * @param params 参数
     * @return
     */
    public static BaseResp sendHttpsForUploadFile(String url,String fileName,byte[] bytes,Map<String ,Object> params){
        try {
            url = urlPrefix + url;
            if(url.indexOf("https") != -1){
                restTemplateUtils.restTemplate = new RestTemplate(new HttpsClientRequestFactory());
            }
            MultiValueMap<String, Object> multipartRequest = new LinkedMultiValueMap<>();
            //设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization",params.get("clientId").toString());
            headers.set("reqUserid",params.get("reqUserid").toString());
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            //如果是用spring 的MultipartFile接受,则加入下面这行, 取个随机文件名
            headers.setContentDispositionFormData("uploadFile", fileName + UUID.randomUUID().toString());
            HttpEntity<ByteArrayResource> httpEntity = new HttpEntity<>(new
                    ByteArrayResource(bytes), headers);
            multipartRequest.add("uploadFile", httpEntity);
            //自定义参数
            multipartRequest.add("tpas","true");
            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multipartRequest, headers);
            ResponseEntity<BaseResp> result = restTemplateUtils.restTemplate.exchange(url, HttpMethod.POST,requestEntity, BaseResp.class,params);
            return result.getBody();
        }catch (Exception e){
            log.error("调用https文件上传异常:" + e);
            return null;
        }
    }
}

6. 总结

通过url判断请求为http还是http,构建不同factory的RestTemplate,来实现调用第三方的http和https接口。