目的:使用配置类+注解,代替:web.xml和springMVC的配置文件!
一、创建初始化类,替代web.xml
从 Servlet 3.0 开始,可以不写 web.xml
,改用 Java 类注册 DispatcherServlet,这种方式叫做:基于 Java 的初始化器配置(Java Config)。
最推荐写法:继承 Spring 提供的 AbstractAnnotationConfigDispatcherServletInitializer
/**
* web工程的初始化类,用来代替web.xml
*/
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 执行spring的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
// 设置springMVC的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMvcConfig.class};
}
/**
* 指定dispatherServlet的映射规则,即:url-pattern
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"}; // 拦截所有请求
}
/**
* 注册过滤器
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
// 请求设置编码
characterEncodingFilter.setEncoding("UTF-8");
// 响应设置编码
characterEncodingFilter.setForceResponseEncoding(true);
// 支持RESTful方式提交PUT/DELETE
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
项目目录结构:
对比之前的web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 注册 DispatcherServlet,对浏览器发送的请求统一处理 -->
<servlet>
<!--
这个 <servlet-name> 其实是给 DispatcherServlet 起的一个“别名”
自定义
它与配置文件名有关!
当你不给 DispatcherServlet 指定配置文件路径时(省略 <init-param>),Spring 会默认去加载这个路径:
/WEB-INF/<servlet-name>-servlet.xml
示例:
如果你写成:<servlet-name>abc</servlet-name>
默认加载:/WEB-INF/abc-servlet.xml
但是可以通过 <init-param> 指定配置文件:
-->
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载 SpringMVC 配置文件:/resource/springMVC.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!--
classpath:默认就是当前项目下的resources文件夹下
-->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--
指定当前 Servlet 是否在服务器启动时立即加载(初始化),以及加载的优先级。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
给 Servlet(如 DispatcherServlet)指定它要拦截哪些 URL 请求
设置 springMVC 的核心控制器所能处理的请求的请求路径
/ 所匹配的请求可以是 /login 或.html 或.js 或.css 方式的请求路径
但是 / 不能匹配.jsp 请求路径的请求
/*,匹配所有的请求路径,包括.jsp 请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理编码的过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 请求设置编码 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 响应设置编码 -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 支持RESTful方式提交PUT/DELETE -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
一个servlet,两个filter。
二、各部分配置类
2-1、WebMvcConfig.java
(SpringMVC 配置)
/**
* springMVC的配置类:
* 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler(静态资源处理)
* 5、注解驱动 6、文件上传解析器 7、异常处理 8、拦截器
*/
@Configuration // 配置类的注解
@ComponentScan("com.wsbazinga.mvc.controller") // 扫描组件
@EnableWebMvc // 注解驱动
public class WebMvcConfig {
// Thymeleaf 视图解析器
// 1、Thymeleaf 模板解析器
@Bean
public SpringResourceTemplateResolver templateResolver(){
/*WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());*/
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
// 视图前缀
templateResolver.setPrefix("/WEB-INF/views/");
// 视图后缀
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
// 2、Thymeleaf 模板引擎
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
// Thymeleaf 视图解析器
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1); // 优先级
return resolver;
}
}
对比之前的springMVC.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启注解驱动 -->
<mvc:annotation-driven/>
<!-- 扫描 Controller 包 -->
<context:component-scan base-package="com.wsbazinga.controller"/>
<!-- 视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<!-- 可以有多个视图解析器,用order属性配置优先级 -->
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/views/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateMode" value="HTML5"/>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
1、default-servlet-handler(静态资源处理)配置
它的作用是:
当 SpringMVC 拦截了请求后,如果没有匹配到任何
@RequestMapping
的 Controller,就把请求交给 Tomcat 默认的静态资源处理器(比如处理.css
,.js
,.png
等)。
原本springMVC.xml中的写法:
<!-- 静态文件处理 -->
<mvc:default-servlet-handler/>
你只需要在配置类中实现 WebMvcConfigurer
接口,并重写一个方法:
/**
* springMVC的配置类:
* 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler(静态资源处理)
* 5、注解驱动 6、文件上传解析器 7、异常处理 8、拦截器
*/
@Configuration
@ComponentScan("com.wsbazinga.mvc.controller") // 扫描组件
@EnableWebMvc // 注解驱动
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 相当于 <mvc:default-servlet-handler/>
* 开启对静态资源的默认 servlet 处理
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 启用默认 servlet 处理
}
// Thymeleaf 视图解析器
// ......
}
【注意】:
快捷键: control + o,可以查看实现的接口里面,需要重写的方法,可以通过方法名确定。
2、配置拦截器
原本springMVC.xml中的写法:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!--<bean class="com.wsbazinga.controller.MyInterceptor"></bean>-->
<!--<ref bean="myInterceptor"></ref>-->
<mvc:interceptor>
<mvc:mapping path="/**"/> <!-- 拦截所有请求 -->
<mvc:exclude-mapping path="/"/> <!-- 排除首页 -->
<bean class="com.wsbazinga.controller.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/> <!-- 拦截所有请求 -->
<mvc:exclude-mapping path="/"/> <!-- 排除首页 -->
<bean class="com.wsbazinga.controller.SecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
编写两个拦截器类:
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor ---> preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor ---> postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor ---> afterCompletion");
}
}
@Component
public class SecondInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor ---> preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor ---> postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor ---> afterCompletion");
}
}
在WebMvcConfig配置类中重写addInterceptors方法:
/**
* springMVC的配置类:
* 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler(静态资源处理)
* 5、注解驱动 6、文件上传解析器 7、异常处理 8、拦截器
*/
@Configuration
@ComponentScan("com.wsbazinga.mvc") // 扫描组件
@EnableWebMvc // 注解驱动
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
SecondInterceptor secondInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 第一个拦截器
registry.addInterceptor(new FirstInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/"); // 排除首页
// 第二个拦截器
registry.addInterceptor(secondInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/");
}
// .......其余配置
}
如果希望从 Spring IOC容器中注入拦截器(加了
@Component
的方式),如:SecondInterceptor
必须加上@Component
注解。
3、配置view-controller
原本的springMVC.xml配置文件:
<!-- 配置首页的view-controller -->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:view-controller path="/test_rest" view-name="test_rest"></mvc:view-controller>
<mvc:view-controller path="/file" view-name="file"></mvc:view-controller>
配置类WebMvcConfig中重写如下方法:
// view-controller
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("hello");
}
4、SpringMVC 的 XML 文件上传解析器配置
原本的springMVC.xml配置文件:
<!-- 处理文件上传的 Bean -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/> <!-- 5MB -->
</bean>
这是为了启用对文件上传请求(multipart/form-data)的处理,常用于表单上传文件。
在配置类(如 WebMvcConfig
)中添加一个 @Bean
方法:
@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(5242880); // 设置最大上传大小为 5MB
// 可选配置:编码、缓冲大小等
resolver.setDefaultEncoding("UTF-8");
return resolver;
}
5、SimpleMappingExceptionResolver
配置异常跳转页面
原本的springMVC.xml配置文件:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<property name="exceptionAttribute" value="ex"/>
</bean>
这是一个<bean>,所以,在配置类中声明一个对应的
@Bean
方法。也可以:override
configureHandlerExceptionResolvers()
方法
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("java.lang.ArithmeticException", "error");
simpleMappingExceptionResolver.setExceptionMappings(properties);
// 想要在error.html页面打印异常信息
// 将异常set到请求域中
simpleMappingExceptionResolver.setExceptionAttribute("exception");
resolvers.add(simpleMappingExceptionResolver);
}
三、完整的 WebMvcConfig配置类
完整的 WebMvcConfig配置类代码如下:
/**
* springMVC的配置类:
* 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler(静态资源处理)
* 5、注解驱动 6、文件上传解析器 7、异常处理 8、拦截器
*/
@Configuration
@ComponentScan("com.wsbazinga.mvc") // 扫描组件
@EnableWebMvc // 注解驱动
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
SecondInterceptor secondInterceptor;
/**
* 异常处理
* @param resolvers
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("java.lang.ArithmeticException", "error");
simpleMappingExceptionResolver.setExceptionMappings(properties);
// 想要在error.html页面打印异常信息
// 将异常set到请求域中
simpleMappingExceptionResolver.setExceptionAttribute("exception");
resolvers.add(simpleMappingExceptionResolver);
}
/**
* 文件上传解析器
* @return
*/
@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(5242880); // 设置最大上传大小为 5MB
// 可选配置:编码、缓冲大小等
resolver.setDefaultEncoding("UTF-8");
return resolver;
}
// view-controller
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("hello");
}
/**
* 拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 第一个拦截器
registry.addInterceptor(new FirstInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/"); // 排除首页
// 第二个拦截器
registry.addInterceptor(secondInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/");
}
/**
* 相当于 <mvc:default-servlet-handler/>
* 开启对静态资源的默认 servlet 处理
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 启用默认 servlet 处理
}
// Thymeleaf 视图解析器
// 1、Thymeleaf 模板解析器
@Bean
public SpringResourceTemplateResolver templateResolver(){
/*WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());*/
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
// 视图前缀
templateResolver.setPrefix("/WEB-INF/views/");
// 视图后缀
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
// 2、Thymeleaf 模板引擎
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
// Thymeleaf 视图解析器
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1); // 优先级
return resolver;
}
}