|
- package com.ningdatech.kqapi.common.config;
-
- import com.fasterxml.jackson.core.JsonParser;
- import com.fasterxml.jackson.core.json.JsonReadFeature;
- import com.fasterxml.jackson.databind.DeserializationFeature;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.SerializationFeature;
- import com.ningdatech.kqapi.common.util.NdDateUtils;
- import com.ningdatech.kqapi.common.util.NdJacksonModule;
- import com.ningdatech.kqapi.common.util.SpringUtils;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.http.Header;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.config.RequestConfig;
- import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
- import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
- import org.apache.http.impl.client.HttpClientBuilder;
- import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
- import org.apache.http.message.BasicHeader;
- import org.springframework.boot.autoconfigure.AutoConfigureBefore;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Primary;
- import org.springframework.core.convert.converter.Converter;
- import org.springframework.http.MediaType;
- import org.springframework.http.client.ClientHttpRequestFactory;
- import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.StringHttpMessageConverter;
- import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
- import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
- import org.springframework.lang.NonNull;
- import org.springframework.web.client.RestTemplate;
- import org.springframework.web.servlet.config.annotation.CorsRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
- import java.nio.charset.StandardCharsets;
- import java.text.SimpleDateFormat;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.time.ZoneId;
- import java.util.*;
- import java.util.concurrent.TimeUnit;
-
- /**
- * @Classname BeanConfig
- * @Description
- * @Date 2023/3/2 9:42
- * @Created by PoffyZhang
- */
- @AutoConfigureBefore(JacksonAutoConfiguration.class)
- @Configuration
- @Slf4j
- public class BeanConfig implements WebMvcConfigurer {
-
-
- @Bean
- public RestTemplate restTemplate() {
- // 添加内容转换器,使用默认的内容转换器
- RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
- // 设置编码格式为UTF-8,解决中文乱码问题
- List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
- HttpMessageConverter<?> converterTarget = null;
- for (HttpMessageConverter<?> item : converterList) {
- if (item.getClass() == StringHttpMessageConverter.class) {
- converterTarget = item;
- break;
- }
- }
- if (converterTarget != null) {
- converterList.remove(converterTarget);
- }
- HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
- converterList.add(1,converter);
-
- MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
- mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
- MediaType.TEXT_HTML,
- MediaType.TEXT_PLAIN));
- restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
-
- log.info("-----restTemplate-----初始化完成");
- return restTemplate;
- }
-
- @Bean
- public ClientHttpRequestFactory httpRequestFactory() {
- return new HttpComponentsClientHttpRequestFactory(httpClient());
- }
-
- @Bean
- public HttpClient httpClient() {
- // 长连接保持30秒
- PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
- //设置整个连接池最大连接数 根据自己的场景决定
- connectionManager.setMaxTotal(500);
- //同路由的并发数,路由是对maxTotal的细分
- connectionManager.setDefaultMaxPerRoute(500);
-
- //requestConfig
- RequestConfig requestConfig = RequestConfig.custom()
- //服务器返回数据(response)的时间,超过该时间抛出read timeout
- .setSocketTimeout(10000)
- //连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
- .setConnectTimeout(5000)
- //从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
- .setConnectionRequestTimeout(500)
- .build();
- //headers
- List<Header> headers = new ArrayList<>();
- headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
- headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
- headers.add(new BasicHeader("Accept-Language", "zh-CN"));
- headers.add(new BasicHeader("Connection", "Keep-Alive"));
- headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));
-
- return HttpClientBuilder.create()
- .setDefaultRequestConfig(requestConfig)
- .setConnectionManager(connectionManager)
- .setDefaultHeaders(headers)
- // 保持长连接配置,需要在头添加Keep-Alive
- .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
- //重试次数,默认是3次,没有开启
- .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
- .build();
- }
-
- /**
- * 全局配置 序列化和反序列化规则
- * addSerializer:序列化 (Controller 返回 给前端的json)
- * 1. Long -> string
- * 2. BigInteger -> string
- * 3. BigDecimal -> string
- * 4. date -> string
- * 5. LocalDateTime -> "yyyy-MM-dd HH:mm:ss"
- * 6. LocalDate -> "yyyy-MM-dd"
- * 7. LocalTime -> "HH:mm:ss"
- * 8. BaseEnum -> {"code": "xxx", "desc": "xxx"}
- *
- * <p>
- * addDeserializer: 反序列化 (前端调用接口时,传递到后台的json)
- * 1. {"code": "xxx"} -> BaseEnum
- * 2. "yyyy-MM-dd HH:mm:ss" -> LocalDateTime
- * 3. "yyyy-MM-dd" -> LocalDate
- * 4. "HH:mm:ss" -> LocalTime
- *
- * @param builder 构造器
- * @return 全局 ObjectMapper
- */
- @Bean
- @Primary
- @ConditionalOnClass(ObjectMapper.class)
- @ConditionalOnMissingBean
- public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
- ObjectMapper objectMapper = builder.createXmlMapper(false).build();
- objectMapper.setLocale(Locale.CHINA)
- //去掉默认的时间戳格式
- .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
- // 时区
- .setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
- //Date参数日期格式
- .setDateFormat(new SimpleDateFormat(NdDateUtils.DEFAULT_DATE_TIME_FORMAT, Locale.CHINA))
-
- //该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性
- .configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
- // 忽略不能转义的字符
- .configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true)
- //在使用spring boot + jpa/hibernate,如果实体字段上加有FetchType.LAZY,并使用jackson序列化为json串时,会遇到SerializationFeature.FAIL_ON_EMPTY_BEANS异常
- .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
- //忽略未知字段
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- //单引号处理
- .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
- // 注册自定义模块
- objectMapper.registerModule(new NdJacksonModule()).findAndRegisterModules();
- return objectMapper;
- }
-
- //解决跨域方式二
- static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE","OPTIONS"};
-
- @Override
- public void addCorsMappings(CorsRegistry registry) {
- registry.addMapping("/**") // 所有的当前站点的请求地址,都支持跨域访问。
- .allowedOriginPatterns("*") // 所有的外部域都可跨域访问。 如果是localhost则很难配置,因为在跨域请求的时候,外部域的解析可能是localhost、127.0.0.1、主机名
- .allowCredentials(true) // 是否支持跨域用户凭证
- .allowedMethods(ORIGINS) // 当前站点支持的跨域请求类型是什么
- .maxAge(3600); // 超时时长设置为1小时。 时间单位是秒。
- }
- }
|