MVC 拦截器Spring MVC 拦截器对应HandlerInterctor接口该接口位于org.springframework.web.servlet的包中定义了三个方法若要实现该接口就要实现其三个方法前置处理preHandle()方法该方法在执行控制器方法之前执行。返回值为Boolean类型如果返回false表示拦截请求不再向下执行如果返回true表示放行程序继续向下执行如果后面没有其他Interceptor就会执行controller方法。所以此方法可对请求进行判断决定程序是否继续执行或者进行一些初始化操作及对请求进行预处理。后置处理postHandle()方法该方法在执行控制器方法调用之后且在返回ModelAndView之前执行。由于该方法会在DispatcherServlet进行返回视图渲染之前被调用所以此方法多被用于处理返回的视图可通过此方法对请求域中的模型和视图做进一步的修改。已完成处理afterCompletion()方法该方法在执行完控制器之后执行由于是在Controller方法执行完毕后执行该方法所以该方法适合进行一些资源清理记录日志信息等处理操作。可以通过拦截器进行权限检验参数校验记录日志等操作拦截器 (Interceptor) 实现案例拦截器Interceptor依赖于web框架在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制属于面向切面编程AOP的一种运用。就是在service或者一个方法前调用一个方法或者在方法后调用一个方法比如动态代理就是拦截器的简单实现在调用方法前打印出字符串或者做其它业务逻辑的操作。也可以在调用方法后打印出字符串甚至在抛出异常的时候做业务逻辑的操作。由于拦截器是基于web框架的调用因此可以使用Spring的依赖注入DI进行一些业务操作同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。自定义拦截器实现import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.Map; /** * 自定义拦截器 - 实现HandlerInterceptor接口 * 适用于业务相关的预处理和后处理 */ Component public class CustomInterceptor implements HandlerInterceptor { private static final ThreadLocalLong startTimeThreadLocal new ThreadLocal(); /** * 预处理回调方法 - 在控制器执行之前调用 * 返回true表示继续执行false表示中断执行 */ Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 记录请求开始时间 startTimeThreadLocal.set(System.currentTimeMillis()); // 获取请求信息 String requestURI request.getRequestURI(); String method request.getMethod(); String clientIP getClientIP(request); System.out.println(【拦截器-preHandle】请求开始: method requestURI); System.out.println(【拦截器-preHandle】客户端IP: clientIP); // 1. 权限验证示例 if (requiresAuth(requestURI) !isAuthenticated(request)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 未授权访问); return false; // 中断请求 } // 2. 参数预处理示例 MapString, String[] params request.getParameterMap(); if (!params.isEmpty()) { System.out.println(【拦截器-preHandle】请求参数: paramsToString(params)); } // 3. 设置请求属性供控制器使用 request.setAttribute(requestStartTime, System.currentTimeMillis()); return true; // 继续执行后续拦截器和控制器 } /** * 后处理回调方法 - 在控制器执行之后视图渲染之前调用返回ModelAndView之前 */ Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { Long startTime startTimeThreadLocal.get(); if (startTime ! null) { long costTime System.currentTimeMillis() - startTime; System.out.println(【拦截器-postHandle】请求处理耗时: costTime ms); // 可以修改ModelAndView if (modelAndView ! null) { modelAndView.addObject(processTime, costTime); modelAndView.addObject(interceptorMessage, 经过拦截器处理); } } } /** * 完成回调方法 - 在整个请求完成之后调用视图渲染完成后 * 适合进行资源清理 */ Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { Long startTime startTimeThreadLocal.get(); if (startTime ! null) { long totalTime System.currentTimeMillis() - startTime; int status response.getStatus(); System.out.println(【拦截器-afterCompletion】请求完成: request.getRequestURI() 状态: status 总耗时: totalTime ms); if (ex ! null) { System.err.println(【拦截器-afterCompletion】异常信息: ex.getMessage()); } // 清理ThreadLocal防止内存泄漏 startTimeThreadLocal.remove(); } } // 工具方法 private String getClientIP(HttpServletRequest request) { String ip request.getHeader(X-Forwarded-For); if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(Proxy-Client-IP); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getHeader(WL-Proxy-Client-IP); } if (ip null || ip.length() 0 || unknown.equalsIgnoreCase(ip)) { ip request.getRemoteAddr(); } return ip; } private boolean requiresAuth(String uri) { // 需要认证的路径规则 return uri.startsWith(/api/admin) || uri.startsWith(/api/user); } private boolean isAuthenticated(HttpServletRequest request) { // 简单的认证检查 String token request.getHeader(Authorization); return token ! null token.startsWith(Bearer ); } private String paramsToString(MapString, String[] params) { StringBuilder sb new StringBuilder(); for (Map.EntryString, String[] entry : params.entrySet()) { sb.append(entry.getKey()).append() .append(Arrays.toString(entry.getValue())).append(; ); } return sb.toString(); } }拦截器配置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; import java.util.Arrays; import java.util.List; Configuration public class InterceptorConfig implements WebMvcConfigurer { Autowired private CustomInterceptor customInterceptor; // 排除路径 private static final ListString EXCLUDE_PATHS Arrays.asList( /api/public/**, /static/**, /error, /login, /logout ); Override public void addInterceptors(InterceptorRegistry registry) { // 注册自定义拦截器 registry.addInterceptor(customInterceptor) .addPathPatterns(/**) // 拦截所有路径 .excludePathPatterns(EXCLUDE_PATHS); // 排除特定路径 // 可以注册多个拦截器按添加顺序执行 registry.addInterceptor(new LoggingInterceptor()) .addPathPatterns(/api/**) .order(1); // 设置执行顺序数字越小优先级越高 } } /** * 另一个日志拦截器示例 */ class LoggingInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println(【日志拦截器】请求路径: request.getRequestURI()); return true; } }过滤器 (Filter) 实现案例过滤器 (Filter) 依赖于servlet容器。在实现上基于函数回调它可以对几乎所有请求进行过滤但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作获取我们想要获取的数据。比如在Javaweb中对传入的request、response提前过滤掉一些信息或者提前设置一些参数然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是在过滤器中修改字符编码CharacterEncodingFilter、在过滤器中修改HttpServletRequest的一些参数XSSFilter(自定义过滤器)。如过滤低俗文字、危险字符等。自定义过滤器实现import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 自定义过滤器 - 实现Filter接口 * 适用于通用的请求/响应处理 */ Component Order(1) // 执行顺序数字越小优先级越高 public class CustomFilter implements Filter { /** * 初始化方法 */ Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(【过滤器】CustomFilter初始化完成); } /** * 过滤处理方法 */ Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; HttpServletResponse httpResponse (HttpServletResponse) response; long startTime System.currentTimeMillis(); System.out.println(【过滤器-doFilter】请求进入: httpRequest.getRequestURI()); // 1. 设置字符编码 httpRequest.setCharacterEncoding(UTF-8); httpResponse.setCharacterEncoding(UTF-8); httpResponse.setContentType(text/html;charsetUTF-8); // 2. 设置CORS头跨域支持 httpResponse.setHeader(Access-Control-Allow-Origin, *); httpResponse.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); httpResponse.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); // 3. 预处理逻辑 if (isOptionsRequest(httpRequest)) { // 处理预检请求 httpResponse.setStatus(HttpServletResponse.SC_OK); return; } // 4. 请求包装可以修改请求参数 CustomHttpServletRequestWrapper wrappedRequest new CustomHttpServletRequestWrapper(httpRequest); // 5. 响应包装可以修改响应内容 CustomHttpServletResponseWrapper wrappedResponse new CustomHttpServletResponseWrapper(httpResponse); try { // 继续执行过滤器链 chain.doFilter(wrappedRequest, wrappedResponse); // 后处理逻辑 long costTime System.currentTimeMillis() - startTime; System.out.println(【过滤器-doFilter】请求完成: httpRequest.getRequestURI() 耗时: costTime ms); // 可以在这里修改响应内容 byte[] responseData wrappedResponse.getData(); if (responseData.length 0) { // 对响应数据进行处理 String modifiedResponse modifyResponse(new String(responseData)); response.getOutputStream().write(modifiedResponse.getBytes()); } } catch (Exception e) { // 异常处理 System.err.println(【过滤器-doFilter】处理异常: e.getMessage()); httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 服务器内部错误); } } /** * 销毁方法 */ Override public void destroy() { System.out.println(【过滤器】CustomFilter销毁); } // 工具方法 private boolean isOptionsRequest(HttpServletRequest request) { return OPTIONS.equalsIgnoreCase(request.getMethod()); } private String modifyResponse(String originalResponse) { // 简单的响应内容修改示例 return originalResponse.replace(旧内容, 新内容); } } /** * 自定义请求包装器 - 用于修改请求参数 */ class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { public CustomHttpServletRequestWrapper(HttpServletRequest request) { super(request); } Override public String getParameter(String name) { // 可以在这里修改请求参数 String value super.getParameter(name); if (username.equals(name) value ! null) { return value.trim(); // 去除用户名前后空格 } return value; } } /** * 自定义响应包装器 - 用于捕获和修改响应内容 */ class CustomHttpServletResponseWrapper extends HttpServletResponseWrapper { private final CustomServletOutputStream outputStream; private final PrintWriter printWriter; public CustomHttpServletResponseWrapper(HttpServletResponse response) { super(response); this.outputStream new CustomServletOutputStream(); this.printWriter new PrintWriter(outputStream); } Override public ServletOutputStream getOutputStream() { return outputStream; } Override public PrintWriter getWriter() { return printWriter; } public byte[] getData() { try { printWriter.flush(); return outputStream.toByteArray(); } catch (IOException e) { return new byte[0]; } } } /** * 自定义Servlet输出流 */ class CustomServletOutputStream extends ServletOutputStream { private final ByteArrayOutputStream buffer new ByteArrayOutputStream(); Override public void write(int b) { buffer.write(b); } Override public boolean isReady() { return true; } Override public void setWriteListener(WriteListener listener) { // 不需要实现 } public byte[] toByteArray() { return buffer.toByteArray(); } }过滤器配置多种方式使用 Component Order推荐 上面的示例已经使用这种方式使用 FilterRegistrationBean更灵活import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class FilterConfig { Bean public FilterRegistrationBeanCustomFilter customFilterRegistration() { FilterRegistrationBeanCustomFilter registration new FilterRegistrationBean(); registration.setFilter(new CustomFilter()); registration.addUrlPatterns(/*); // 过滤所有请求 registration.setOrder(1); // 执行顺序 registration.setName(customFilter); // 可以设置初始化参数 registration.addInitParameter(param1, value1); return registration; } Bean public FilterRegistrationBeanLoggingFilter loggingFilterRegistration() { FilterRegistrationBeanLoggingFilter registration new FilterRegistrationBean(); registration.setFilter(new LoggingFilter()); registration.addUrlPatterns(/api/*); registration.setOrder(2); return registration; } } /** * 日志过滤器 */ class LoggingFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; System.out.println(【日志过滤器】请求: httpRequest.getMethod() httpRequest.getRequestURI()); chain.doFilter(request, response); } }使用 WebFilter 注解import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; WebFilter( urlPatterns /*, initParams { WebInitParam(name encoding, value UTF-8), WebInitParam(name enableCors, value true) } ) public class AnnotationFilter implements Filter { // 实现同上 }需要在启动类添加ServletComponentScanSpringBootApplication ServletComponentScan // 扫描WebFilter、WebServlet等注解 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }MVC 的Interctor和 Filter 过滤器的区别功能相同Interctor和 Filter 都能实现相应的功能容器不同Interctor构建在 Spring MVC 体系中Filter 构建在 Servlet 容器之上拦截内容不同Filter对所有访问进行增强Interctor仅对MVC访问进行增强使用便利性不同Interctor提供了三个方法分别在不同的时机执行过滤器仅提供一个方法使用场景区别使用拦截器的场景业务逻辑处理权限验证、日志记录、参数预处理需要访问Spring上下文需要注入Spring Bean的业务控制器相关处理只需要对Spring MVC管理的请求进行处理需要修改ModelAndView在视图渲染前修改模型数据使用过滤器的场景通用请求处理字符编码、CORS支持、压缩处理静态资源处理需要对所有请求包括静态资源进行处理底层请求处理需要在DispatcherServlet之前执行的逻辑请求/响应包装需要修改请求参数或响应内容组合使用示例/** * 完整的请求处理链示例 * 过滤器(通用处理) → 拦截器(业务处理) → 控制器 */ // 1. 过滤器处理字符编码、CORS等通用逻辑 Component Order(1) public class GlobalFilter implements Filter { // 处理所有请求的通用逻辑 } // 2. 拦截器处理业务相关的逻辑 Component public class AuthInterceptor implements HandlerInterceptor { // 处理需要认证的业务逻辑 } // 3. 控制器处理具体业务 RestController public class BusinessController { // 业务实现 }过滤器和拦截器执行顺序请求进入 → 过滤器预处理 → Spring MVC 核心处理 → 拦截器预处理 → 控制器执行 → 拦截器后处理 → 拦截器完成处理 → 过滤器后处理 → 响应返回详细执行步骤分解第一阶段过滤器预处理Filter Pre-processing进入过滤器客户端请求首先到达 Servlet 容器执行chain.doFilter(request, response)之前的逻辑对请求进行通用预处理常见操作设置字符编码、添加 CORS 头部、安全检查、请求日志记录此时尚未进入 Spring MVC 框架第二阶段Spring MVC 核心分发Servlet 的service()方法请求进入 Servlet 容器处理流程Spring MVC 的doService()方法Spring MVC 框架开始接管请求Spring MVC 请求分发方法DispatcherServlet根据 URL 映射确定对应的处理器Handler第三阶段拦截器预处理进入拦截器请求正式进入 Spring MVC 的拦截器链执行Controller之前调用preHandle()进行业务相关的预处理常见操作用户认证、权限检查、参数验证、业务日志返回值控制true继续执行后续拦截器和控制器false中断请求直接返回第四阶段控制器执行执行具体的业务逻辑准备模型数据Model确定视图信息View第五阶段拦截器后处理postHandle()方法执行时机控制器逻辑执行完毕但在返回ModelAndView之前能力可以查看和修改控制器返回的ModelAndView对象常见操作添加全局模型数据、记录处理结果、统一响应格式第六阶段拦截器完成处理afterCompletion()方法执行时机控制器已经返回ModelAndView但在过滤器将响应返回给客户端之前特点无论请求成功还是异常都会执行类似finally块常见操作清理 ThreadLocal 资源、记录最终处理状态、性能监控第七阶段过滤器后处理FilterAfter逻辑执行时机服务器端所有逻辑执行完成准备将响应返回给客户端之前常见操作响应压缩、添加安全头部、响应日志记录、编码最后确认多拦截器执行顺序当配置多个拦截器时会形成拦截器链拦截器的运行顺序参照拦截器添加顺序为准即addInterctor的顺序过滤器同理当拦截器中出现对原始处理器的拦截后面的拦截器均终止运行当拦截器运行中断仅运行配置在前面的拦截器afterCompletion流程解析看下图文章转载自程序员Seven原文链接https://www.cnblogs.com/sevencoding/p/19788272体验地址http://www.jnpfsoft.com/?from403