众所周知,request.getInputStream()只能调一次。如果希望在请求进入Controller之前统一打印请求参数(拦截器或过滤器),又不影响业务,我们只能将获取到的输入流缓存起来,后续都从缓存中获取即可。

首先,自定义一个ServletInputStream

package com.cjs.example.log.filter;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException; /**
* @Author: ChengJianSheng
* @Date: 2023/3/6
*/
public class CustomServletInputStream extends ServletInputStream { private ByteArrayInputStream inputStream; public CustomServletInputStream(byte[] body) {
this.inputStream = new ByteArrayInputStream(body);
} @Override
public boolean isFinished() {
return inputStream.available() == 0;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener readListener) { } @Override
public int read() throws IOException {
return inputStream.read();
}
}

然后,自定义一个HttpServletRequestWrapper

package com.cjs.example.log.filter;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*; /**
* @Author: ChengJianSheng
* @Date: 2023/3/6
*/
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] body; public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = IOUtils.toByteArray(request.getInputStream());
} @Override
public ServletInputStream getInputStream() throws IOException {
return new CustomServletInputStream(body);
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
}
}

接下来,写一个过滤器,在过滤器中打印请求参数

package com.cjs.example.log.filter;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; /**
* @Author: ChengJianSheng
* @Date: 2023/3/6
*/
public class LogFilter implements Filter { private final static Logger logger = LoggerFactory.getLogger(LogFilter.class); @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
printLog(requestWrapper);
filterChain.doFilter(requestWrapper, servletResponse);
} private void printLog(CustomHttpServletRequestWrapper requestWrapper) throws IOException {
logger.info("请求URL: {}", requestWrapper.getRequestURL());
String method = requestWrapper.getMethod();
if ("GET".equalsIgnoreCase(method)) {
logger.info("请求参数: {}", requestWrapper.getQueryString());
} else if ("POST".equalsIgnoreCase(method) && "application/json".equalsIgnoreCase(requestWrapper.getContentType())) {
String body = IOUtils.toString(requestWrapper.getInputStream(), requestWrapper.getCharacterEncoding());
logger.info("请求参数: {}", body);
}
}
}

请求经过过滤器的时候,首先在构造CustomHttpServletRequestWrapper的时候将请求中的InputStream转成字节数字缓存到内存中,然后后面每次再getInputStream()的时候都从缓存中取出内容并返回一个新的ServletInputStream

最后,定义一个配置类

package com.cjs.example.log.config;

import com.cjs.example.log.filter.LogFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @Author: ChengJianSheng
* @Date: 2023/3/6
*/
@Configuration
public class CustomLogAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LogFilter logFilter() {
return new LogFilter();
}
}

在resources/META-INF/spring.factories中新增一行自动配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.cjs.example.log.config.CustomLogAutoConfiguration

统一日志输出打印POST请求参数的更多相关文章

  1. Logback 整合 RabbitMQ 实现统一日志输出

    原文地址:Logback 整合 RabbitMQ 实现统一日志输出 博客地址:http://www.extlight.com 一.前言 公司项目做了集群实现请求分流,由于线上或多或少会出现请求失败或系 ...

  2. Spring AOP实现统一日志输出

    目的: 统一日志输出格式 思路: 1.针对不同的调用场景定义不同的注解,目前想的是接口层和服务层. 2.我设想的接口层和服务层的区别在于: (1)接口层可以打印客户端IP,而服务层不需要 (2)接口层 ...

  3. nginx 日志打印post请求参数

    在日志格式后面加上 $request_body 配置信息 log_format main '$remote_addr - $remote_user [$time_local] "$reque ...

  4. 转发:tomcat的acess_log打印post请求参数,分析日志

    转载自:https://blog.csdn.net/qq_30121245/article/details/52861935 1) 在项目中加入相应的包和类,加载那里无所谓,只要web.xml配置正确 ...

  5. spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码

    1.背景 在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下 2.代码 package com.qianxingniwo.log; ...

  6. SpringBoot2.0针对请求参数@RequestBody验证统一拦截

    title: "SpringBoot2.0针对请求参数@RequestBody验证的统一拦截"categories: SpringBoot2.0 Shirotags: Spring ...

  7. springboot 学习之路 4(日志输出)

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

  8. Spring AOP统一日志 全量日志

    Spring AOP 切面@Around注解的具体使用 lichuangcsdn 2019-02-19 23:21:36 63936 收藏 61分类专栏: Spring 文章标签: Spring AO ...

  9. struts2之请求参数接收

    struts2之请求参数接收 1. 采用基本类型接受请求参数(get/post)在Action类中定义与请求参数同名的属性,struts2便能自动接收请求参数并赋予给同名的属性.请求路径:http:/ ...

  10. struts2接受请求参数

    https://blog.csdn.net/y249839817/article/details/77702745 https://blog.csdn.net/nthack5730/article/d ...

随机推荐

  1. 超全面总结Vue面试知识点,助力金三银四

    前言 本文会对Vue中一些常见的重要知识点以及框架原理进行整理汇总,意在帮助作者以及读者自测Vue的熟练度以及方便查询与复习.金三银四的到来,想必vue会是很多面试官的重点考核内容,希望小伙伴们读完本 ...

  2. SQLServer数据库JDBC连接串参数的简单学习

    SQLServer数据库JDBC连接串参数的简单学习 背景 前段时间一直跟同事一起处理SQLServer 比其他数据库的deadlock更多的问题. 涉及到了几个驱动的参数. 想着问题基本上告一段落, ...

  3. [转帖]TiKV 缩容不掉如何解决?

    TiKV节点缩容不掉,通常遇到的情况: 1.经常遇到的情况是:3个节点的tikv集群缩容肯定会一直卡着,因为没有新节点接受要下线kv的region peer. 2.另外就是除缩容tikv外,剩下的KV ...

  4. [转帖]关于https://goproxy.cn,direct与https://proxy.golang.org的问题,国内无法访问https://proxy.golang.org设置了GOPROXY仍不可行

    关于https://goproxy.cn,direct与https://proxy.golang.org的问题,国内无法访问https://proxy.golang.org设置了GOPROXY仍不可行 ...

  5. gcore的学习

    gcore的学习-解决jmap无法生成dump文件的一种方法 背景 周末在跆拳道馆看孩子练跆拳道. 开着笔记本翻到了 扣钉日记 公众号里面的讲解 想着自己也遇到过无法保存dump文件的情况. 所以想学 ...

  6. [转帖]2.20 Native Operating System Tools

    https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr020.html#BABBHHIE 2.20  ...

  7. Linux 查询最近占用内存最多的十个进程的方法

    ps -eo rss,pid,user,command --sort -rss | awk '{ hr=$1/1024 ; printf("%13.2f Mb ",hr) } { ...

  8. springboot多模块打包报错问题根因分析:Unable to find main class

    问题背景: 项目结构为springboot多模块,其中有四个模块bean.utils.user.ems,其中user和ems模块为主程序,包含启动类,其他两个模块为其服务,提供依赖 问题分析: 查看u ...

  9. 蘑菇街大三Java后端暑期实习面经

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识.准备 Java 面试,首选 JavaGuide! 分享一位热心读者分享的实习面经给博客园的小伙伴们看看. 一面 1.自我 ...

  10. LyScript 通过PEB结构解析堆基址

    LyScript中默认并没有提供获取进程堆基址的函数,不过却提供了获取PEB/TEB的函数,以PEB获取为例,可以调用dbg.get_peb_address(local_pid)用户传入当前进程的PI ...