spring 6.0 RestTemplate 配置

RestTemplateConfig

java 复制代码
package cn.sitc.pc.config;

import cn.sitc.pc.interceptor.LoggingInterceptor;
import cn.sitc.pc.wrapper.APIResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.TrustManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @date 2024/10/24
 **/
@Slf4j
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate apiRestTemplate() throws Exception {
        RestTemplate restTemplate = new RestTemplate(factory());
        restTemplate.setInterceptors(Collections.singletonList(bpmInterceptor()));
//        MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream().filter(MappingJackson2HttpMessageConverter.class::isInstance)
//                .map(MappingJackson2HttpMessageConverter.class::cast).findFirst().orElseThrow(() -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
//        messageConverter.setObjectMapper(new ObjectMapper());
//        //防止响应中文乱码
//        restTemplate.getMessageConverters().stream().filter(StringHttpMessageConverter.class::isInstance).map(StringHttpMessageConverter.class::cast).forEach(a -> {
//            a.setWriteAcceptCharset(false);
//            a.setDefaultCharset(StandardCharsets.UTF_8);
//        });
        return restTemplate;
    }

    public ClientHttpRequestFactory factory() throws Exception {
        // 创建一个HttpComponentsClientHttpRequestFactory,并设置HttpClient
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(createHttpClient());
        return requestFactory;
    }

    public CloseableHttpClient createHttpClient() throws Exception {
        TlsSocketStrategy tlsStrategy = new DefaultClientTlsStrategy(createSslContext(), NoopHostnameVerifier.INSTANCE);
        // 使用自定义的 SSLConnectionSocketFactory 构建连接管理器
        PoolingHttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create()
                .setTlsSocketStrategy(tlsStrategy)
                .build();
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(5L, TimeUnit.SECONDS)
                .setResponseTimeout(5L, TimeUnit.SECONDS).build();

        // 创建 HttpClient
        return HttpClients.custom()
                .setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    public SSLContext createSslContext() throws Exception {
        // 创建一个信任所有证书的信任管理器
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
        };
        // 使用我们的信任管理器初始化SSL上下文
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        return sslContext;
    }

    @Bean
    public LoggingInterceptor loggingInterceptor() {
        return new LoggingInterceptor();
    }

    @Bean
    public ClientHttpRequestInterceptor bpmInterceptor() {
        return (request, body, execution) -> {
            LocalDateTime startTime = LocalDateTime.now();
            try {
                ClientHttpResponse response = execution.execute(request, body);
                return new APIResponseWrapper(response, "BPM", request, body, startTime);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return new APIResponseWrapper(e, "BPM", request, body, startTime);
            }
        };
    }
}

ClientHttpResponse

java 复制代码
package cn.sitc.pc.wrapper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.hibernate.service.spi.ServiceException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * @date 2024/10/24
 **/

@Slf4j
public class APIResponseWrapper implements ClientHttpResponse {

    private ClientHttpResponse originalResponse;
    private final byte[] responseBodyByte;
    private ByteArrayInputStream responseInputStream;

    public APIResponseWrapper(ClientHttpResponse originalResponse) {
        if (originalResponse == null) {
            // 调用OMS Token接口异常
            this.responseBodyByte = "ERROR".getBytes();
        } else {
            this.originalResponse = originalResponse;
            try {
                responseBodyByte = IOUtils.toString(originalResponse.getBody(), StandardCharsets.UTF_8).getBytes();
                // JSONObject json = JSON.parseObject(new String(responseBodyByte));
            } catch (Exception e1) {
                throw new ServiceException("There was a problem reading/decoding the response coming from the service ", e1);
            }
        }
    }

    public APIResponseWrapper(ClientHttpResponse response, String system, HttpRequest request, byte[] body, LocalDateTime startTime) throws IOException {
        this(response);
        logIntegration(request, body, response, this.responseBodyByte, system, startTime);
    }

    public APIResponseWrapper(Exception exception, String system, HttpRequest request, byte[] body, LocalDateTime startTime) {
        this(null);
        logRequest(request, body);
        callTime(system, startTime);
    }

    private void logIntegration(HttpRequest request, byte[] requestBody, ClientHttpResponse response, byte[] responseBody, String system, LocalDateTime startTime) throws IOException {
        logRequest(request, requestBody);
        logResponse(response, responseBody);
        callTime(system, startTime);
    }

    private void logRequest(HttpRequest request, byte[] requestBody) {
        log.info("=========================== request begin ===========================");
        log.info("Request method: {}", request.getMethod());
        log.info("Request URI: {}", request.getURI());
        log.info("Request headers: {}", request.getHeaders());
        if (requestBody.length > 0) {
            log.info("Request body: {}", URLDecoder.decode(new String(requestBody, StandardCharsets.UTF_8), StandardCharsets.UTF_8));
        }
        log.info("=========================== request end ===========================");
    }

    private void logResponse(ClientHttpResponse response, byte[] responseBody) throws IOException {
        log.info("=========================== response begin ===========================");
        log.info("Response status code: {}", response.getStatusCode());
        log.info("Response headers: {}", response.getHeaders());
        String responseString = new String(responseBody, StandardCharsets.UTF_8);
        // 截取打印 response 的日志长度
        String truncatedResponse = responseString.substring(0, Math.min(10000, responseString.length()));
        log.info("Response body: {}", truncatedResponse);
        log.info("=========================== response end ===========================");
    }

    private void callTime(String system, LocalDateTime startTime) {
        log.info("===========================invoke {} call time:{}ms", system, ChronoUnit.MILLIS.between(startTime, LocalDateTime.now()));
    }

    @NonNull
    @Override
    public HttpStatusCode getStatusCode() throws IOException {
        return originalResponse != null ? originalResponse.getStatusCode() : HttpStatus.INTERNAL_SERVER_ERROR;
    }

    @NonNull
    @Override
    public String getStatusText() throws IOException {
        return originalResponse != null ? originalResponse.getStatusText() : HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
    }

    @Override
    public void close() {
        originalResponse.close();
    }

    @NonNull
    @Override
    public InputStream getBody() throws IOException {
        if (responseInputStream == null) {
            try {
                JSONObject json = JSON.parseObject(new String(responseBodyByte));
                // 根据返回的code 做后续逻辑处理
//                if (json.getInteger("code") != 200) {
//                    // 存在错误
//                    log.error("ERROR: {}", json.toJSONString());
//                    // 修改返回
//                    json.put("message", "" + json.getString("message"));
//                }
                responseInputStream = new ByteArrayInputStream(json.toJSONString().getBytes());
            } catch (Exception e) {
                log.error("系统异常", e);
            }
            if (responseInputStream == null) {
                responseInputStream = new ByteArrayInputStream(responseBodyByte);
            }
        }
        return responseInputStream;
    }

    @NonNull
    @Override
    public HttpHeaders getHeaders() {
        return originalResponse != null ? originalResponse.getHeaders() : new HttpHeaders();
    }

}
相关推荐
XiaoLiuLB几秒前
Tomcat NIO 配置实操指南
java·tomcat·nio
Be_Somebody4 分钟前
[这可能是最好的Spring教程!]Maven的模块管理——如何拆分大项目并且用parent继承保证代码的简介性
java·spring boot·spring·spring入门
计算机学姐13 分钟前
基于Python的高校成绩分析管理系统
开发语言·vue.js·后端·python·mysql·pycharm·django
一个数据小开发20 分钟前
业务开发问题之ConcurrentHashMap
java·开发语言·高并发·map
会飞的架狗师36 分钟前
【Spring】Spring框架中有有哪些常见的设计模式
java·spring·设计模式
wclass-zhengge1 小时前
SpringCloud篇(服务拆分 / 远程调用 - 入门案例)
后端·spring·spring cloud
Jakarta EE1 小时前
在JPA和EJB中用乐观锁解决并发问题
java
花心蝴蝶.1 小时前
并发编程中常见的锁策略
java·jvm·windows
A_cot1 小时前
一篇Spring Boot 笔记
java·spring boot·笔记·后端·mysql·spring·maven
tryCbest2 小时前
java8之Stream流
java·后端