Browse Source

feat: 使用请求拦截器替换aop打印请求日志

weijianghai 2 năm trước cách đây
mục cha
commit
0d7515b5e5

+ 6 - 0
build-dir/rollback.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+sh stop.sh
+rm -rf domainBApi.jar
+mv domainBApi.jar.bak domainBApi.jar
+sh run.sh

+ 7 - 0
build-dir/update.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+rm -rf domainBApi.jar.bak
+sh stop.sh
+mv domainBApi.jar domainBApi.jar.bak
+mv domainBApi.jar.new domainBApi.jar
+sh run.sh

+ 2 - 1
src/main/java/com/nokia/common/http/R.java

@@ -1,6 +1,7 @@
 package com.nokia.common.http;
 
 import lombok.Data;
+import org.slf4j.MDC;
 
 /**
  * 返回值的统一包装
@@ -41,7 +42,7 @@ public class R {
         R r = new R();
         r.setSuccess(false);
         r.setCode(500);
-        r.setMessage("失败");
+        r.setMessage("失败" + MDC.get("traceId"));
         return r;
     }
     public R success(Boolean success) {

+ 0 - 84
src/main/java/com/nokia/domainb/config/LogAspectConfig.java

@@ -1,84 +0,0 @@
-package com.nokia.domainb.config;
-
-import com.alibaba.fastjson2.JSON;
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.slf4j.MDC;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StopWatch;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * 日志配置
- *
- */
-@Aspect
-@Component
-@Slf4j
-public class LogAspectConfig
-{
-
-    @Pointcut("execution(public * com.nokia..*Controller.*(..))")
-    public void controllerPointcut()
-    {
-        // Pointcut
-    }
-
-    @Pointcut("execution(* com.nokia..ControllerExceptionHandler.*(..))")
-    public void controllerExceptionHandlerPointcut()
-    {
-        // Pointcut
-    }
-
-    @Pointcut("controllerPointcut() || controllerExceptionHandlerPointcut()")
-    public void aroundPointCut()
-    {
-        // Pointcut
-    }
-
-    @Around("aroundPointCut()")
-    public Object around(ProceedingJoinPoint point) throws Throwable
-    {
-        StopWatch stopWatch = new StopWatch();
-        stopWatch.start();
-        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
-        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-        Object result = point.proceed();
-        if (attributes == null)
-        {
-            return result;
-        }
-
-        HttpServletRequest request = attributes.getRequest();
-        Object[] args = point.getArgs();
-        List<Object> list = new ArrayList<>();
-        for (Object arg : args) {
-            if (arg instanceof ServletRequest
-                    || arg instanceof ServletResponse
-                    || arg instanceof MultipartFile
-                    || arg instanceof Exception
-            ) {
-                continue;
-            }
-            list.add(arg);
-        }
-        stopWatch.stop();
-        log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
-        log.info("请求参数: {}", JSON.toJSONString(list));
-        log.info("返回: {}", JSON.toJSONString(result));
-        log.info("耗时:{} ms", stopWatch.getTotalTimeMillis());
-        return result;
-    }
-}

+ 1 - 1
src/main/java/com/nokia/domainb/config/ControllerExceptionHandler.java → src/main/java/com/nokia/domainb/config/web/ControllerExceptionHandler.java

@@ -1,4 +1,4 @@
-package com.nokia.domainb.config;
+package com.nokia.domainb.config.web;
 
 import com.nokia.common.http.R;
 import lombok.extern.slf4j.Slf4j;

+ 14 - 0
src/main/java/com/nokia/domainb/config/web/MyDispatcherServlet.java

@@ -0,0 +1,14 @@
+package com.nokia.domainb.config.web;
+
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class MyDispatcherServlet extends DispatcherServlet {
+    @Override
+    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        // 替换request和response
+        super.doDispatch(new MyHttpServletRequestWrapper(request), new MyHttpServletResponseWrapper(response));
+    }
+}

+ 54 - 0
src/main/java/com/nokia/domainb/config/web/MyHttpServletRequestWrapper.java

@@ -0,0 +1,54 @@
+package com.nokia.domainb.config.web;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StreamUtils;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.*;
+
+/**
+ * 解决流只能读取一次问题
+ */
+@Slf4j
+public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
+    private byte[] bytes;
+
+    public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
+        super(request);
+        bytes = StreamUtils.copyToByteArray(request.getInputStream());
+    }
+
+    @Override
+    public ServletInputStream getInputStream() {
+        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+        return new ServletInputStream() {
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+                //
+            }
+
+            @Override
+            public int read() {
+                return stream.read();
+            }
+        };
+    }
+
+    @Override
+    public BufferedReader getReader() throws UnsupportedEncodingException {
+        return new BufferedReader(new InputStreamReader(getInputStream(), super.getCharacterEncoding()));
+    }
+}

+ 47 - 0
src/main/java/com/nokia/domainb/config/web/MyHttpServletResponseWrapper.java

@@ -0,0 +1,47 @@
+package com.nokia.domainb.config.web;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * 解决流只能读取一次问题
+ */
+public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
+    private ByteArrayOutputStream byteArrayOutputStream;
+    private ServletOutputStream servletOutputStream;
+
+    public MyHttpServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+        byteArrayOutputStream = new ByteArrayOutputStream();
+        servletOutputStream = new ServletOutputStream() {
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setWriteListener(WriteListener writeListener) {
+                //
+            }
+
+            @Override
+            public void write(int b) throws IOException {
+                response.getOutputStream().write(b);
+                byteArrayOutputStream.write(b);
+            }
+        };
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() {
+        return servletOutputStream;
+    }
+
+    public byte[] toByteArray() {
+        return byteArrayOutputStream.toByteArray();
+    }
+}

+ 52 - 0
src/main/java/com/nokia/domainb/config/web/MyWebMvcConfigurer.java

@@ -0,0 +1,52 @@
+package com.nokia.domainb.config.web;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MyWebMvcConfigurer implements WebMvcConfigurer {
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 添加请求日志拦截
+        registry.addInterceptor(new RequestLogHandlerInterceptor()).addPathPatterns("/**");
+    }
+
+    /**
+     * 使用自定义DispatcherServlet
+     */
+    @Bean
+    @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
+    public DispatcherServlet dispatcherServlet() {
+        return new MyDispatcherServlet();
+    }
+
+//    /**
+//     * 配置消息转换器
+//     *
+//     * @param converters 转换器
+//     */
+//    @Override
+//    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
+//        converters.add(mappingJackson2HttpMessageConverter());
+//    }
+//
+//    /**
+//     * 配置映射jackson2 http消息转换器
+//     *
+//     * @return {@link MappingJackson2HttpMessageConverter}
+//     */
+//    @Bean
+//    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
+//        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
+//        ObjectMapper mapper = new ObjectMapper();
+//        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+//        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+//        converter.setObjectMapper(mapper);
+//        return converter;
+//    }
+}

+ 70 - 0
src/main/java/com/nokia/domainb/config/web/RequestLogHandlerInterceptor.java

@@ -0,0 +1,70 @@
+package com.nokia.domainb.config.web;
+
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StopWatch;
+import org.springframework.util.StreamUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.nio.charset.Charset;
+import java.util.UUID;
+
+/**
+ * 请求日志拦截器
+ */
+@Slf4j
+public class RequestLogHandlerInterceptor implements HandlerInterceptor {
+    /**
+     * 计时器线程变量
+     */
+    private static final ThreadLocal<StopWatch> STOP_WATCH_THREAD_LOCAL = new ThreadLocal<>();
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+        // 计时器放入线程变量
+        STOP_WATCH_THREAD_LOCAL.set(stopWatch);
+        // 日志添加跟踪id
+        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
+        log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
+        // 请求头参数
+//        Map<String, String> headers = new HashMap<>();
+//        Enumeration<String> headerNames = request.getHeaderNames();
+//        while (headerNames.hasMoreElements()) {
+//            String k	= headerNames.nextElement();
+//            String v = request.getHeader(k);
+//            headers.put(k, v);
+//        }
+//        log.info("请求头参数: {}", JSON.toJSONString(headers));
+        // 查询参数
+//        Map<String, String> parameters = new HashMap<>();
+//        Enumeration<String> parameterNames = request.getParameterNames();
+//        while (parameterNames.hasMoreElements()) {
+//            String k	= parameterNames.nextElement();
+//            String v = request.getParameter(k);
+//            parameters.put(k, v);
+//        }
+//        log.info("查询参数: {}", JSON.toJSONString(parameters));
+        // 请求体参数
+        String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName(request.getCharacterEncoding()));
+        log.info("请求参数: {}", StringUtils.trimAllWhitespace(body));
+        return true;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
+                                @Nullable Exception ex) throws Exception {
+        MyHttpServletResponseWrapper wrapper = (MyHttpServletResponseWrapper) response;
+        String responseString = new String(wrapper.toByteArray());
+        log.info("返回 {}: {}", wrapper.getStatus(), responseString);
+        StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
+        stopWatch.stop();
+        log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());
+        STOP_WATCH_THREAD_LOCAL.remove();
+    }
+}