统一日志输出打印POST请求参数

打印 上一主题 下一主题

主题 834|帖子 834|积分 2502

众所周知,request.getInputStream()只能调一次。如果希望在请求进入Controller之前统一打印请求参数(拦截器或过滤器),又不影响业务,我们只能将获取到的输入流缓存起来,后续都从缓存中获取即可。
首先,自定义一个ServletInputStream
  1. package com.cjs.example.log.filter;
  2. import javax.servlet.ReadListener;
  3. import javax.servlet.ServletInputStream;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.IOException;
  6. /**
  7. * @Author: ChengJianSheng
  8. * @Date: 2023/3/6
  9. */
  10. public class CustomServletInputStream extends ServletInputStream {
  11.     private ByteArrayInputStream inputStream;
  12.     public CustomServletInputStream(byte[] body) {
  13.         this.inputStream = new ByteArrayInputStream(body);
  14.     }
  15.     @Override
  16.     public boolean isFinished() {
  17.         return inputStream.available() == 0;
  18.     }
  19.     @Override
  20.     public boolean isReady() {
  21.         return true;
  22.     }
  23.     @Override
  24.     public void setReadListener(ReadListener readListener) {
  25.     }
  26.     @Override
  27.     public int read() throws IOException {
  28.         return inputStream.read();
  29.     }
  30. }
复制代码
然后,自定义一个HttpServletRequestWrapper
  1. package com.cjs.example.log.filter;
  2. import org.apache.commons.io.IOUtils;
  3. import javax.servlet.ServletInputStream;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletRequestWrapper;
  6. import java.io.*;
  7. /**
  8. * @Author: ChengJianSheng
  9. * @Date: 2023/3/6
  10. */
  11. public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
  12.     private byte[] body;
  13.     public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
  14.         super(request);
  15.         body = IOUtils.toByteArray(request.getInputStream());
  16.     }
  17.     @Override
  18.     public ServletInputStream getInputStream() throws IOException {
  19.         return new CustomServletInputStream(body);
  20.     }
  21.     @Override
  22.     public BufferedReader getReader() throws IOException {
  23.         return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
  24.     }
  25. }
复制代码
接下来,写一个过滤器,在过滤器中打印请求参数
  1. package com.cjs.example.log.filter;
  2. import org.apache.commons.io.IOUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import javax.servlet.*;
  6. import javax.servlet.http.HttpServletRequest;
  7. import java.io.IOException;
  8. /**
  9. * @Author: ChengJianSheng
  10. * @Date: 2023/3/6
  11. */
  12. public class LogFilter implements Filter {
  13.     private final static Logger logger = LoggerFactory.getLogger(LogFilter.class);
  14.     @Override
  15.     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  16.         CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
  17.         printLog(requestWrapper);
  18.         filterChain.doFilter(requestWrapper, servletResponse);
  19.     }
  20.     private void printLog(CustomHttpServletRequestWrapper requestWrapper) throws IOException {
  21.         logger.info("请求URL: {}", requestWrapper.getRequestURL());
  22.         String method = requestWrapper.getMethod();
  23.         if ("GET".equalsIgnoreCase(method)) {
  24.             logger.info("请求参数: {}", requestWrapper.getQueryString());
  25.         } else if ("POST".equalsIgnoreCase(method) && "application/json".equalsIgnoreCase(requestWrapper.getContentType())) {
  26.             String body = IOUtils.toString(requestWrapper.getInputStream(), requestWrapper.getCharacterEncoding());
  27.             logger.info("请求参数: {}", body);
  28.         }
  29.     }
  30. }
复制代码
请求经过过滤器的时候,首先在构造CustomHttpServletRequestWrapper的时候将请求中的InputStream转成字节数字缓存到内存中,然后后面每次再getInputStream()的时候都从缓存中取出内容并返回一个新的ServletInputStream
最后,定义一个配置类
  1. package com.cjs.example.log.config;
  2. import com.cjs.example.log.filter.LogFilter;
  3. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. /**
  7. * @Author: ChengJianSheng
  8. * @Date: 2023/3/6
  9. */
  10. @Configuration
  11. public class CustomLogAutoConfiguration {
  12.     @Bean
  13.     @ConditionalOnMissingBean
  14.     public LogFilter logFilter() {
  15.         return new LogFilter();
  16.     }
  17. }
复制代码
在resources/META-INF/spring.factories中新增一行自动配置
  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.cjs.example.log.config.CustomLogAutoConfiguration
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

尚未崩坏

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表