Spring MVC中配置日志拦截器需实现HandlerInterceptor接口,在preHandle记录请求信息、afterCompletion记录响应与耗时,并通过WebMvcConfigurer注册;注意RequestBody只能读一次,需用ContentCachingRequestWrapper包装,且应脱敏敏感字段、控制日志级别。

在 Spring MVC 中配置拦截器记录请求日志,核心是实现 HandlerInterceptor 接口,并在 preHandle 记录入参、afterCompletion 记录响应结果和耗时,再通过配置类或 XML 注册到拦截器链中。
编写日志拦截器类
创建一个实现 HandlerInterceptor 的类,重点覆盖三个方法:
-
preHandle:在 Controller 方法执行前调用,适合记录请求 URL、HTTP 方法、请求头、查询参数和请求体(注意:request body 只能读取一次,如需记录需用
ContentCachingRequestWrapper包装) -
postHandle:Controller 执行完但视图渲染前,可获取
ModelAndView,一般日志场景中较少使用 - afterCompletion:整个请求结束后调用,适合记录响应状态码、耗时、异常信息(如有)
示例代码片段:
public class RequestLogInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(RequestLogInterceptor.class);
<pre class='brush:java;toolbar:false;'>@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
String uri = request.getRequestURI();
String method = request.getMethod();
String queryString = request.getQueryString();
log.info("→ [{} {}{}] {}", method, uri, queryString != null ? "?" + queryString : "", getRemoteAddr(request));
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long cost = System.currentTimeMillis() - startTime;
int status = response.getStatus();
log.info("← [{}ms {} {}]", cost, status, handler);
if (ex != null) {
log.error("Exception in request", ex);
}
}
private String getRemoteAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}}
立即学习“Java免费学习笔记(深入)”;
注册拦截器到 Spring MVC 配置
Spring Boot 项目推荐使用配置类方式注册:
- 继承
WebMvcConfigurer,重写addInterceptors方法 - 通过
registry.addInterceptor()添加自定义拦截器 - 用
excludePathPatterns排除静态资源(如/static/**、/favicon.ico)避免干扰日志
示例配置类:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
@Configuration
public class WebConfig implements WebMvcConfigurer {
<pre class='brush:java;toolbar:false;'>@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestLogInterceptor())
.excludePathPatterns("/static/**", "/favicon.ico", "/actuator/**");
}}
立即学习“Java免费学习笔记(深入)”;
增强请求体(RequestBody)记录能力
默认 HttpServletRequest 的 input stream 只能读取一次,直接调用 getInputStream() 会导致后续 Controller 无法解析 JSON。解决办法:
- 在
preHandle中将原始 request 包装为ContentCachingRequestWrapper - 该包装类会缓存请求体内容,供多次读取
- 从包装类中提取 byte[],再转成字符串(注意字符编码,推荐 UTF-8)
小提示:仅对需要记录 body 的路径启用(如 POST/PUT),避免性能开销;生产环境慎用,建议配合日志级别控制(如只在 DEBUG 级别下打印 body)。
日志输出优化建议
为避免日志爆炸或敏感信息泄露,建议:
- 对密码、token、身份证号等字段做脱敏处理(如用
***替换) - 限制日志长度,超长内容截断并标记(如
...[TRUNCATED]) - 区分日志级别:请求入口用 INFO,详细参数用 DEBUG,异常用 ERROR
- 使用 MDC(Mapped Diagnostic Context)添加 traceId,便于分布式链路追踪
不复杂但容易忽略。

















