经常测试人员过来告诉你接口又又又又报错了, 有时小程序或其它客户端不好抓包,这时不如自己直接在后台日志中直接打印url 和json .但是springboot 的aop无法打印出入参的json ,这时首先想到的就是filter
中打印出入参, 但是会出现流只能读一次的尴尬情况.所以需要加一个wrapper 主要的功能能是让request可重复读. 增加如下2个类就可以实现功能了
新增一个filter
package com.bit.filter;
import com.bit.filter.wrapper.BodyReaderHttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 日志记录的filter
*/
@WebFilter(urlPatterns = "/*", filterName = "logFilter")
@Slf4j
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("--------------logFilter 过滤器初始化------------");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 防止流读取一次后就没有了, 所以需要将流继续写出去
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
printRequest(requestWrapper);
filterChain.doFilter(requestWrapper, servletResponse);
}
private void printRequest(ServletRequest servletRequest) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String uri = request.getRequestURI();
String requestBody = "";
String requestContentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
if (requestContentType != null) {
// 只拦截 json 请求的参数
if (requestContentType.startsWith(MediaType.APPLICATION_JSON_VALUE) || requestContentType.startsWith(MediaType.APPLICATION_XML_VALUE)) {
requestBody = getRequestBody(request);
log.info("请求开始 url ==={}", uri);
log.info("请求开始 参数 ==={}", requestBody);
}
}
}
private String getRequestBody(HttpServletRequest request) {
int contentLength = request.getContentLength();
if (contentLength <= 0) {
return "";
}
try {
return IOUtils.toString(request.getReader());
} catch (IOException e) {
log.error("获取请求体失败", e);
return "";
}
}
@Override
public void destroy() {
System.out.println("--------------过滤器销毁------------");
}
}
BodyReaderHttpServletRequestWrapper
package com.bit.filter.wrapper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
/**
* @author mifei
* @create 2020-06-23 13:16
**/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(Charset.forName("UTF-8"));
}
/**
* 获取请求Body
*
* @param request
* @return
*/
public String getBodyString(final ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = cloneInputStream(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();
}
/**
* Description: 复制输入流
*
* @param inputStream
* @return
*/
public InputStream cloneInputStream(ServletInputStream inputStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return byteArrayInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
参考
https://blog.csdn.net/shangrila_kun/article/details/89308766
springMVC拦截器从Request中获取Json格式并解决request的请求流只能读取一次的问题_菜鸟sdut的博客-CSDN博客_request中的数据获取一次就没有了
https://blog.csdn.net/sdut406/article/details/81369983
解决:Spring boot系统请求/响应参数打印_代码实现_春风化雨-CSDN博客_springboot 打印请求参数
https://blog.csdn.net/jiahao1186/article/details/91870776