你请求我接口,传了什么参数,我返回了什么值给你,全部记下来。防止扯皮

需求:记录每次用户请求Controller的Body参数,

思路:在每个Controller 该当中记录,容易漏记,如果在拦截器里面记的话,可以统一处理

问题:在postHandle 里面记,request.getInputStream() 取出来是空的,放在preHandle里面,就进不到 Controller 里面了。报:I/O error while reading input message; nested exception is java.io.IOException: Stream closed

原因:在拦截器已经读取了请求体中的内容,这时候请求的流中已经没有了数据,就是说HttpServletRequest请求体中的内容一旦读取就不不存在了,所以直接读取是不行的。

方案:对httprequest进行修饰,自定义的包装类来实现

添加 RequestLogFilter

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; @Component
@WebFilter(filterName = "requestLogFilter",urlPatterns = {"/*"},
initParams = {@WebInitParam(name = "ignoredUrl", value = ".css;.js;.jpg;.png;.gif;.ico;.html"),
@WebInitParam(name = "filterPath", value = "/user/login#/user/registerUser")})
public class RequestLogFilter implements OncePerRequestFilter { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
boolean writeLog = true;
String ignoreLog = "swagger;upload;.jpg;.png;.zip;.dat;.ico;.pdf;download"; //可以放配置文件
RequestLogWrapper requestWapper = null;
if (servletRequest instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
for (String item : ignoreLog.split(";")) {
if ("/".equals(request.getRequestURI()) || request.getRequestURI().toLowerCase().contains(item)) {
//有一个包含就不记
writeLog = false;
break;
}
}
if (writeLog) {
requestWapper = new RequestLogWrapper(request);
}
} ResponseLogWrapper responseLogWrapper = new ResponseLogWrapper(servletResponse); //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
// 在chain.doFiler方法中传递新的request对象
if (requestWapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
if (writeLog) {
filterChain.doFilter(requestWapper, responseLogWrapper);
} else {
filterChain.doFilter(requestWapper, servletResponse);
}
} if (writeLog) {
//打印返回响应日志
String result = new String(responseLogWrapper.getResponseData());
ServletOutputStream outputStream = servletResponse.getOutputStream();
outputStream.write(result.getBytes());
outputStream.flush();
outputStream.close(); String queryStr = StrUtil.isEmpty(servletRequest.getQueryString()) ? "" : "?" + servletRequest.getQueryString();
logger.info("Response => {}{} \r\n{}", servletRequest.getRequestURI(), queryStr, result);
}
} @Override
public void destroy() {
logger.info(">>>> RequestLogFilter destroy <<<<");
}
}

添加 RequestLogWapper

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; public class RequestLogWrapper extends HttpServletRequestWrapper { private Logger logger = LoggerFactory.getLogger(this.getClass()); private String requestBody; public String getRequestBody() {
return requestBody;
} public RequestLogWrapper(HttpServletRequest request) throws IOException {
super(request);
requestBody = getBodyString(request);
String queryStr = StrUtil.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString(); String remoteAddr = request.getRemoteAddr();
Enumeration<String> headerNames = request.getHeaderNames();
String headerStr = "";
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
headerStr += StrUtil.format("{}:{};", headerName, headerValue);
}
logger.info("Request => {}{} RemoteAddr => {} \r\n Headers => {}\r\n{}", request.getRequestURI(), queryStr, remoteAddr, headerStr, requestBody);
} @Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
} @Override
public boolean isReady() {
return false;
} @Override
public void setReadListener(ReadListener readListener) {
} @Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
} public String getBodyString(HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}

ResponseLogWrapper

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*; public class ResponseLogWrapper extends HttpServletResponseWrapper { private ByteArrayOutputStream buffer = null;//输出到byte array
private ServletOutputStream out = null;
private PrintWriter writer = null; public ResponseLogWrapper(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();// 真正存储数据的流
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding()));
} /** 重载父类获取outputstream的方法 */
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
} /** 重载父类获取writer的方法 */
@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
return writer;
} /** 重载父类获取flushBuffer的方法 */
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
} @Override
public void reset() {
buffer.reset();
} /** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();
} /** 内部类,对ServletOutputStream进行包装 */
private class WapperedOutputStream extends ServletOutputStream {
private ByteArrayOutputStream bos = null; public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException {
bos = stream;
} @Override
public void write(int b) throws IOException {
bos.write(b);
} @Override
public void write(byte[] b) throws IOException {
bos.write(b, 0, b.length);
} @Override
public boolean isReady() {
return false;
} @Override
public void setWriteListener(WriteListener listener) { }
}
}

参考资源:

https://www.jianshu.com/p/ba2d5101ad90

https://blog.csdn.net/qq_38132283/article/details/107685797

SpringBoot 拦截器 统一日志 记录用户请求返回日志的更多相关文章

  1. SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author l ...

  2. 分享知识-快乐自己:SpringBoot结合使用拦截器(判断是否用户是否已登陆)

    所有的开发之中拦截器一定是一个必须要使用的功能,利用拦截器可以更加有效的实现数据的验证处理,而且最为幸运的是在SpringBoot之中所使用的拦截器与Spring中的拦截器完全一样. 基础拦截器操作: ...

  3. SpringBoot 拦截器获取http请求参数

    SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 目录 SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 获取http请求参数是一种刚需 定义拦截器获取请求 为 ...

  4. Java结合SpringBoot拦截器实现简单的登录认证模块

    Java结合SpringBoot拦截器实现简单的登录认证模块 之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章 ...

  5. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  6. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  7. 分享知识-快乐自己:SpringMVC 结合使用拦截器(判断是否用户是否已登陆)

    基础拦截器操作: 拦截器是一种AOP操作实现,那么在AOP之中用户一定不需要去关注拦截器的存在,用户只需要按照自己已经习惯的处理方式进行代码的编写即可. 首先我们先创建一个自定义的拦截器: packa ...

  8. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

  9. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现. 业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口. 实现功能:写一个拦 ...

  10. SpringBoot拦截器及源码分析

    1.拦截器是什么 java里的拦截器(Interceptor)是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止 ...

随机推荐

  1. 决策树C4.5算法的技术深度剖析、实战解读

    在本篇深入探讨的文章中,我们全面分析了C4.5决策树算法,包括其核心原理.实现流程.实战案例,以及与其他流行决策树算法(如ID3.CART和Random Forests)的比较.文章不仅涵盖了丰富的理 ...

  2. (数据科学学习手札155)基于martin为在线地图构建字体切片服务

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,在之前的一篇文章(基于mart ...

  3. 【开源】int,long long去一边去:高精度大合集!

    加法 \(add\) string add(string s1, string s2) { //时间复杂度 O(log n) string res = ""; int c = 0, ...

  4. lottie 动画在 vue 中的使用

    前言 最近我所负责的项目中,我采用了动画效果,并开始使用 gif 来实现.然而,在实践过程中,我发现 gif 格式的动画在 git 中出现了明显的锯齿感,这让我非常困扰.为了追求更完美的表现效果,我最 ...

  5. Bert-vits2最终版Bert-vits2-2.3云端训练和推理(Colab免费GPU算力平台)

    对于深度学习初学者来说,JupyterNoteBook的脚本运行形式显然更加友好,依托Python语言的跨平台特性,JupyterNoteBook既可以在本地线下环境运行,也可以在线上服务器上运行.G ...

  6. 在macOS中搭建.NET MAUI开发环境

    @ 目录 准备 安装扩展 安装 .NET 安装工作负载 安装 Xcode 命令行工具 调试安卓应用 安装 JDK 安装 Android SDK 安装 Android 模拟器 安装模拟器 安装镜像 创建 ...

  7. 变更(重命名)AD域名称

    文章来自:https://blog.51cto.com/sxleilong/1377731 示例将域名contoso.com重命名为Corp.sxleilong.com 查看当前fsmo的5个角色. ...

  8. JavaFx之从controller关闭stage(十八)

    JavaFx之从controller关闭stage(十八) 开发时,我们需要从controller的button时间中关闭当前,那么你的按钮事件可以这样: @FXML public Button ca ...

  9. String 类和 STL (Standard Template Library)

    目录 一. string 类 1. 构造字符串 2. string类输入 3. 使用字符串 4. 其他string类方法 5. 字符串种类 一. string 类 很多应用程序都需要处理字符串.C语言 ...

  10. GitHub OAuth2的授权指南

    一.OAuth2简介 OAuth 2.0(开放授权 2.0)是一种用于授权的开放标准,旨在允许用户在不提供他们的用户名和密码的情况下,授权第三方应用访问其在另一网站上的信息.它是在网络服务之间安全地共 ...