众所周知,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. 23- 数码管动态显示02-转换BCD码

    1.BCD码 数码管动态显示的data[19:0]使用二进制数表示的多位十进制数,不能直接生成段选和片选信号,需要使用BCD码表示的十进制数 BCD码(Binary-Coded Decimal),又称 ...

  2. [转帖]Archery

    Archery SQL 审核查询平台          文档 | FAQ | Releases 功能清单 数据库 查询 审核 执行 备份 数据字典 慢日志 会话管理 账号管理 参数管理 数据归档 My ...

  3. [转帖]OpenSSL版本历史

    OpenSSL版本历史 新闻日志 这是所有 OpenSSL 公告的简洁日志.它们几乎是发布通知. 日期物品 2021 年 7 月 29 日OpenSSL 3.0 的 Beta 2 现已推出.这是一个候 ...

  4. [转帖]Module ngx_http_v2_module

    https://nginx.org/en/docs/http/ngx_http_v2_module.html#:~:text=Sets%20the%20maximum%20number%20of%20 ...

  5. [转帖]Linux:crontab要点整理(表达式,转义,权限管理,日志)

    https://www.jianshu.com/p/fd46652f247e 摘要:Linux,crontab整理crontab的使用,包括cron表达式,设置和删除任务,权限管理,查看日志 cron ...

  6. 如何去掉 node.js 获取MySQL数据产生的RowDataPacket

    如何去掉 node.js 获取MySQL数据产生的RowDataPacket 利用JSON.stringify()把对象转为对象字符串,可去掉RowDataPacket. router.post('/ ...

  7. 解决VS选择运行“在证书存储区中找不到清单签名证书”

     转:https://www.cnblogs.com/190196539/archive/2011/12/03/2272861.html 解决"在证书存储区中找不到清单签名证书" ...

  8. 没有安装vs通过Rider编译Dll

    没安装vs怎样生成dll? 比起VS那庞大的体积和编码效率,我还是更喜欢使用Rider(和VS的神级插件Resharper是同一家公司的产品),那么在没有安装VS的电脑上是否可以在命令行下把C#代码生 ...

  9. Unity字体和画面花屏处理

    字体花屏和相机渲染花屏,这两者的表现有明显的差异. 字体花屏 字体花屏是持续性的,直到组件被刷新,或字体图集被刷新.目前在我们项目中当游戏启动时,就会填充游戏用到的所有字符到贴图中,所以并没有遇到此问 ...

  10. 小白学k8s(3)什么是内网穿透

    什么是内网穿透 内网穿透 工作方式 通信的一方处于内网 通信的双方都处于内网 NAT穿透的原理 UDP内网穿透的实现流程 参考 什么是内网穿透 内网穿透 什么是内网穿透呢? 百度百科的描述 内网穿透, ...