【转载】spring2.x 拦截器实现日志打印,json类型日志打印
需求:日志打印请求参数
错误示例
以下部分错误代码
1、使用拦截器
public class LogInterceptor implements HandlerInterceptor {
private NamedThreadLocal<Long> startTimeThreadLocal=new NamedThreadLocal<Long>("StartTime-EndTime");
private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
Map<String, Object> parames = WebUtil.getParameters(request);
logger.info("servletPath===>{},parameters====>{}",request.getServletPath(),JSON.toJSONString(parames));
logger.info("method==>{}",request.getMethod());
HandlerMethod hand = (HandlerMethod)handler;
logger.info("methodPath====>{}",hand.getMethod());
startTimeThreadLocal.set(System.currentTimeMillis());
return true;
}
/**
* 异常结束
* @param request
* @param response
* @param handler
* @param ex
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
final Long startTime = startTimeThreadLocal.get();
final Long endTime = System.currentTimeMillis();
HandlerMethod hand = (HandlerMethod)handler;
if(ex != null) {
logger.error("methodPath====> {}, start time===> {} used time==> {}", hand.getMethod(), DateUtil.parse(startTime),
DateUtil.parseMins(endTime - startTime));
}
}
2、解析request中的请求参数
public class WebUtil {
public static ThreadLocal<HttpServletRequest> REQUEST = new NamedThreadLocal<HttpServletRequest>(
"ThreadLocalRequest");
public static Map<String, Object> getParameters(ServletRequest request) {
Map<String, Object> params = null;
if (request != null) {
//是html/text
params = WebUtils.getParametersStartingWith(request, null);
//是json
if (params.isEmpty()) {
params = JSON.parseObject(getParametersJson(request), Map.class);
}
}
return params;
}
public static String getParametersJson(ServletRequest request) {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
String body = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} catch (IOException ex) {
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
}
}
}
body = stringBuilder.toString();
return body;
}
}
因为我还写了全局异常类,所以我在全局异常类中处理异常。
配置上就有效果
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
但是出现异常
Caused by: java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:334) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:93) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
at java.io.FilterInputStream.read(FilterInputStream.java:83) ~[na:1.8.0_131]
at java.io.PushbackInputStream.read(PushbackInputStream.java:139) ~[na:1.8.0_131]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver$EmptyBodyCheckingHttpInputMessage.<init>(AbstractMessageConverterMethodArgumentResolver.java:319) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:192) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
... 101 common frames omitted
at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:334) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:93) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
at java.io.FilterInputStream.read(FilterInputStream.java:83) ~[na:1.8.0_131]
at java.io.PushbackInputStream.read(PushbackInputStream.java:139) ~[na:1.8.0_131]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver$EmptyBodyCheckingHttpInputMessage.<init>(AbstractMessageConverterMethodArgumentResolver.java:319) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:192) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
... 101 common frames omitted
3、原因
json类型的参数读取,在执行后面操作时出现异常,由于request是采用流的形式传递数据,请求主体只能被读取一次。
异常解决方法:
https://cloud.tencent.com/developer/ask/76655 ----->不全面
异常解决方法:
https://cloud.tencent.com/developer/ask/76655 ----->不全面
修改
要写:HttpServletRequestWrapper 后面的代码要读取request.getInputStream() 时按照我们的方法读取。
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.*;
/**
* @author xxwy
* on 2018/8/14 0014
*/
public class LogRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = LoggerFactory.getLogger(LogRequestWrapper.class);
private final String body;
public LogRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append(" ");
}
} catch (IOException ex) {
logger.error("获取request流出现异常");
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
logger.error("关闭bufferedReader出现异常");
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
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(){
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
通过 过滤器绑定到我们的springboot容器内
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
ServletRequest requestWrapper = new LogRequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper, response);
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
注册上过滤器
/**
*过滤器
* @return
*/
@Bean
public FilterRegistrationBean<LogFilter> localeFilterRegistration() {
FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<LogFilter>(
new LogFilter());
registration.setName("logFilter");
registration.addUrlPatterns("/*");
//优先级
registration.setOrder(Integer.MAX_VALUE);
return registration;
}
作者:砂糖z
链接:https://www.jianshu.com/p/9b6b194b9706
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://www.jianshu.com/p/9b6b194b9706
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?