柯桥增值式服务
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

196 行
9.6KB

  1. package com.ningdatech.kqapi.common.config;
  2. import com.fasterxml.jackson.core.JsonParser;
  3. import com.fasterxml.jackson.core.json.JsonReadFeature;
  4. import com.fasterxml.jackson.databind.DeserializationFeature;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import com.fasterxml.jackson.databind.SerializationFeature;
  7. import com.ningdatech.kqapi.common.util.NdDateUtils;
  8. import com.ningdatech.kqapi.common.util.NdJacksonModule;
  9. import com.ningdatech.kqapi.common.util.SpringUtils;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.apache.http.Header;
  12. import org.apache.http.client.HttpClient;
  13. import org.apache.http.client.config.RequestConfig;
  14. import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
  15. import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
  16. import org.apache.http.impl.client.HttpClientBuilder;
  17. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  18. import org.apache.http.message.BasicHeader;
  19. import org.springframework.boot.autoconfigure.AutoConfigureBefore;
  20. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  21. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  22. import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
  23. import org.springframework.context.ApplicationContext;
  24. import org.springframework.context.annotation.Bean;
  25. import org.springframework.context.annotation.Configuration;
  26. import org.springframework.context.annotation.Primary;
  27. import org.springframework.core.convert.converter.Converter;
  28. import org.springframework.http.MediaType;
  29. import org.springframework.http.client.ClientHttpRequestFactory;
  30. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  31. import org.springframework.http.converter.HttpMessageConverter;
  32. import org.springframework.http.converter.StringHttpMessageConverter;
  33. import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
  34. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  35. import org.springframework.lang.NonNull;
  36. import org.springframework.web.client.RestTemplate;
  37. import org.springframework.web.servlet.config.annotation.CorsRegistry;
  38. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  39. import java.nio.charset.StandardCharsets;
  40. import java.text.SimpleDateFormat;
  41. import java.time.LocalDate;
  42. import java.time.LocalDateTime;
  43. import java.time.LocalTime;
  44. import java.time.ZoneId;
  45. import java.util.*;
  46. import java.util.concurrent.TimeUnit;
  47. /**
  48. * @Classname BeanConfig
  49. * @Description
  50. * @Date 2023/3/2 9:42
  51. * @Created by PoffyZhang
  52. */
  53. @AutoConfigureBefore(JacksonAutoConfiguration.class)
  54. @Configuration
  55. @Slf4j
  56. public class BeanConfig implements WebMvcConfigurer {
  57. @Bean
  58. public RestTemplate restTemplate() {
  59. // 添加内容转换器,使用默认的内容转换器
  60. RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
  61. // 设置编码格式为UTF-8,解决中文乱码问题
  62. List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
  63. HttpMessageConverter<?> converterTarget = null;
  64. for (HttpMessageConverter<?> item : converterList) {
  65. if (item.getClass() == StringHttpMessageConverter.class) {
  66. converterTarget = item;
  67. break;
  68. }
  69. }
  70. if (converterTarget != null) {
  71. converterList.remove(converterTarget);
  72. }
  73. HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
  74. converterList.add(1,converter);
  75. MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
  76. mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
  77. MediaType.TEXT_HTML,
  78. MediaType.TEXT_PLAIN));
  79. restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
  80. log.info("-----restTemplate-----初始化完成");
  81. return restTemplate;
  82. }
  83. @Bean
  84. public ClientHttpRequestFactory httpRequestFactory() {
  85. return new HttpComponentsClientHttpRequestFactory(httpClient());
  86. }
  87. @Bean
  88. public HttpClient httpClient() {
  89. // 长连接保持30秒
  90. PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
  91. //设置整个连接池最大连接数 根据自己的场景决定
  92. connectionManager.setMaxTotal(500);
  93. //同路由的并发数,路由是对maxTotal的细分
  94. connectionManager.setDefaultMaxPerRoute(500);
  95. //requestConfig
  96. RequestConfig requestConfig = RequestConfig.custom()
  97. //服务器返回数据(response)的时间,超过该时间抛出read timeout
  98. .setSocketTimeout(10000)
  99. //连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
  100. .setConnectTimeout(5000)
  101. //从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
  102. .setConnectionRequestTimeout(500)
  103. .build();
  104. //headers
  105. List<Header> headers = new ArrayList<>();
  106. 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"));
  107. headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
  108. headers.add(new BasicHeader("Accept-Language", "zh-CN"));
  109. headers.add(new BasicHeader("Connection", "Keep-Alive"));
  110. headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));
  111. return HttpClientBuilder.create()
  112. .setDefaultRequestConfig(requestConfig)
  113. .setConnectionManager(connectionManager)
  114. .setDefaultHeaders(headers)
  115. // 保持长连接配置,需要在头添加Keep-Alive
  116. .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
  117. //重试次数,默认是3次,没有开启
  118. .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
  119. .build();
  120. }
  121. /**
  122. * 全局配置 序列化和反序列化规则
  123. * addSerializer:序列化 (Controller 返回 给前端的json)
  124. * 1. Long -> string
  125. * 2. BigInteger -> string
  126. * 3. BigDecimal -> string
  127. * 4. date -> string
  128. * 5. LocalDateTime -> "yyyy-MM-dd HH:mm:ss"
  129. * 6. LocalDate -> "yyyy-MM-dd"
  130. * 7. LocalTime -> "HH:mm:ss"
  131. * 8. BaseEnum -> {"code": "xxx", "desc": "xxx"}
  132. *
  133. * <p>
  134. * addDeserializer: 反序列化 (前端调用接口时,传递到后台的json)
  135. * 1. {"code": "xxx"} -> BaseEnum
  136. * 2. "yyyy-MM-dd HH:mm:ss" -> LocalDateTime
  137. * 3. "yyyy-MM-dd" -> LocalDate
  138. * 4. "HH:mm:ss" -> LocalTime
  139. *
  140. * @param builder 构造器
  141. * @return 全局 ObjectMapper
  142. */
  143. @Bean
  144. @Primary
  145. @ConditionalOnClass(ObjectMapper.class)
  146. @ConditionalOnMissingBean
  147. public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
  148. ObjectMapper objectMapper = builder.createXmlMapper(false).build();
  149. objectMapper.setLocale(Locale.CHINA)
  150. //去掉默认的时间戳格式
  151. .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
  152. // 时区
  153. .setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
  154. //Date参数日期格式
  155. .setDateFormat(new SimpleDateFormat(NdDateUtils.DEFAULT_DATE_TIME_FORMAT, Locale.CHINA))
  156. //该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性
  157. .configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
  158. // 忽略不能转义的字符
  159. .configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true)
  160. //在使用spring boot + jpa/hibernate,如果实体字段上加有FetchType.LAZY,并使用jackson序列化为json串时,会遇到SerializationFeature.FAIL_ON_EMPTY_BEANS异常
  161. .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
  162. //忽略未知字段
  163. .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
  164. //单引号处理
  165. .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
  166. // 注册自定义模块
  167. objectMapper.registerModule(new NdJacksonModule()).findAndRegisterModules();
  168. return objectMapper;
  169. }
  170. //解决跨域方式二
  171. static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE","OPTIONS"};
  172. @Override
  173. public void addCorsMappings(CorsRegistry registry) {
  174. registry.addMapping("/**") // 所有的当前站点的请求地址,都支持跨域访问。
  175. .allowedOriginPatterns("*") // 所有的外部域都可跨域访问。 如果是localhost则很难配置,因为在跨域请求的时候,外部域的解析可能是localhost、127.0.0.1、主机名
  176. .allowCredentials(true) // 是否支持跨域用户凭证
  177. .allowedMethods(ORIGINS) // 当前站点支持的跨域请求类型是什么
  178. .maxAge(3600); // 超时时长设置为1小时。 时间单位是秒。
  179. }
  180. }