前言

WebMvcConfigurerAdapter 在 SpringBoot 2.0 + Spring5 中已经被废弃
原因:接口 WebMvcConfigurer 新增了默认方法,不再需要适配器继承;
新版标准写法:直接实现 WebMvcConfigurer 接口,不要继承过期的适配器类。

一、WebMvcConfigurer 常用扩展能力

1、标准配置类模板

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    // 1. 添加自定义拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

    }

    // 2. 静态资源映射
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    }

    // 3. 全局跨域配置
    @Override
    public void addCorsMappings(CorsRegistry registry) {

    }

    // 4. 视图控制器跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

    }
}

2、常用扩展逐一实现

(1)静态资源自定义映射
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 访问 /files/** 映射到服务器 D:/upload/ 真实物理路径
    registry.addResourceHandler("/files/**")
            .addResourceLocations("file:D:/upload/");

    // classpath下静态目录
    registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/");
}
(2)全局CORS跨域
@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
            .allowedOriginPatterns("*")
            .allowedMethods("GET","POST","PUT","DELETE")
            .allowCredentials(true)
            .maxAge(3600);
}
(3)视图跳转(无Controller直接页面转发)
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    // 访问 /login 直接跳转到 login.html
    registry.addViewController("/login").setViewName("login");
}

二、拦截器 HandlerInterceptor

特点

  1. 属于SpringMVC组件,只拦截Controller请求,不拦截静态资源、Servlet、Filter;
  2. 执行时机:Filter → Servlet → Interceptor → Controller
  3. 不能获取原生 HttpServletRequest 的流(可拿到,但无法二次读取);
  4. 适合:登录校验、token校验、权限校验、接口日志、请求耗时统计。

步骤1:自定义拦截器

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {

    // Controller执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        if(token == null || token.isEmpty()){
            response.setStatus(401);
            response.getWriter().write("未登录");
            return false; // 拦截,不放行
        }
        return true; // 放行
    }

    // Controller执行完毕,视图渲染之前
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    // 整个请求结束后(视图渲染之后)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

步骤2:注册到WebMvcConfigurer

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginInterceptor())
            .addPathPatterns("/**")               // 拦截所有接口
            .excludePathPatterns("/login","/static/**","/files/**"); // 放行路径
}

三、过滤器 Filter

特点

  1. Servlet规范组件,在最外层,所有请求都会拦截(静态资源、Servlet、Controller全部拦截);
  2. 执行顺序:多个Filter按照注册顺序链式执行;
  3. 可修改request/response原始报文、编码统一、XSS过滤、全局编码、限流;
  4. 无法注入Spring Bean(需要特殊处理)。

两种注册方式

方式1:@WebFilter + 启动类 @ServletComponentScan

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "encodingFilter", urlPatterns = "/*")
public class EncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        // 统一编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        chain.doFilter(request, response); // 放行
    }
}

启动类开启扫描:

@SpringBootApplication
@ServletComponentScan // 扫描@WebFilter、@WebServlet、@WebListener
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

方式2:JavaConfig 注册FilterRegistrationBean

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<EncodingFilter> encodingFilter(){
        FilterRegistrationBean<EncodingFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new EncodingFilter());
        bean.addUrlPatterns("/*");
        bean.setOrder(1); // 执行优先级,数字越小越先执行
        return bean;
    }
}

四、原生 Servlet 注册

使用场景

对接老旧原生Servlet、第三方SDK、特殊协议处理,现在Web项目极少手写原生Servlet。

方式1:注解 @WebServlet

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("自定义原生Servlet响应");
    }
}

同样需要 @ServletComponentScan

方式2:RegistrationBean注册

@Bean
public ServletRegistrationBean<MyServlet> myServletRegistrationBean(){
    ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>();
    bean.setServlet(new MyServlet());
    bean.addUrlMappings("/myServlet");
    return bean;
}

五、Servlet监听器 Listener

三大常用监听器:

  1. ServletContextListener:应用启动/销毁监听(项目上线、关闭钩子)
  2. HttpSessionListener:会话创建/销毁(在线人数统计)
  3. ServletRequestListener:每次请求创建/销毁

示例:应用启动监听

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class AppListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext context = sce.getServletContext();
        System.out.println("项目Tomcat容器启动完成");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("项目容器关闭");
    }
}

启动类加 @ServletComponentScan 自动生效;
也可以用 ServletListenerRegistrationBean 代码注册。

六、执行完整调用顺序

客户端请求
↓
Filter1.doFilter()
↓
Filter2.doFilter()
↓
原生Servlet / DispatcherServlet(SpringMVC前端控制器)
↓
Interceptor.preHandle()
↓
Controller 执行
↓
Interceptor.postHandle()
↓
视图渲染
↓
Interceptor.afterCompletion()
↓
Filter 后续逻辑返回
↓
响应返回浏览器

七、拦截器Interceptor vs 过滤器Filter 核心区别汇总

对比项 Filter 过滤器 Interceptor 拦截器
归属规范 Servlet规范,Tomcat原生 SpringMVC框架组件
拦截范围 所有请求(静态资源、Servlet、Controller) 仅Controller接口,静态资源不拦截
执行层级 最外层,最先执行 DispatcherServlet内部执行
能否注入Spring Bean 默认不行,需额外包装 可以直接@Autowired注入
使用场景 编码统一、XSS过滤、跨域、流包装、全局请求替换 登录校验、Token校验、权限、接口耗时、日志

更多推荐