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

需求:记录每次用户请求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. JPA中@ElementCollection使用

    转载请注明出处: 在JPA中,@ElementCollection注解主要用于映射集合属性,例如List.Set或数组等集合属性,以及Map结构的集合属性,每个属性值都有对应的key映射.这个注解可以 ...

  2. Kurator v0.5.0发布,打造统一的多集群备份与存储体验

    本文分享自华为云社区<Kurator v0.5.0正式发布! 打造统一的多集群备份与存储体验>,作者: 云容器大未来 . Kurator 是由华为云推出的开源分布式云原生套件.面向分布式云 ...

  3. string函数部分解释

    ```c1. 运算符重载+.+= 连接字符串= 字符串赋值>.>=.<.<= 字符串比较(例如a < b, aa < ab)==.!= 比较字符串<<. ...

  4. 潜在威胁信息模型(PTIM)-Potential threats Information Modeling

    前言 这只是一位学识浅薄博主的一个突然想法,还望各位专业领域的专家教授轻怼 潜在威胁信息模型 目前的想法是通过全城摄像头建立城市的潜在威胁信息模型,这个潜在威胁可以包括:天气灾害(冰雹.雾霾能见度等) ...

  5. 使用Tensorrt部署,C++ API yolov7_pose模型

    使用Tensorrt部署,C++ API yolov7_pose模型 虽然标题叫部署yolov7_pose模型,但是接下来的教程可以使用Tensorrt部署任何pytorch模型. 仓库地址:http ...

  6. 2020-2021 “Orz Panda” Cup Programming Contest G题(树形结构)

    题目传送门 题目大意:给点一颗包含 \(n\)个节点的无根树,有 \(m\)次询问,每次询问给出两个点 \(u\)和 \(v\),要求计算 \[\sum_{r=1}^{n}d_{r}(u,v) \] ...

  7. 经典卷积神经网络LeNet&AlexNet&VGG

    LeNet LeNet-5是一种经典的卷积神经网络结构,于1998年投入实际使用中.该网络最早应用于手写体字符识别应用中.普遍认为,卷积神经网络的出现开始于LeCun等提出的LeNet网络,可以说Le ...

  8. CSP_J

  9. 在Linux服务器上装jenkins(方式二:rpm包)

    官网下载jenkins https://www.jenkins.io/zh/download/ 上面比较慢,我们从清华大学开源镜像站下载安装包:https://mirrors.tuna.tsinghu ...

  10. 使用dtd定义元素