|
@@ -5,21 +5,29 @@ import com.example.service.common.RequestLogService;
|
|
|
import com.example.utils.AESUtil;
|
|
|
import com.example.utils.R;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
-import com.google.gson.Gson;
|
|
|
-import com.google.gson.reflect.TypeToken;
|
|
|
+import com.fasterxml.jackson.databind.type.TypeFactory;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.slf4j.MDC;
|
|
|
+import org.springframework.core.MethodParameter;
|
|
|
+import org.springframework.http.HttpInputMessage;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.http.converter.HttpMessageConverter;
|
|
|
+import org.springframework.http.server.ServerHttpRequest;
|
|
|
+import org.springframework.http.server.ServerHttpResponse;
|
|
|
import org.springframework.lang.Nullable;
|
|
|
import org.springframework.util.StopWatch;
|
|
|
-import org.springframework.util.StreamUtils;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
+import org.springframework.web.bind.annotation.ControllerAdvice;
|
|
|
import org.springframework.web.servlet.HandlerInterceptor;
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.io.IOException;
|
|
|
+import java.lang.reflect.Type;
|
|
|
import java.net.URLDecoder;
|
|
|
-import java.nio.charset.Charset;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
@@ -32,16 +40,16 @@ import java.util.UUID;
|
|
|
* 请求日志拦截器
|
|
|
*/
|
|
|
@Slf4j
|
|
|
-public class RequestLogHandlerInterceptor implements HandlerInterceptor {
|
|
|
+@ControllerAdvice
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class RequestLogHandlerInterceptor implements HandlerInterceptor, RequestBodyAdvice, ResponseBodyAdvice<Object> {
|
|
|
/**
|
|
|
* 计时器线程变量
|
|
|
*/
|
|
|
private static final ThreadLocal<StopWatch> STOP_WATCH_THREAD_LOCAL = new ThreadLocal<>();
|
|
|
- private RequestLogService requestLogService;
|
|
|
-
|
|
|
- public RequestLogHandlerInterceptor(RequestLogService requestLogService) {
|
|
|
- this.requestLogService = requestLogService;
|
|
|
- }
|
|
|
+ private static final ThreadLocal<RequestLogPo> REQUEST_LOG_PO_THREAD_LOCAL = new ThreadLocal<>();
|
|
|
+ private final RequestLogService requestLogService;
|
|
|
+ private final ObjectMapper objectMapper;
|
|
|
|
|
|
@Override
|
|
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
|
@@ -71,12 +79,6 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
|
|
|
parameters.put(k, v);
|
|
|
}
|
|
|
log.info("查询参数: {}", new ObjectMapper().writeValueAsString(parameters));
|
|
|
- String body = null;
|
|
|
- if (!MyDispatcherServlet.UN_WRAPPER.contains(request.getRequestURI())) {
|
|
|
- // 请求体参数
|
|
|
- body = StreamUtils.copyToString(request.getInputStream(), Charset.forName(request.getCharacterEncoding()));
|
|
|
- log.info("请求体参数: {}", StringUtils.trimAllWhitespace(body));
|
|
|
- }
|
|
|
String token = request.getHeader("token");
|
|
|
if (!StringUtils.hasText(token) || "undefined".equals(token)) {
|
|
|
token = parameters.get("token");
|
|
@@ -90,9 +92,8 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
|
|
|
log.info("urlDecodeToken: {}", urlDecodeToken);
|
|
|
String decryptToken = AESUtil.decrypt(urlDecodeToken);
|
|
|
log.info("decryptToken: {}", decryptToken);
|
|
|
- Gson gson = new Gson();
|
|
|
- Map<String, String> map = gson.fromJson(decryptToken, new TypeToken<Map<String, String>>() {
|
|
|
- }.getType());
|
|
|
+ Map<String, String> map = objectMapper.readValue(decryptToken,
|
|
|
+ TypeFactory.defaultInstance().constructMapType(Map.class, String.class, String.class));
|
|
|
if (!"FINANCE".equals(map.get("APP_ID"))
|
|
|
|| !StringUtils.hasText(map.get("LOGIN_ID"))
|
|
|
|| !StringUtils.hasText(map.get("TIME_STAMP"))
|
|
@@ -109,21 +110,20 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
|
|
|
return unauthorized(response);
|
|
|
}
|
|
|
Map<String, String> requestParameters = new HashMap<>();
|
|
|
- requestParameters.put("request_parameters", gson.toJson(parameters));
|
|
|
- requestParameters.put("request_body", body);
|
|
|
+ requestParameters.put("request_parameters", objectMapper.writeValueAsString(parameters));
|
|
|
RequestLogPo requestLogPo = new RequestLogPo();
|
|
|
+ REQUEST_LOG_PO_THREAD_LOCAL.set(requestLogPo);
|
|
|
requestLogPo.setRequestTime(now);
|
|
|
requestLogPo.setLoginId(map.get("LOGIN_ID"));
|
|
|
requestLogPo.setPageUrl(map.get("REQUEST_URL"));
|
|
|
requestLogPo.setApi(request.getRequestURI());
|
|
|
- requestLogPo.setRequestParameters(gson.toJson(requestParameters));
|
|
|
- requestLogPo.setHeaders(gson.toJson(headers));
|
|
|
+ requestLogPo.setRequestParameters(objectMapper.writeValueAsString(requestParameters));
|
|
|
+ requestLogPo.setHeaders(objectMapper.writeValueAsString(headers));
|
|
|
requestLogPo.setAppId(map.get("APP_ID"));
|
|
|
requestLogPo.setToken(urlDecodeToken);
|
|
|
requestLogPo.setTimeStamp(timeStamp);
|
|
|
requestLogPo.setExpireTime(expireTime);
|
|
|
requestLogPo.setExpireTimeStamp(expireTimeStamp);
|
|
|
- requestLogService.offer(requestLogPo);
|
|
|
} catch (Exception e) {
|
|
|
log.error("token解密失败: {} {}", token, e.getMessage(), e);
|
|
|
return forbidden(response);
|
|
@@ -134,47 +134,97 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
|
|
|
@Override
|
|
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
|
|
@Nullable Exception ex) throws Exception {
|
|
|
- if (!MyDispatcherServlet.UN_WRAPPER.contains(request.getRequestURI())) {
|
|
|
- MyHttpServletResponseWrapper wrapper = (MyHttpServletResponseWrapper) response;
|
|
|
- String responseString = new String(wrapper.toByteArray());
|
|
|
-// log.info("响应 {}: {}", wrapper.getStatus(), responseString);
|
|
|
- // 返回结果打印前500个字符
|
|
|
- log.info("返回 {}: {}", wrapper.getStatus(),
|
|
|
- org.apache.commons.lang3.StringUtils.substring(responseString, 0, 500));
|
|
|
- } else {
|
|
|
- log.info("响应 {}", response.getStatus());
|
|
|
- }
|
|
|
+ log.info("响应状态: {}", response.getStatus());
|
|
|
StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
|
|
|
stopWatch.stop();
|
|
|
- log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());
|
|
|
+ log.info("耗时: {} ms", stopWatch.getTotalTimeMillis());
|
|
|
STOP_WATCH_THREAD_LOCAL.remove();
|
|
|
+ RequestLogPo requestLogPo = REQUEST_LOG_PO_THREAD_LOCAL.get();
|
|
|
+ if (requestLogPo != null) {
|
|
|
+ requestLogService.offer(requestLogPo);
|
|
|
+ }
|
|
|
+ REQUEST_LOG_PO_THREAD_LOCAL.remove();
|
|
|
}
|
|
|
|
|
|
private boolean forbidden(HttpServletResponse response) throws IOException {
|
|
|
- response.setCharacterEncoding("UTF-8");
|
|
|
- response.setContentType("application/json; charset=utf-8");
|
|
|
- String r = new Gson().toJson(R.error(403, "没有权限访问"));
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
|
|
+ String r = objectMapper.writeValueAsString(R.error(403, "没有权限访问"));
|
|
|
byte[] bytes = r.getBytes();
|
|
|
response.getOutputStream().write(bytes);
|
|
|
StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
|
|
|
stopWatch.stop();
|
|
|
- log.warn("返回 {}: {}", response.getStatus(), r);
|
|
|
+ log.warn("响应状态: {}", response.getStatus());
|
|
|
+ log.warn("响应内容: {}", r);
|
|
|
log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());
|
|
|
STOP_WATCH_THREAD_LOCAL.remove();
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
private boolean unauthorized(HttpServletResponse response) throws IOException {
|
|
|
- response.setCharacterEncoding("UTF-8");
|
|
|
- response.setContentType("application/json; charset=utf-8");
|
|
|
- String r = new Gson().toJson(R.error(401, "请刷新页面或重新登录"));
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
|
|
+ String r = objectMapper.writeValueAsString(R.error(401, "请刷新页面或重新登录"));
|
|
|
byte[] bytes = r.getBytes();
|
|
|
response.getOutputStream().write(bytes);
|
|
|
StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
|
|
|
stopWatch.stop();
|
|
|
- log.info("返回 {}: {}", response.getStatus(), r);
|
|
|
+ log.warn("响应状态: {}", response.getStatus());
|
|
|
+ log.warn("响应内容: {}", r);
|
|
|
log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());
|
|
|
STOP_WATCH_THREAD_LOCAL.remove();
|
|
|
return false;
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
|
|
|
+ return inputMessage;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ try {
|
|
|
+ if (STOP_WATCH_THREAD_LOCAL.get() != null) {
|
|
|
+ String bodyStr = objectMapper.writeValueAsString(body);
|
|
|
+ log.info("请求体参数: {}", bodyStr);
|
|
|
+ RequestLogPo requestLogPo = REQUEST_LOG_PO_THREAD_LOCAL.get();
|
|
|
+ if (requestLogPo != null) {
|
|
|
+ Map<String, String> requestParameters = objectMapper.readValue(requestLogPo.getRequestParameters(),
|
|
|
+ TypeFactory.defaultInstance().constructMapType(Map.class, String.class, String.class));
|
|
|
+ requestParameters.put("request_body", bodyStr);
|
|
|
+ requestLogPo.setRequestParameters(objectMapper.writeValueAsString(requestParameters));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.toString(), e);
|
|
|
+ }
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
|
|
|
+ try {
|
|
|
+ if (STOP_WATCH_THREAD_LOCAL.get() != null) {
|
|
|
+ log.info("响应内容: {}", org.apache.commons.lang3.StringUtils.substring(objectMapper.writeValueAsString(body), 0, 500));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.toString(), e);
|
|
|
+ }
|
|
|
+ return body;
|
|
|
+ }
|
|
|
}
|