特性 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
所属规范 | Servlet 规范(javax.servlet ) |
Spring MVC 框架(基于 AOP 实现) |
作用范围 | 所有请求(包括静态资源) | 仅拦截 Controller 的请求 |
执行时机 | 在 DispatcherServlet 之前 执行 | 在 Controller 方法前后 执行 |
访问上下文 | 无法直接获取 Spring 的 Bean 或注解信息 | 可以访问 HandlerMethod(如 Controller 方法) |
配置方式 | 通过 web.xml 或 @WebFilter |
通过 WebMvcConfigurer 注册 |
适用场景 | 全局编码、日志、安全过滤 | 权限校验、参数预处理、响应后处理 |
拦截未登录或权限不足的请求。
package com.example.spring_demo01.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !token.equals("Bearer 123456")) {
response.setContentType("application/json");
response.getWriter().write("{\"code\": 401, \"msg\": \"未授权访问\"}");
return false; // 中断请求
}
return true; // 放行请求
}
}
记录每个接口的请求耗时。
package com.example.spring_demo01.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
System.out.println("请求开始: " + request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long endTime = System.currentTimeMillis();
long startTime = (Long) request.getAttribute("startTime");
System.out.println("请求结束,耗时: " + (endTime - startTime) + "ms");
}
}
限制单个 IP 的请求频率。
package com.example.spring_demo01.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
private final ConcurrentHashMap<String, Long> ipAccessTime = new ConcurrentHashMap<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = request.getRemoteAddr();
Long lastAccess = ipAccessTime.get(ip);
long currentTime = System.currentTimeMillis();
if (lastAccess != null && currentTime - lastAccess < TimeUnit.SECONDS.toMillis(1)) {
response.setContentType("application/json");
response.getWriter().write("{\"code\": 429, \"msg\": \"请求过于频繁\"}");
return false;
}
ipAccessTime.put(ip, currentTime);
return true;
}
}
统一处理请求参数(如去除字符串两端的空格)。
package com.example.spring_demo01.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class ParamTrimInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 遍历所有参数并去除空格
request.getParameterMap().forEach((key, values) -> {
String[] trimmedValues = new String[values.length];
for (int i = 0; i < values.length; i++) {
trimmedValues[i] = values[i].trim();
}
request.setAttribute(key, trimmedValues);
});
return true;
}
}
在返回响应前对数据进行加密。
package com.example.spring_demo01.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.util.Base64;
@Component
public class ResponseEncryptInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
String originalData = response.getContentType().startsWith("application/json") ?
(String) request.getAttribute("responseBody") : "";
String encryptedData = Base64.getEncoder().encodeToString(originalData.getBytes());
response.getWriter().write(encryptedData);
}
}
创建配置类实现 WebMvcConfigurer
,添加拦截器并指定路径:
package com.example.spring_demo01.config;
import com.example.spring_demo01.interceptor.AuthInterceptor;
import com.example.spring_demo01.interceptor.LogInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Autowired
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 权限拦截器(拦截 /api/** 路径)
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login"); // 排除登录接口
// 日志拦截器(拦截所有路径)
registry.addInterceptor(logInterceptor)
.addPathPatterns("/**");
// 其他拦截器...
}
}
通过 order()
方法控制拦截器执行顺序(值越小优先级越高):
registry.addInterceptor(authInterceptor)
.order(1) // 先执行权限校验
.addPathPatterns("/api/**");
registry.addInterceptor(logInterceptor)
.order(2) // 后执行日志记录
.addPathPatterns("/**");
@PreAuthorize
)进行权限控制。