u
This commit is contained in:
1 parent
a4e59dd5d1
commit
c7240ea7c9
16 files changed
+598
-476
No files matched your search
@@ -2,7 +2,9 @@ package cn.g3soft.config;
|
||||
|
||||
import cn.g3soft.interceptor.AuthInterceptor;
|
||||
import cn.g3soft.interceptor.DataSourceInterceptor;
|
||||
import cn.g3soft.interceptor.RequestBodyCacheInterceptor;
|
||||
import cn.g3soft.interceptor.RequestWrapperFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
@@ -11,9 +13,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new RequestBodyCacheInterceptor())
|
||||
.addPathPatterns("/**");
|
||||
|
||||
registry.addInterceptor(new AuthInterceptor())
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(
|
||||
@@ -28,4 +27,13 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
"/error"
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<RequestWrapperFilter> requestWrapperFilter() {
|
||||
FilterRegistrationBean<RequestWrapperFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new RequestWrapperFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setOrder(1); // 一定要靠前
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -1,6 +1,5 @@
|
||||
package cn.g3soft.exception;
|
||||
|
||||
import cn.g3soft.interceptor.RequestBodyCacheInterceptor;
|
||||
import cn.g3soft.utils.ExceptionUtils;
|
||||
import cn.g3soft.utils.Result;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -14,9 +13,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
public class GlobalExceptionHandler {
|
||||
@ExceptionHandler(Exception.class)
|
||||
public Result<ExceptionDetailInfo> handleException(Exception ex, HttpServletRequest request) {
|
||||
String requestBody = RequestBodyCacheInterceptor.getRequestBodyFromThreadLocal();
|
||||
|
||||
ExceptionDetailInfo info = ExceptionUtils.extractExceptionInfo(ex, requestBody, "cn.g3soft");
|
||||
ExceptionDetailInfo info = ExceptionUtils.extractExceptionInfo(ex, request, "cn.g3soft");
|
||||
|
||||
log.error("异常发生在 {}#{}({}:{}),ID: {},信息: {}",
|
||||
info.getClassName(),
|
||||
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
package cn.g3soft.interceptor;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Component
|
||||
public class RequestBodyCacheInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final ThreadLocal<String> requestBodyThreadLocal = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 仅在异常发生时读取请求体
|
||||
if (response.isCommitted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 缓存请求体到 ThreadLocal
|
||||
if (isExceptionRequest(request)) {
|
||||
String requestBody = getRequestBody(request);
|
||||
requestBodyThreadLocal.set(requestBody); // 将请求体保存到 ThreadLocal
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isExceptionRequest(HttpServletRequest request) {
|
||||
// 你可以根据某些条件判断是否需要读取请求体,比如请求头或者请求的 URI
|
||||
// 这里简单示范,假设在异常时才读取
|
||||
return true; // 仅在异常发生时才读取请求体
|
||||
}
|
||||
|
||||
private String getRequestBody(HttpServletRequest request) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
bodyBuilder.append(line);
|
||||
}
|
||||
return bodyBuilder.toString();
|
||||
}
|
||||
|
||||
// 提供获取请求体的方法
|
||||
public static String getRequestBodyFromThreadLocal() {
|
||||
return requestBodyThreadLocal.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
// 清除ThreadLocal中的请求体
|
||||
requestBodyThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package cn.g3soft.interceptor;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RequestWrapperFilter implements Filter {
|
||||
private static final int MAX_CACHE_SIZE = 1024 * 50; // 50KB
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
|
||||
String contentType = req.getContentType();
|
||||
|
||||
// 只处理 JSON,排除文件上传
|
||||
if (contentType != null
|
||||
&& contentType.contains("application/json")
|
||||
&& !contentType.contains("multipart/form-data")) {
|
||||
|
||||
ContentCachingRequestWrapper wrapper =
|
||||
new ContentCachingRequestWrapper(req, MAX_CACHE_SIZE);
|
||||
|
||||
chain.doFilter(wrapper, response);
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-47
@@ -3,6 +3,7 @@ package cn.g3soft.utils;
|
||||
import cn.g3soft.exception.ExceptionDetailInfo;
|
||||
import cn.g3soft.utils.uniqueId.idgen.UniqueId;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -10,10 +11,7 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class ExceptionUtils {
|
||||
|
||||
@@ -43,7 +41,6 @@ public class ExceptionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
String briefMessage;
|
||||
|
||||
if (ex.getMessage() != null) {
|
||||
@@ -67,54 +64,38 @@ public class ExceptionUtils {
|
||||
briefMessage = ex.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
String paramJson = null;
|
||||
// 先尝试从parameterMap获取普通参数
|
||||
Map<String, String> paramMap = new HashMap<>();
|
||||
Enumeration<String> paramNames = request.getParameterNames();
|
||||
while (paramNames.hasMoreElements()) {
|
||||
String paramName = paramNames.nextElement();
|
||||
paramMap.put(paramName, request.getParameter(paramName));
|
||||
}
|
||||
// ================= 参数获取 =================
|
||||
String paramJson = "{}";
|
||||
|
||||
// 如果普通参数为空,尝试读取请求体(用于@RequestBody)
|
||||
if (paramMap.isEmpty()) {
|
||||
try {
|
||||
// 获取请求体内容
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
bodyBuilder.append(line);
|
||||
try {
|
||||
// 1️⃣ URL参数
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
if (!parameterMap.isEmpty()) {
|
||||
Map<String, String> simpleMap = new HashMap<>();
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
simpleMap.put(entry.getKey(), Arrays.toString(entry.getValue()));
|
||||
}
|
||||
String requestBody = bodyBuilder.toString();
|
||||
paramJson = JsonUtils.toJson(simpleMap);
|
||||
} else {
|
||||
// 2️⃣ Body(重点)
|
||||
if (request instanceof ContentCachingRequestWrapper) {
|
||||
ContentCachingRequestWrapper wrapper =
|
||||
(ContentCachingRequestWrapper) request;
|
||||
|
||||
if (!requestBody.isEmpty()) {
|
||||
// 如果是JSON格式,可以尝试解析
|
||||
try {
|
||||
// 尝试将JSON字符串格式化为可读格式
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Object jsonObject = mapper.readValue(requestBody, Object.class);
|
||||
paramJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
|
||||
} catch (Exception e) {
|
||||
// 如果不是JSON,直接使用原始字符串
|
||||
paramJson = requestBody.length() > 1000 ?
|
||||
requestBody.substring(0, 1000) + "..." : requestBody;
|
||||
byte[] buf = wrapper.getContentAsByteArray();
|
||||
|
||||
if (buf.length > 0) {
|
||||
String body = new String(buf, StandardCharsets.UTF_8);
|
||||
|
||||
// 截断,防止过长
|
||||
paramJson = body.length() > 1000
|
||||
? body.substring(0, 1000) + "..."
|
||||
: body;
|
||||
}
|
||||
} else {
|
||||
paramJson = "{}";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
paramJson = "请求体读取失败: " + e.getMessage();
|
||||
}
|
||||
} else {
|
||||
// 如果有普通参数,则序列化普通参数
|
||||
try {
|
||||
paramJson = JsonUtils.toJson(paramMap);
|
||||
} catch (Exception e) {
|
||||
paramJson = "参数序列化失败: " + e.getMessage();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
paramJson = "参数解析失败: " + e.getMessage();
|
||||
}
|
||||
|
||||
return ExceptionDetailInfo.builder()
|
||||
|
||||
Reference in new issue
Block a user