refactor(common-web): 优化 Web 基础配置与请求处理
- 修复可重复读取请求体包装器的 ServletInputStream 状态判断 - 将 XSS 过滤器改为构造器注入配置,移除静态 Spring Bean 获取 - 增加 CORS 配置属性,支持通过 web.cors.* 配置跨域规则 - 优化请求日志参数处理,避免 JSON 解析异常影响主请求并限制日志长度 - 收敛请求体解析异常响应,避免向前端暴露底层异常细节
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- web 容器使用 undertow 性能更强 -->
|
<!-- web 容器使用 jetty -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-jetty</artifactId>
|
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ public class FilterConfig {
|
|||||||
order = FilterRegistrationBean.HIGHEST_PRECEDENCE + 1,
|
order = FilterRegistrationBean.HIGHEST_PRECEDENCE + 1,
|
||||||
dispatcherTypes = DispatcherType.REQUEST
|
dispatcherTypes = DispatcherType.REQUEST
|
||||||
)
|
)
|
||||||
public XssFilter xssFilter() {
|
public XssFilter xssFilter(XssProperties xssProperties) {
|
||||||
return new XssFilter();
|
return new XssFilter(xssProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
-20
@@ -5,16 +5,17 @@ import cn.hutool.core.date.DateUtil;
|
|||||||
import org.dromara.common.core.utils.ObjectUtils;
|
import org.dromara.common.core.utils.ObjectUtils;
|
||||||
import org.dromara.common.json.enhance.JsonValueEnhancer;
|
import org.dromara.common.json.enhance.JsonValueEnhancer;
|
||||||
import org.dromara.common.web.advice.ResponseEnhancementAdvice;
|
import org.dromara.common.web.advice.ResponseEnhancementAdvice;
|
||||||
|
import org.dromara.common.web.config.properties.CorsProperties;
|
||||||
import org.dromara.common.web.handler.GlobalExceptionHandler;
|
import org.dromara.common.web.handler.GlobalExceptionHandler;
|
||||||
import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor;
|
import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.format.FormatterRegistry;
|
import org.springframework.format.FormatterRegistry;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
import org.springframework.web.filter.CorsFilter;
|
import org.springframework.web.filter.CorsFilter;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -25,6 +26,7 @@ import java.util.Date;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
|
@EnableConfigurationProperties(CorsProperties.class)
|
||||||
public class ResourcesConfig implements WebMvcConfigurer {
|
public class ResourcesConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,32 +57,19 @@ public class ResourcesConfig implements WebMvcConfigurer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册静态资源处理器。
|
|
||||||
*
|
|
||||||
* @param registry 资源处理器注册表
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跨域配置
|
* 跨域配置
|
||||||
*
|
*
|
||||||
* @return 全局 Cors 过滤器
|
* @return 全局 Cors 过滤器
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public CorsFilter corsFilter() {
|
public CorsFilter corsFilter(CorsProperties corsProperties) {
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
config.setAllowCredentials(true);
|
config.setAllowCredentials(corsProperties.getAllowCredentials());
|
||||||
// 设置访问源地址
|
config.setAllowedOriginPatterns(corsProperties.getAllowedOriginPatterns());
|
||||||
config.addAllowedOriginPattern("*");
|
config.setAllowedHeaders(corsProperties.getAllowedHeaders());
|
||||||
// 设置访问源请求头
|
config.setAllowedMethods(corsProperties.getAllowedMethods());
|
||||||
config.addAllowedHeader("*");
|
config.setMaxAge(corsProperties.getMaxAge());
|
||||||
// 设置访问源请求方法
|
|
||||||
config.addAllowedMethod("*");
|
|
||||||
// 有效期 1800秒
|
|
||||||
config.setMaxAge(1800L);
|
|
||||||
// 添加映射路径,拦截一切请求
|
// 添加映射路径,拦截一切请求
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
source.registerCorsConfiguration("/**", config);
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
|||||||
-63
@@ -1,63 +0,0 @@
|
|||||||
//package org.dromara.common.web.config;
|
|
||||||
//
|
|
||||||
//import io.undertow.server.DefaultByteBufferPool;
|
|
||||||
//import io.undertow.server.handlers.DisallowedMethodsHandler;
|
|
||||||
//import io.undertow.util.HttpString;
|
|
||||||
//import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
|
|
||||||
//import org.dromara.common.core.utils.SpringUtils;
|
|
||||||
//import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
||||||
//import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
|
|
||||||
//import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
|
||||||
//import org.springframework.core.task.VirtualThreadTaskExecutor;
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Undertow 自定义配置
|
|
||||||
// *
|
|
||||||
// * @author Lion Li
|
|
||||||
// */
|
|
||||||
//@AutoConfiguration
|
|
||||||
//public class UndertowConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 自定义 Undertow 配置
|
|
||||||
// * <p>
|
|
||||||
// * 主要配置内容包括:
|
|
||||||
// * 1. 配置 WebSocket 部署信息
|
|
||||||
// * 2. 在虚拟线程模式下使用虚拟线程池
|
|
||||||
// * 3. 禁用不安全的 HTTP 方法,如 CONNECT、TRACE、TRACK
|
|
||||||
// * </p>
|
|
||||||
// *
|
|
||||||
// * @param factory Undertow 的 Web 服务器工厂
|
|
||||||
// */
|
|
||||||
// @Override
|
|
||||||
// public void customize(UndertowServletWebServerFactory factory) {
|
|
||||||
// factory.addDeploymentInfoCustomizers(deploymentInfo -> {
|
|
||||||
// // 配置 WebSocket 部署信息,设置 WebSocket 使用的缓冲区池
|
|
||||||
// WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
|
|
||||||
// webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 1024));
|
|
||||||
// deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
|
||||||
//
|
|
||||||
// // 如果启用了虚拟线程,配置 Undertow 使用虚拟线程池
|
|
||||||
// if (SpringUtils.isVirtual()) {
|
|
||||||
// // 创建虚拟线程池,线程池前缀为 "undertow-"
|
|
||||||
// VirtualThreadTaskExecutor executor = new VirtualThreadTaskExecutor("undertow-");
|
|
||||||
// // 设置虚拟线程池为执行器和异步执行器
|
|
||||||
// deploymentInfo.setExecutor(executor);
|
|
||||||
// deploymentInfo.setAsyncExecutor(executor);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 配置禁止某些不安全的 HTTP 方法(如 CONNECT、TRACE、TRACK)
|
|
||||||
// deploymentInfo.addInitialHandlerChainWrapper(handler -> {
|
|
||||||
// // 禁止三个方法 CONNECT/TRACE/TRACK 也是不安全的 避免爬虫骚扰
|
|
||||||
// HttpString[] disallowedHttpMethods = {
|
|
||||||
// HttpString.tryFromString("CONNECT"),
|
|
||||||
// HttpString.tryFromString("TRACE"),
|
|
||||||
// HttpString.tryFromString("TRACK")
|
|
||||||
// };
|
|
||||||
// // 使用 DisallowedMethodsHandler 拦截并拒绝这些方法的请求
|
|
||||||
// return new DisallowedMethodsHandler(handler, disallowedHttpMethods);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package org.dromara.common.web.config.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跨域配置属性。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "web.cors")
|
||||||
|
public class CorsProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许携带凭证。
|
||||||
|
*/
|
||||||
|
private Boolean allowCredentials = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许的来源匹配规则。
|
||||||
|
*/
|
||||||
|
private List<String> allowedOriginPatterns = new ArrayList<>(List.of("*"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许的请求头。
|
||||||
|
*/
|
||||||
|
private List<String> allowedHeaders = new ArrayList<>(List.of("*"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许的请求方法。
|
||||||
|
*/
|
||||||
|
private List<String> allowedMethods = new ArrayList<>(List.of("*"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预检请求缓存时间,单位秒。
|
||||||
|
*/
|
||||||
|
private Long maxAge = 1800L;
|
||||||
|
|
||||||
|
}
|
||||||
+5
-4
@@ -13,6 +13,7 @@ import java.io.BufferedReader;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建可重复读取输入流的请求包装器,缓存请求体以支持多次读取。
|
* 构建可重复读取输入流的请求包装器,缓存请求体以支持多次读取。
|
||||||
@@ -45,7 +46,7 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BufferedReader getReader() throws IOException {
|
public BufferedReader getReader() throws IOException {
|
||||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,17 +66,17 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
return body.length;
|
return bais.available();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return false;
|
return bais.available() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+8
-4
@@ -1,6 +1,6 @@
|
|||||||
package org.dromara.common.web.filter;
|
package org.dromara.common.web.filter;
|
||||||
|
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.web.config.properties.XssProperties;
|
import org.dromara.common.web.config.properties.XssProperties;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -17,11 +17,14 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class XssFilter implements Filter {
|
public class XssFilter implements Filter {
|
||||||
/**
|
/**
|
||||||
* 跳过 XSS 过滤的请求路径集合。
|
* 跳过 XSS 过滤的请求路径集合。
|
||||||
*/
|
*/
|
||||||
public List<String> excludes = new ArrayList<>();
|
private final List<String> excludes = new ArrayList<>();
|
||||||
|
|
||||||
|
private final XssProperties properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化过滤器并加载配置中的排除路径。
|
* 初始化过滤器并加载配置中的排除路径。
|
||||||
@@ -31,8 +34,9 @@ public class XssFilter implements Filter {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
XssProperties properties = SpringUtils.getBean(XssProperties.class);
|
if (properties.getExcludeUrls() != null) {
|
||||||
excludes.addAll(properties.getExcludeUrls());
|
excludes.addAll(properties.getExcludeUrls());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -213,7 +213,7 @@ public class GlobalExceptionHandler {
|
|||||||
public R<Void> handleJsonParseException(JsonParseException e, HttpServletRequest request) {
|
public R<Void> handleJsonParseException(JsonParseException e, HttpServletRequest request) {
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
log.error("请求地址'{}' 发生 JSON 解析异常: {}", requestURI, e.getMessage());
|
log.error("请求地址'{}' 发生 JSON 解析异常: {}", requestURI, e.getMessage());
|
||||||
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求数据格式错误(JSON 解析失败):" + e.getMessage());
|
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求数据格式错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,7 +222,7 @@ public class GlobalExceptionHandler {
|
|||||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
public R<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
|
public R<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
|
||||||
log.error("请求地址'{}', 参数解析失败: {}", request.getRequestURI(), e.getMessage());
|
log.error("请求地址'{}', 参数解析失败: {}", request.getRequestURI(), e.getMessage());
|
||||||
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求参数格式错误:" + e.getMostSpecificCause().getMessage());
|
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求参数格式错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+33
-9
@@ -14,7 +14,6 @@ import org.dromara.common.json.utils.JsonUtils;
|
|||||||
import org.dromara.common.web.filter.RepeatedlyRequestWrapper;
|
import org.dromara.common.web.filter.RepeatedlyRequestWrapper;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
import tools.jackson.databind.JsonNode;
|
import tools.jackson.databind.JsonNode;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
import tools.jackson.databind.node.ArrayNode;
|
import tools.jackson.databind.node.ArrayNode;
|
||||||
@@ -36,6 +35,11 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数日志最大长度。
|
||||||
|
*/
|
||||||
|
private static final int MAX_PARAM_LOG_LENGTH = 4000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求进入控制器前记录入参并启动耗时统计。
|
* 请求进入控制器前记录入参并启动耗时统计。
|
||||||
*
|
*
|
||||||
@@ -54,20 +58,17 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
if (request instanceof RepeatedlyRequestWrapper) {
|
if (request instanceof RepeatedlyRequestWrapper) {
|
||||||
jsonParam = IoUtil.read(request.getReader());
|
jsonParam = IoUtil.read(request.getReader());
|
||||||
if (StringUtils.isNotBlank(jsonParam)) {
|
if (StringUtils.isNotBlank(jsonParam)) {
|
||||||
JsonMapper jsonMapper = JsonUtils.getJsonMapper();
|
jsonParam = sanitizeJsonParam(jsonParam);
|
||||||
JsonNode rootNode = jsonMapper.readTree(jsonParam);
|
|
||||||
removeSensitiveFields(rootNode, SystemConstants.EXCLUDE_PROPERTIES);
|
|
||||||
jsonParam = rootNode.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, limit(jsonParam));
|
||||||
} else {
|
} else {
|
||||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||||
if (MapUtil.isNotEmpty(parameterMap)) {
|
if (MapUtil.isNotEmpty(parameterMap)) {
|
||||||
Map<String, String[]> map = new LinkedHashMap<>(parameterMap);
|
Map<String, String[]> map = new LinkedHashMap<>(parameterMap);
|
||||||
MapUtil.removeAny(map, SystemConstants.EXCLUDE_PROPERTIES);
|
MapUtil.removeAny(map, SystemConstants.EXCLUDE_PROPERTIES);
|
||||||
String parameters = JsonUtils.toJsonString(map);
|
String parameters = JsonUtils.toJsonString(map);
|
||||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
|
log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, limit(parameters));
|
||||||
} else {
|
} else {
|
||||||
log.info("[PLUS]开始请求 => URL[{}],无参数", url);
|
log.info("[PLUS]开始请求 => URL[{}],无参数", url);
|
||||||
}
|
}
|
||||||
@@ -110,9 +111,32 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
* 清洗 JSON 请求参数日志,解析失败时不影响主请求。
|
||||||
|
*
|
||||||
|
* @param jsonParam 原始 JSON 字符串
|
||||||
|
* @return 清洗后的参数日志
|
||||||
|
*/
|
||||||
|
private String sanitizeJsonParam(String jsonParam) {
|
||||||
|
try {
|
||||||
|
JsonMapper jsonMapper = JsonUtils.getJsonMapper();
|
||||||
|
JsonNode rootNode = jsonMapper.readTree(jsonParam);
|
||||||
|
removeSensitiveFields(rootNode, SystemConstants.EXCLUDE_PROPERTIES);
|
||||||
|
return rootNode.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("[PLUS]请求参数 JSON 解析失败,跳过结构化脱敏: {}", e.getMessage());
|
||||||
|
return jsonParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限制日志字段长度。
|
||||||
|
*
|
||||||
|
* @param value 原始字符串
|
||||||
|
* @return 截断后的字符串
|
||||||
|
*/
|
||||||
|
private String limit(String value) {
|
||||||
|
return StringUtils.substring(value, 0, MAX_PARAM_LOG_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user