• 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() {}
    }
  • 相关阅读:
    Apache Commons CLI命令行启动
    《三体1——地球往事》—— 读后总结
    《鬼谷子的局4》 —— 读后总结
    Microsoft Visual C++ 2017 Redistributable
    Navicat Premium 12安装与激活(亲测已成功激活)
    如何从DOS命令窗口进行复制粘贴
    使用java写js中类似setTimeout的代码
    Spring @RestController、@Controller区别
    SpringBoot整合Swagger2
    git clone 报“The project you were looking for could not be found.”
  • 原文地址:https://www.cnblogs.com/lasdaybg/p/9929501.html
Copyright © 2020-2023  润新知