• Spring中操作日志记录web请求的body报文


    在spring中,通常可以使用切面编程方式对web请求记录操作日志。但是这种方式存在一个问题,那就是只能记录url中的请求参数,无法记录POST或者PUT请求的报文体,因为报文体是放在request对象的InputStream中的,只能读取一次。解决方法就是利用HttpServletRequestWrapper先读取InputStream,记录到一个头参数中,然后再重新放到InputStream中去。

    代码如下:
    先创建一个WrappedHttpServletRequest类:

    import org.apache.commons.io.IOUtils;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    
    public class WrappedHttpServletRequest extends HttpServletRequestWrapper {
    
      private byte[] bytes;
      private WrappedServletInputStream wrappedServletInputStream;
    
      public WrappedHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        // 读取输入流里的请求参数,并保存到bytes里
        bytes = IOUtils.toByteArray(request.getInputStream());
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);
    
        // 很重要,把post参数重新写入请求流
        reWriteInputStream();
      }
    
      /**
       * 把参数重新写进请求里
       */
      public void reWriteInputStream() {
        wrappedServletInputStream
            .setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));
      }
    
      @Override
      public ServletInputStream getInputStream() throws IOException {
        return wrappedServletInputStream;
      }
    
      @Override
      public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(wrappedServletInputStream));
      }
    
      /**
       * 获取post参数,可以自己再转为相应格式
       */
      public String getRequestParams() throws IOException {
        return new String(bytes, this.getCharacterEncoding());
      }
    
      private class WrappedServletInputStream extends ServletInputStream {
    
        public void setStream(InputStream stream) {
          this.stream = stream;
        }
    
        private InputStream stream;
    
        public WrappedServletInputStream(InputStream stream) {
          this.stream = stream;
        }
    
        @Override
        public int read() throws IOException {
          return stream.read();
        }
    
        @Override
        public boolean isFinished() {
          return true;
        }
    
        @Override
        public boolean isReady() {
          return true;
        }
    
        @Override
        public void setReadListener(ReadListener readListener) {}
      }
    }

    再创建一个LogFilter对象:

    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Component;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Component
    @WebFilter(value = "/*", filterName = "logFilter")
    @Slf4j
    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 {
    
        try {
          WrappedHttpServletRequest requestWrapper =
              new WrappedHttpServletRequest((HttpServletRequest) request);
    
          // 获取请求参数
          String requestBody = requestWrapper.getRequestParams();
          if (!StringUtils.isBlank(requestBody)) {
            if (requestBody.length() >= 8192) {
              requestBody = requestBody.substring(0, 8192);
            }
            request.setAttribute("request-body", requestBody); // 这里创建一个参数头,把要记录的报文放到参数头里面,在切面中读取这个参数头
          }
    
          // 这里doFilter传入我们实现的子类
          chain.doFilter(requestWrapper, response);
        } catch (Exception e) {
          log.error(e.getMessage(), e);
        }
      }
    
      @Override
      public void destroy() {}
    }
  • 相关阅读:
    呵呵

    HDU 1878 欧拉回路
    HDU 3293 sort
    HDU 2714 ISBN
    神秀作偈
    大学之道
    写给自己过去疯狂的一年(2)(写在一个特别的时候)
    这几天我的生活就是这样的
    学习和研究计划
  • 原文地址:https://www.cnblogs.com/lasdaybg/p/9929501.html
Copyright © 2020-2023  润新知