【SpringMVC笔记】 - 12 - 全注解开发
一、全注解开发的核心背景
在 Servlet3.0 规范发布之前,Java Web 开发中必须依赖web.xml文件完成 Servlet、Filter、Listener 等核心组件的配置,以及 SpringMVC 的前端控制器(DispatcherServlet)初始化等关键操作。
Servlet3.0 带来了全新的特性:允许不再编写 web.xml 文件,而是通过 Java 类和注解的方式完成所有 Web 应用的配置,实现 "零 XML" 开发。

Servlet3.0 规范中定义了ServletContainerInitializer接口,Web 服务器启动时会自动扫描并加载该接口的实现类,调用其onStartup方法完成 Servlet 上下文的初始化。
Spring3.1 版本针对该规范提供了适配实现,核心是WebApplicationInitializer接口,

而AbstractAnnotationConfigDispatcherServletInitializer作为该接口的抽象子类,是 SpringMVC 全注解开发的核心入口 ------ 开发者只需继承该类,即可替代web.xml完成 DispatcherServlet 的配置、Spring/SpringMVC 容器初始化、过滤器配置等核心操作。

二、核心配置类:替代 web.xml 的 WebAppInitializer
2.1 类的作用
WebAppInitializer类是全注解开发中替代web.xml的核心,负责:
- 指定 Spring 和 SpringMVC 的配置类;
- 配置 DispatcherServlet 的映射路径(对应
web.xml中<servlet-mapping>); - 配置 Web 应用的过滤器(对应
web.xml中<filter>和<filter-mapping>)。
2.2 完整实现代码
java
package com.zzz.config;
import jakarta.servlet.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* 替代web.xml的核心配置类
* 继承AbstractAnnotationConfigDispatcherServletInitializer后,Web服务器启动时自动初始化Servlet上下文
*/
@Configuration
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/*
* 配置Spring根容器的配置类(非MVC相关,如数据源、事务等)
* 对应web.xml中配置的ContextLoaderListener加载的Spring配置
* 若暂时无Spring核心配置,返回空数组即可
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
/*
* 配置SpringMVC容器的配置类(MVC相关:拦截器、视图解析器、异常处理等)
* 对应web.xml中DispatcherServlet的<init-param>指定的contextConfigLocation
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
/*
* 配置DispatcherServlet的映射规则(url-pattern)
* "/" 表示拦截所有请求(除了JSP),替代web.xml中<servlet-mapping>的<url-pattern>
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/*
* 配置Web应用的过滤器,替代web.xml中的<filter>配置
* 此处配置了字符编码过滤器和RESTful风格的HiddenHttpMethodFilter
*/
@Override
protected Filter[] getServletFilters() {
// 1. 字符编码过滤器:解决请求/响应中文乱码
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceRequestEncoding(true); // 强制请求编码为UTF-8
characterEncodingFilter.setForceResponseEncoding(true); // 强制响应编码为UTF-8
// 2. HiddenHttpMethodFilter:支持PUT/DELETE等请求方法(RESTful)
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
// 返回过滤器数组,多个过滤器按顺序生效
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
2.3 关键方法说明
| 方法名 | 作用 | 对应 web.xml 配置项 |
|---|---|---|
getRootConfigClasses |
指定 Spring 根容器配置类(非 MVC) | <context-param> + ContextLoaderListener |
getServletConfigClasses |
指定 SpringMVC 配置类 | DispatcherServlet 的<init-param> |
getServletMappings |
配置 DispatcherServlet 的映射路径 | <servlet-mapping> |
getServletFilters |
配置过滤器,返回过滤器数组 | <filter> + <filter-mapping> |
三、SpringMVC 核心配置类:SpringMvcConfig
SpringMvcConfig是 SpringMVC 的核心配置类,替代传统的springmvc.xml文件,负责配置视图解析器、组件扫描、注解驱动、静态资源处理、拦截器、异常处理器等 MVC 核心功能。该类需实现WebMvcConfigurer接口,并重写对应方法完成个性化配置。
3.1 基础配置:组件扫描 + 注解驱动
java
package com.zzz.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* SpringMVC核心配置类(替代springmvc.xml)
* 实现WebMvcConfigurer接口:提供MVC相关配置的扩展点
*/
@Configuration // 标记为配置类,替代xml的<beans>标签
@ComponentScan("com.zzz") // 组件扫描:扫描控制器、拦截器等组件,替代<context:component-scan>
@EnableWebMvc // 开启MVC注解驱动:支持@RequestMapping、@ResponseBody等注解,替代<mvc:annotation-driven>
public class SpringMvcConfig implements WebMvcConfigurer {
// 后续配置方法均在此类中扩展
}
3.2 视图解析器配置(Thymeleaf)
SpringMVC 默认不内置 Thymeleaf 支持,需手动配置模板解析器、模板引擎、视图解析器三个 Bean,替代springmvc.xml中 Thymeleaf 的相关配置:
java
// 在SpringMvcConfig类中添加以下Bean配置
// 1. 模板解析器:指定模板位置、编码、后缀等
@Bean
public ITemplateResolver templateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext); // 注入Spring上下文
resolver.setPrefix("/WEB-INF/templates/"); // 模板文件前缀(对应jsp的/WEB-INF/views/)
resolver.setSuffix(".html"); // 模板文件后缀
resolver.setTemplateMode(TemplateMode.HTML); // 模板模式为HTML
resolver.setCharacterEncoding("UTF-8"); // 编码格式
resolver.setCacheable(false); // 开发环境关闭缓存,修改模板后无需重启
return resolver;
}
// 2. 模板引擎:整合模板解析器
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
// 3. 视图解析器:整合模板引擎,返回解析后的视图
@Bean
public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("UTF-8"); // 响应编码
viewResolver.setTemplateEngine(templateEngine); // 关联模板引擎
viewResolver.setOrder(1); // 视图解析器优先级(多个时生效)
return viewResolver;
}
3.3 静态资源处理
传统springmvc.xml中通过<mvc:default-servlet-handler/>开启静态资源处理,全注解方式需重写configureDefaultServletHandling方法:
java
/*
* 开启默认Servlet处理:让SpringMVC接管静态资源(css/js/img等)
* 替代<mvc:default-servlet-handler/>
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 启用默认Servlet处理静态资源
}
3.4 视图控制器(View Controller)
无需编写控制器方法,直接映射请求到视图,替代<mvc:view-controller>:
java
/*
* 视图控制器:简化无业务逻辑的页面跳转
* 替代<mvc:view-controller path="/test" view-name="test"/>
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问/test路径时,直接跳转至test.html视图
registry.addViewController("/test").setViewName("test");
}
3.5 异常处理器配置
替代<mvc:exception-resolvers>,配置全局异常映射,将异常类型映射到指定错误页面:
java
/*
* 配置全局异常处理器:替代<mvc:exception-resolvers>
* 将指定异常类型映射到错误视图,并传递异常对象到页面
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
// 配置异常类型与视图名的映射(key:异常全类名,value:视图名)
Properties exceptionMappings = new Properties();
exceptionMappings.setProperty("java.lang.Exception", "error"); // 所有Exception映射到error.html
resolver.setExceptionMappings(exceptionMappings); // 设置异常映射
resolver.setExceptionAttribute("exception"); // 页面获取异常的变量名(如${exception})
resolvers.add(resolver); // 添加到异常处理器列表
}
对应的错误页面(/WEB-INF/templates/error.html):
html
<!DOCTYPE html>
<html lang="en" xmlns:th = "http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Error</title>
</head>
<body>
<h1>Error</h1>
<hr>
<div th:text="${exception}"></div> <!-- 显示异常信息 -->
</body>
</html>
3.6 拦截器配置
替代<mvc:interceptors>,配置自定义拦截器,并指定拦截 / 排除路径:
java
/*
* 配置拦截器:替代<mvc:interceptors>
* 注册自定义拦截器,指定拦截路径和排除路径
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 创建自定义拦截器实例
MyInterceptor myInterceptor = new MyInterceptor();
// 注册拦截器,并配置路径规则
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/hello"); // 排除/hello路径不拦截
}
自定义拦截器实现(MyInterceptor.java):
java
package com.zzz.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 MyInterceptor implements HandlerInterceptor {
// 控制器方法执行前调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor -> preHandle");
return true; // 返回true:放行;false:拦截
}
// 控制器方法执行后,视图渲染前调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor -> postHandle");
}
// 视图渲染完成后调用(无论是否异常)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor -> afterCompletion");
}
}
四、控制器实现
java
package com.zzz.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 示例控制器:通过@ComponentScan扫描生效
*/
@Controller
public class HelloController {
// 处理/hello的POST请求,返回hello视图(对应/WEB-INF/templates/hello.html)
@RequestMapping(value = "/hello", method = RequestMethod.POST)
public String hello(){
return "hello";
}
}
对应的视图页面(/WEB-INF/templates/hello.html):
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
五、全注解开发的核心优势
- 零 XML 配置 :摆脱
web.xml和springmvc.xml的繁琐配置,所有配置通过 Java 类 + 注解完成,代码更易维护; - 类型安全:配置通过 Java 代码编写,编译期即可发现错误,而非运行期;
- 扩展性强 :
WebMvcConfigurer接口提供了丰富的扩展方法,可灵活配置拦截器、异常处理、静态资源、视图控制器等; - 符合 Servlet3.0 规范:适配现代 Web 容器(Tomcat7+),充分利用 Servlet3.0 的新特性;
- 与 Spring 生态无缝整合:注解驱动的配置方式与 Spring Boot 的自动配置理念一致,为后续学习 Spring Boot 打下基础。
六、注意事项
- 包扫描范围 :
@ComponentScan需指定正确的包路径(如com.zzz),确保控制器、拦截器等组件被扫描到; - Thymeleaf 缓存 :开发环境需关闭模板缓存(
resolver.setCacheable(false)),避免修改模板后需重启服务器; - 拦截器路径规则 :
addPathPatterns("/**")表示拦截所有请求,excludePathPatterns需精准配置排除路径(如静态资源、特定接口); - 字符编码过滤器 :必须设置
ForceRequestEncoding和ForceResponseEncoding为true,否则可能出现中文乱码; - 视图解析器前缀 / 后缀 :
SpringResourceTemplateResolver的prefix需与实际模板文件路径一致(如/WEB-INF/templates/),否则会找不到视图文件。
开发环境需关闭模板缓存(resolver.setCacheable(false)),避免修改模板后需重启服务器; - 拦截器路径规则 :
addPathPatterns("/**")表示拦截所有请求,excludePathPatterns需精准配置排除路径(如静态资源、特定接口); - 字符编码过滤器 :必须设置
ForceRequestEncoding和ForceResponseEncoding为true,否则可能出现中文乱码; - 视图解析器前缀 / 后缀 :
SpringResourceTemplateResolver的prefix需与实际模板文件路径一致(如/WEB-INF/templates/),否则会找不到视图文件。