Web请求日志的打印有几种方法:
- AOP切面打印
- HandlerInterceptor
- Filter
以下为Filter的实现方案:
package com.example.common;
import cn.hutool.extra.servlet.ServletUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
@WebFilter(filterName = "webLogFilter", urlPatterns = "/*")
public class WebLogFilter implements Filter {
private final Logger LOGGER = LoggerFactory.getLogger(WebLogFilter.class);
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
long start = System.currentTimeMillis();
HttpServletRequest request = (HttpServletRequest) servletRequest;
RequestWrapper requestWrapper = new RequestWrapper(request);
ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
chain.doFilter(requestWrapper, responseWrapper);
LOGGER.debug("HTTP {} {} {\n\trequest params: {},\n\trequest body: {},\n\tresponse body: {},\n\tclient ip: {},\n\tcost: {}ms\n}",
request.getMethod(), request.getRequestURI(), ServletUtil.getParamMap(request), requestWrapper.getBodyAsString(),
responseWrapper.getContentAsString(), ServletUtil.getClientIP(request), System.currentTimeMillis() - start);
ServletOutputStream outputStream = servletResponse.getOutputStream();
outputStream.write(responseWrapper.getContent());
outputStream.flush();
outputStream.close();
}
public static class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = StreamUtils.copyToByteArray(request.getInputStream());
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
public int read() {
return byteArrayInputStream.read();
}
public boolean isFinished() {
return false;
}
public boolean isReady() {
return false;
}
public void setReadListener(ReadListener listener) {
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
public byte[] getBody() {
return body;
}
public String getBodyAsString() {
return new String(body, StandardCharsets.UTF_8);
}
}
public static class ResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream;
private ServletOutputStream servletOutputStream;
public ResponseWrapper(HttpServletResponse response) {
super(response);
byteArrayOutputStream = new ByteArrayOutputStream();
servletOutputStream = new MyServletOutputStream(byteArrayOutputStream);
}
@Override
public ServletOutputStream getOutputStream() {
return servletOutputStream;
}
@Override
public PrintWriter getWriter() {
return new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, StandardCharsets.UTF_8));
}
@Override
public void flushBuffer() {
if (servletOutputStream != null) {
try {
servletOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public byte[] getContent() {
flushBuffer();
// response中的数据
return byteArrayOutputStream.toByteArray();
}
public String getContentAsString() {
return new String(getContent(), StandardCharsets.UTF_8);
}
class MyServletOutputStream extends ServletOutputStream {
// 把response输出流中的数据写入字节流中
private ByteArrayOutputStream byteArrayOutputStream;
public MyServletOutputStream(ByteArrayOutputStream byteArrayOutputStream) {
this.byteArrayOutputStream = byteArrayOutputStream;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) {
byteArrayOutputStream.write(b);
}
}
}
}
需要添加hutool依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.1</version>
</dependency>