美文网首页
spring2.x 拦截器实现日志打印,json类型日志打印

spring2.x 拦截器实现日志打印,json类型日志打印

作者: 砂糖z | 来源:发表于2018-08-14 15:27 被阅读0次

    需求:日志打印请求参数

    做法:

    以下部分错误代码
    1.使用拦截器

    public class LogInterceptor implements HandlerInterceptor {
    
        private NamedThreadLocal<Long> startTimeThreadLocal=new NamedThreadLocal<Long>("StartTime-EndTime");
    
        private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
    
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            Map<String, Object> parames = WebUtil.getParameters(request);
            logger.info("servletPath===>{},parameters====>{}",request.getServletPath(),JSON.toJSONString(parames));
            logger.info("method==>{}",request.getMethod());
            HandlerMethod hand = (HandlerMethod)handler;
            logger.info("methodPath====>{}",hand.getMethod());
            startTimeThreadLocal.set(System.currentTimeMillis());
            return true;
        }
    
    
        /**
         * 异常结束
         * @param request
         * @param response
         * @param handler
         * @param ex
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            final Long startTime = startTimeThreadLocal.get();
            final Long endTime = System.currentTimeMillis();
            HandlerMethod hand = (HandlerMethod)handler;
            if(ex != null) {
                logger.error("methodPath====> {}, start time===> {} used time==> {}", hand.getMethod(), DateUtil.parse(startTime),
                        DateUtil.parseMins(endTime - startTime));
            }
    
        }
    

    解析request中的请求参数

    public class WebUtil {
    
        public static ThreadLocal<HttpServletRequest> REQUEST = new NamedThreadLocal<HttpServletRequest>(
                "ThreadLocalRequest");
    
        public static Map<String, Object> getParameters(ServletRequest request) {
            Map<String, Object> params = null;
            if (request != null) {
                //是html/text
                params = WebUtils.getParametersStartingWith(request, null);
                //是json
                if (params.isEmpty()) {
                    params = JSON.parseObject(getParametersJson(request), Map.class);
                }
            }
            return params;
        }
    
        public static String getParametersJson(ServletRequest request) {
            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader bufferedReader = null;
            String body = null;
            try {
                bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } catch (IOException ex) {
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException ex) {
                    }
                }
            }
            body = stringBuilder.toString();
            return body;
        }
    }
    

    因为我还写了全局异常类,所以我在全局异常类中处理异常。
    配置上就有效果

    @Configuration
    public  class WebMvcConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
        }
    
    }
    

    但是出现异常

    Caused by: java.io.IOException: Stream closed
    at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:334) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:93) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
    at java.io.FilterInputStream.read(FilterInputStream.java:83) ~[na:1.8.0_131]
    at java.io.PushbackInputStream.read(PushbackInputStream.java:139) ~[na:1.8.0_131]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver$EmptyBodyCheckingHttpInputMessage.<init>(AbstractMessageConverterMethodArgumentResolver.java:319) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:192) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    ... 101 common frames omitted

    原因:json类型的参数读取,在执行后面操作时出现异常,由于request是采用流的形式传递数据,请求主体只能被读取一次。
    异常解决方法:
    https://cloud.tencent.com/developer/ask/76655 ----->不全面

    修改

    要写:HttpServletRequestWrapper 后面的代码要读取request.getInputStream() 时按照我们的方法读取。

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    
    /**
     * @author xxwy
     * on 2018/8/14 0014
     */
    public class LogRequestWrapper extends HttpServletRequestWrapper {
    
        private static final Logger logger = LoggerFactory.getLogger(LogRequestWrapper.class);
    
        private final String body;
    
        public LogRequestWrapper(HttpServletRequest request)  {
            super(request);
            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader bufferedReader = null;
            try {
                InputStream inputStream = request.getInputStream();
                if (inputStream != null) {
                    bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
                    char[] charBuffer = new char[128];
                    int bytesRead = -1;
                    while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                        stringBuilder.append(charBuffer, 0, bytesRead);
                    }
                } else {
                    stringBuilder.append(" ");
                }
            } catch (IOException ex) {
                logger.error("获取request流出现异常");
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException ex) {
                        logger.error("关闭bufferedReader出现异常");
                    }
                }
            }
            body = stringBuilder.toString();
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream byteArrayInputStream = new  ByteArrayInputStream(body.getBytes());
            ServletInputStream servletInputStream = 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 byteArrayInputStream.read();
                }
            };
            return servletInputStream;
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }
    
        public String getBody() {
            return this.body;
        }
    }
    

    通过 过滤器绑定到我们的springboot容器内

    public class LogFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            if (request instanceof HttpServletRequest) {
                ServletRequest requestWrapper = new LogRequestWrapper((HttpServletRequest) request);
                chain.doFilter(requestWrapper, response);
            } else {
                chain.doFilter(request, response);
            }
    
        }
    
        @Override
        public void destroy() {
    
        }
        
    }
    

    注册上过滤器

    /**
         *过滤器
         * @return
         */
        @Bean
        public FilterRegistrationBean<LogFilter> localeFilterRegistration() {
            FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<LogFilter>(
                    new LogFilter());
            registration.setName("logFilter");
            registration.addUrlPatterns("/*");
            //优先级
            registration.setOrder(Integer.MAX_VALUE);
            return registration;
        }
    

    感受:

    还是要知道运行流程才能定位错误未知,下次补上感受,先发布

    相关文章

      网友评论

          本文标题:spring2.x 拦截器实现日志打印,json类型日志打印

          本文链接:https://www.haomeiwen.com/subject/ucnmbftx.html