zoukankan      html  css  js  c++  java
  • 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() {}
    }
  • 相关阅读:
    c++ stl string char* 向 string 转换的问题
    不要在疲惫中工作
    今天
    悠然自得
    忙与闲
    <转>LuaTinker的bug和缺陷
    匿名管道
    SetWindowHookEx 做消息响应
    最近工作
    实现网页页面跳转的几种方法(meta标签、js实现、php实现)
  • 原文地址:https://www.cnblogs.com/lasdaybg/p/9929501.html
Copyright © 2011-2022 走看看