20.Spring MVC注解配置

除了传统的 XML 配置文件外,我们还可以通过“注解+配置类”的方式代替 web.xml 和 Spring MVC 的配置文件,来实现对 Spring MVC 的配置工作。本节,我们来详解介绍下如何通过注解来配置 Spring MVC。

1. 使用初始化类代替 web.xml

我们知道,Spring MVC 本质就是对 Servlet 的进一步封装,其核心组件是一个 DispatcherServelt。DispatcherServelt 是 Spring MVC 中请求最先到达的地方,负责请求在其他各个组件间的传递和加工。在此之前,像 DispatcherServlet 这样的 Servlet,我们都是通过 web.xml 文件来进行配置的。

除了 web.xml 外,我们还可以通过初始化类来实现对 DispatcherServlet 的配置。Servlet 容器在启动时,会自动查找类项目路径下实现了 javax.servlet.ServletContainerInitializer 接口的初始化类。若找到,则使用该初始化类代替 web.xml,对 Servlet 容器的上下文进行配置。

Spring 就为 ServletContainerInitializer 接口提供了一个名为 SpringServletContainerInitializer 的实现类,其部分源码如下。

  1. @HandlesTypes({WebApplicationInitializer.class})
  2. public class SpringServletContainerInitializer implements ServletContainerInitializer {
  3. public SpringServletContainerInitializer() {
  4. }
  5.  
  6. public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
  7. ……
  8. }
  9. }


我们看到,SpringServletContainerInitializer 类上使用了一个 @HandlesTypes 注解,该注解能够获取到所有实现了 WebApplicationInitializer 接口的类,然后赋值给 onStartup() 方法的 webAppInitializerClasses 参数。onStartup() 方法会借助 webAppInitializerClasses 参数调用 WebApplicationInitializer 实现类中的方法,以实现对 DispatcherServlet 和 Spring MVC 的配置工作。

Spring 提供了一个 DispatcherServelt 的快速配置类 org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer,它就是 WebApplicationInitializer 的实现类之一 ,其常用方法如下表。

方法 说明
protected abstract Class<?>[] getRootConfigClasses(); 该方法用于设置 Spring 的配置类。
protected abstract Class<?>[] getServletConfigClasses(); 该方法用于设置 Spring MVC 的配置类。
 protected abstract String[] getServletMappings(); 该方法用于指定 DispatcherServelt 的映射规则,即 web.xml 中的 url-pattern。
protected Filter[] getServletFilters()  该方法用于添加各种过滤器(filter)。

 

如果我们自定义的初始化类继承了 AbstractAnnotationConfigDispatcherServletInitializer 并将其部署到 Servlet 容器中,Servvelt 容器会自动加载这个初始化类,并使用它来完成对 DispatcherServlet 和 Spring MVC 的配置工作,示例代码如下。

  1. package net.biancheng.c.config;
  2.  
  3. import org.springframework.web.filter.CharacterEncodingFilter;
  4. import org.springframework.web.filter.HiddenHttpMethodFilter;
  5. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  6.  
  7. import javax.servlet.Filter;
  8.  
  9. public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
  10. // 设置 Spring 的配置类
  11. @Override
  12. protected Class<?>[] getRootConfigClasses() {
  13. return new Class[]{SpringConfig.class};
  14. }
  15.  
  16. // 设置 Spring MVC 的配置类
  17. @Override
  18. protected Class<?>[] getServletConfigClasses() {
  19. return new Class[]{WebConfig.class};
  20. }
  21.  
  22. // 为 DispatcherServlet 指定映射规则,相当于 web.xml 中配置的 url-pattern
  23. @Override
  24. protected String[] getServletMappings() {
  25. return new String[]{"/"};
  26. }
  27.  
  28. //添加过滤器
  29. @Override
  30. protected Filter[] getServletFilters() {
  31. CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
  32. characterEncodingFilter.setEncoding("UTF-8");
  33. characterEncodingFilter.setForceResponseEncoding(true);
  34. HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
  35. return new Filter[]{hiddenHttpMethodFilter};
  36. }
  37. }

2. 使用配置类代替 Spring 的配置文件

我们还可以使用一个标注了 @Configuration 注解的 Java 类(通常被称为“配置类”),来代替 Spring 的配置文件。

在这个配置类中,我们可以定义多个被 @Bean 注解修饰的方法,这些方法与 Spring 配置文件中 <bean> 标签的作用一样,都是可以将指定的 Java 对象以 Bean 的形式交由 Spring 的 IoC 容器管理。  

例如,在 Spring 的 XML 配置文件中定义的一个 Student 类型 Bean,配置形式如下。

  1. <bean id="student" class="net.biancheng.c.entity.Student">
  2. <property name="stuId" value="1001"></property>
  3. <property name="stuName" value="小明"></property>
  4. <property name="age" value="18"></property>
  5. </bean>


上面的 Spring 配置可以通过 SpringConfig 配置类实现,代码如下。

  1. package net.biancheng.c.config;
  2.  
  3. import net.biancheng.c.entity.Student;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6.  
  7. @Configuration
  8. public class SpringConfig {
  9.  
  10. //定义 Bean
  11. @Bean
  12. public Student student(){
  13. Student student = new Student();
  14. student.setStuId("1001");
  15. student.setStuName("小明");
  16. student.setAge(18);
  17. return student;
  18. }
  19. }

 

在配置类中,@Bean 注解修饰的方法说明如下:

  • 方法名相当于 <bean> 标签的 id 属性。
  • 方法的返回值类型就相当于 <bean> 标签的 class 属性。
  • 若该方中存在参数,则该参数对象通常为 Spring 容器中的组件,Spring 会按照类型或参数名称注入该参数对象。

3. 使用配置类代替 Spring MVC 的配置文件

我们还可以使用一个 @Configuration 注解的 Java 类(通常被称为“配置类”),来代替 Spring MVC 的配置文件。

我们知道,Spring MVC 的配置项繁多,例如组件扫描、视图解析器、拦截器、类型转换器、异常解析器、文件上传解析器等。它们在配置类中的配置方式也不尽相同,大致可以被分为 3 种方式:

  • 实现 WebMvcConfigurer 接口
  • 使用 @EnableWebMvc、@ComponentScan 等注解
  • 使用 @Bean 注解

实现 WebMvcConfigurer 接口

我们可以通过一个实现了 WebMvcConfigurer 接口的配置类(标注 @Configuration 的类)对 Spring MVC 的部分组件进行配置,例如拦截器、格式化程序、视图控制器等。

SpringBoot 1.5 及以前是通过继承 WebMvcConfigurerAdapter 抽象类来定制 Spring MVC 配置的,但在 SpringBoot 2.0 后,WebMvcConfigurerAdapter 抽象类就被弃用了,改为实现 WebMvcConfigurer 接口来定制 Spring MvVC 配置。

WebMvcConfigurer 是一个基于 Java  8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以实现对 Spring MVC 的配置。

方法 说明
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {} 将静态文件交给 Servlet 容器(Tomcat)内置的默认 Servlet 处理。
default void addInterceptors(InterceptorRegistry registry) {} 添加 Spring MVC 拦截器,对请求进行拦截处理。
default void addResourceHandlers(ResourceHandlerRegistry registry) {} 添加或修改静态资源(例如图片,js,css 等)映射;

Spring Boot 默认设置的静态资源文件夹就是通过重写该方法设置的。
default void addViewControllers(ViewControllerRegistry registry) {} 主要用于实现无业务逻辑跳转,例如主页跳转,简单的请求重定向,错误页跳转等
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {} 用于配置默认的消息转换器(转换 HTTP 请求和响应)。
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {} 直接添加消息转换器,会关闭默认的消息转换器列表;

实现该方法即可在不关闭默认转换器的起提下,新增一个自定义转换器。
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {} 配置异常解析器。

使用 @EnableWebMvc、@ComponentScan 等注解

我们还可以在配置类中通过 @EnableWebMvc、@ComponentScan 等注解实现对 Spring MVC 的配置。

1) 使用 @ComponentScan 注解开启组件扫描

我们知道,在 Spring 和 Spring MVC 的配置文件中,开启组件扫描功能的配置内容如下。

  • <!--开启组件扫描-->
  • <context:component-scan base-package="net.biancheng.c"></context:component-scan>


使用配置类开启组件扫描功能的代码如下。

  1. @Configuration
  2. //扫描组件
  3. @ComponentScan("net.biancheng.c")
  4. public class WebConfig implements WebMvcConfigurer {
  5. }

2) 使用 @EnableWebMvc 注解开启 Spring MVC 注解驱动

我们可以在 Spring MVC 配置类上使用 @EnableWebMvc 注解代替 <mvc:annotation-driven /> 标签,开启 Spring MVC 的注解驱动,示例代码如下。

  1. @Configuration
  2. //开启组件扫描
  3. @ComponentScan("net.biancheng.c")
  4. //开启 Spring MVC注解驱动
  5. @EnableWebMvc
  6. public class WebConfig implements WebMvcConfigurer {
  7. }

使用 @Bean 注解

我们还可以在配置类中通过 @Bean 注解对 Spring MVC 组件进行配置。

1) 使用 @Bean 注解配置 Thymeleaf 视图解析器

在 Spring MVC 的配置类中,使用 @Bean 注解可以实现对视图解析器的配置。

以 Thymeleaf 视图解析器为例,由于 Spring MVC 的配置文件 Thymeleaf 视图解析器的配置方式如下。

  1. <!-- 配置 Thymeleaf 视图解析器 -->
  2. <bean id="viewResolver"
  3. class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
  4. <property name="order" value="1"/>
  5. <property name="characterEncoding" value="UTF-8"/>
  6. <property name="templateEngine">
  7. <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
  8. <property name="templateResolver">
  9. <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
  10. <!-- 视图前缀 -->
  11. <property name="prefix" value="/WEB-INF/templates/"/>
  12. <!-- 视图后缀 -->
  13. <property name="suffix" value=".html"/>
  14. <property name="templateMode" value="HTML5"/>
  15. <property name="characterEncoding" value="UTF-8"/>
  16. </bean>
  17. </property>
  18. </bean>
  19. </property>
  20. </bean>


从上面的配置内容可以看出,Thymeleaf 视图解析器配置起来还是比较麻烦的,共涉及了 3 种类型的 Bean,它们分别是 ThymeleafViewResolver、SpringTemplateEngine 以及 SpringResourceTemplateResolver。其中 SpringResourceTemplateResolver 的 Bean 是以内部 Bean 的形式,通过 <property> 标签注入到 SpringTemplateEngine 类型的 Bean 中的;而 SpringTemplateEngine 的 Bean 又是以内部 Bean 的形式,通过 <property> 标签注入到 ThymeleafViewResolver 类型的 Bean 中的。

基于以上情况,我们可以在 Spring MVC 的配置类中,分别定义 3 个不同的 @Bean 注解修饰的方法,代码如下。

  1. @Configuration
  2. //扫描组件
  3. @ComponentScan("net.biancheng.c")
  4. //开启MVC注解驱动
  5. @EnableWebMvc
  6. public class WebConfig implements WebMvcConfigurer {
  7. //配置生成模板解析器
  8. @Bean
  9. public ITemplateResolver templateResolver() {
  10. WebApplicationContext webApplicationContext =
  11. ContextLoader.getCurrentWebApplicationContext();
  12. // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过 WebApplicationContext
  13. ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
  14. templateResolver.setPrefix("/WEB-INF/templates/");
  15. templateResolver.setSuffix(".html");
  16. templateResolver.setCharacterEncoding("UTF-8");
  17. templateResolver.setTemplateMode(TemplateMode.HTML);
  18. return templateResolver;
  19. }
  20.  
  21. //生成模板引擎并为模板引擎注入模板解析器
  22. @Bean
  23. public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
  24. SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  25. templateEngine.setTemplateResolver(templateResolver);
  26. return templateEngine;
  27. }
  28.  
  29. //生成视图解析器并为解析器注入模板引擎
  30. @Bean
  31. public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
  32. ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
  33. viewResolver.setCharacterEncoding("UTF-8");
  34. viewResolver.setTemplateEngine(templateEngine);
  35. return viewResolver;
  36. }
  37. }

2) 使用 @Bean 注解配置文件上传解析器

我们知道,想要实现文件上传功能,就需要对 Spring MVC 的文件上传解析器进行配置。

在 Spring MVC 的配置文件中,文件上传解析器的配置形式如下。

  1. <!--配置文件上传解析器-->
  2. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  3. <!--设置上传文件的默认编码格式-->
  4. <property name="defaultEncoding" value="UTF-8"></property>
  5. <!--设置允许上传的最大长度-->
  6. <property name="maxUploadSize" value="10485760"></property>
  7. </bean


在 Spring MVC 的配置类中,我们可以通过 @Bean 注解来对文件上传解析器进行配置,代码如下。

  1. @Configuration
  2. //扫描组件
  3. @ComponentScan("net.biancheng.c")
  4. //开启MVC注解驱动
  5. @EnableWebMvc
  6. public class WebConfig implements WebMvcConfigurer {
  7. //配置文件上传解析器
  8. @Bean
  9. public CommonsMultipartResolver multipartResolver() {
  10. CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
  11. commonsMultipartResolver.setDefaultEncoding("UTF-8");
  12. commonsMultipartResolver.setMaxUploadSize(1024*1024*10);
  13. return commonsMultipartResolver;
  14. }
  15. }

示例

下面,我们通过一个实例,来演示下如何通过全注解方式完成对 Spring MVC 工程的配置,具体步骤如下。

1. 新建一个名为 springmvc-annotation-config-demo 的 Web 工程,将 Spring MVC 和 Commons-upload 的相关依赖引入到该工程中。

2. 在 net.biancheng.c.config 包下,创建一个名为 WebInit 的初始化类代替 web.xml,代码如下。

  1. package net.biancheng.c.config;
  2.  
  3. import org.springframework.web.filter.CharacterEncodingFilter;
  4. import org.springframework.web.filter.HiddenHttpMethodFilter;
  5. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  6.  
  7. import javax.servlet.Filter;
  8.  
  9. //初始化类,代替 web.xml
  10. public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
  11. //设置 Spring 的配置类
  12. @Override
  13. protected Class<?>[] getRootConfigClasses() {
  14. return new Class[]{SpringConfig.class};
  15. }
  16.  
  17. //设置 Spring MVC 的配置类
  18. @Override
  19. protected Class<?>[] getServletConfigClasses() {
  20. return new Class[]{WebConfig.class};
  21. }
  22.  
  23. //为 DispatcherServlet 指定映射规则,相当于 web.xml 中配置的 url-pattern
  24. @Override
  25. protected String[] getServletMappings() {
  26. return new String[]{"/"};
  27. }
  28.  
  29. //添加过滤器
  30. @Override
  31. protected Filter[] getServletFilters() {
  32. CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
  33. characterEncodingFilter.setEncoding("UTF-8");
  34. characterEncodingFilter.setForceResponseEncoding(true);
  35. HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
  36. return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
  37. }
  38.  
  39. }


2. 在 net.biancheng.c.config 包下,新建一个名为 SpringConfig 的配置类代替 Spring 的配置文件,代码如下。 

  1. package net.biancheng.c.config;
  2.  
  3. import net.biancheng.c.entity.User;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6.  
  7. import java.util.Date;
  8. //创建一个配置类,代替 Spring 的配置文件
  9. @Configuration
  10. public class SpringConfig {
  11.  
  12. //定义 User 类型的 Bean,交由 Spring 容器管理
  13. @Bean
  14. public User User(){
  15. User user = new User();
  16. user.setUserName("小明");
  17. user.setBirth(new Date());
  18. user.setHeight(180.0);
  19. return user;
  20. }
  21. }


3.  在 net.biancheng.c.config 包下,新建一个名为 WebConfig 的配置类代替 Spring MVC 的配置文件,代码如下。 

  1. package net.biancheng.c.config;
  2.  
  3. import net.biancheng.c.converter.MyDateConverter;
  4. import net.biancheng.c.interceptor.MyInterceptor;
  5.  
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.ComponentScan;
  8. import org.springframework.context.annotation.Configuration;
  9.  
  10. import org.springframework.format.FormatterRegistry;
  11.  
  12. import org.springframework.web.context.ContextLoader;
  13. import org.springframework.web.context.WebApplicationContext;
  14. import org.springframework.web.multipart.commons.CommonsMultipartResolver;
  15. import org.springframework.web.servlet.HandlerExceptionResolver;
  16. import org.springframework.web.servlet.ViewResolver;
  17. import org.springframework.web.servlet.config.annotation.*;
  18. import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
  19. import org.thymeleaf.spring5.SpringTemplateEngine;
  20. import org.thymeleaf.spring5.view.ThymeleafViewResolver;
  21. import org.thymeleaf.templatemode.TemplateMode;
  22. import org.thymeleaf.templateresolver.ITemplateResolver;
  23. import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
  24.  
  25. import java.util.List;
  26. import java.util.Properties;
  27.  
  28. //配置类代替 Spring MVC 的配置文件
  29. @Configuration
  30. //扫描组件
  31. @ComponentScan("net.biancheng.c")
  32. //开启MVC注解驱动
  33. @EnableWebMvc
  34. public class WebConfig implements WebMvcConfigurer {
  35. //使用默认的servlet处理静态资源
  36. @Override
  37. public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
  38. configurer.enable();
  39. }
  40.  
  41. //配置文件上传解析器
  42. @Bean
  43. public CommonsMultipartResolver multipartResolver() {
  44. CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
  45. commonsMultipartResolver.setDefaultEncoding("UTF-8");
  46. commonsMultipartResolver.setMaxUploadSize(1024 * 1024 * 10);
  47. return commonsMultipartResolver;
  48. }
  49.  
  50. //配置拦截器
  51. @Override
  52. public void addInterceptors(InterceptorRegistry registry) {
  53. MyInterceptor myInterceptor = new MyInterceptor();
  54. registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/");
  55. }
  56.  
  57. //配置视图控制
  58. @Override
  59. public void addViewControllers(ViewControllerRegistry registry) {
  60. registry.addViewController("/").setViewName("user");
  61. }
  62.  
  63. //配置异常映射
  64. @Override
  65. public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
  66. SimpleMappingExceptionResolver exceptionResolver = new
  67. SimpleMappingExceptionResolver();
  68. Properties prop = new Properties();
  69. prop.setProperty("java.lang.Exception", "error");
  70. //设置异常映射
  71. exceptionResolver.setExceptionMappings(prop);
  72. //设置共享异常信息的键
  73. exceptionResolver.setExceptionAttribute("ex");
  74. resolvers.add(exceptionResolver);
  75. }
  76.  
  77. //配置生成模板解析器
  78. @Bean
  79. public ITemplateResolver templateResolver() {
  80. WebApplicationContext webApplicationContext =
  81. ContextLoader.getCurrentWebApplicationContext();
  82. // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过 WebApplicationContext
  83. ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
  84. templateResolver.setPrefix("/WEB-INF/templates/");
  85. templateResolver.setSuffix(".html");
  86. templateResolver.setCharacterEncoding("UTF-8");
  87. templateResolver.setTemplateMode(TemplateMode.HTML);
  88. return templateResolver;
  89. }
  90.  
  91. //生成模板引擎并为模板引擎注入模板解析器
  92. @Bean
  93. public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
  94. SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  95. templateEngine.setTemplateResolver(templateResolver);
  96. return templateEngine;
  97. }
  98.  
  99. //生成视图解析器并未解析器注入模板引擎
  100. @Bean
  101. public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
  102. ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
  103. viewResolver.setCharacterEncoding("UTF-8");
  104. viewResolver.setTemplateEngine(templateEngine);
  105. return viewResolver;
  106. }
  107.  
  108. //添加类型转换器和格式化器
  109. @Override
  110. public void addFormatters(FormatterRegistry registry) {
  111. MyDateConverter myDateConverter = new MyDateConverter();
  112. registry.addConverter(myDateConverter);
  113. }
  114. }


自此,我们就完成了该项目所有的配置工作,接下来我们就通过一些操作来验证下,这些配置是否生效。

4. 在 net.biancheng.c.entity 包下,新建一个名为 User 的类,代码如下。

  1. package net.biancheng.c.entity;
  2.  
  3. import org.springframework.web.multipart.MultipartFile;
  4.  
  5. import java.util.Date;
  6. import java.util.List;
  7.  
  8. /**
  9. * 实体类 User
  10. */
  11. public class User {
  12. private String userName;
  13. private Date birth;
  14. private Double height;
  15. private List<MultipartFile> photos;
  16.  
  17. public String getUserName() {
  18. return userName;
  19. }
  20.  
  21. public void setUserName(String userName) {
  22. this.userName = userName;
  23. }
  24.  
  25. public Date getBirth() {
  26. return birth;
  27. }
  28.  
  29. public void setBirth(Date birth) {
  30. this.birth = birth;
  31. }
  32.  
  33. public Double getHeight() {
  34. return height;
  35. }
  36.  
  37. public void setHeight(Double height) {
  38. this.height = height;
  39. }
  40.  
  41. public List<MultipartFile> getPhotos() {
  42. return photos;
  43. }
  44.  
  45. public void setPhotos(List<MultipartFile> photos) {
  46. this.photos = photos;
  47. }
  48.  
  49. @Override
  50. public String toString() {
  51. return "User{" +
  52. "userName='" + userName + '\'' +
  53. ", birth=" + birth +
  54. ", height=" + height +
  55. ", photos=" + photos +
  56. '}';
  57. }
  58. }


5. 在 net.biancheng.c.converter 包下,创建一个名为 MyDateConverter 的自定义类型转换器,代码如下。

  1. package net.biancheng.c.converter;
  2.  
  3. import org.springframework.core.convert.converter.Converter;
  4.  
  5. import java.text.ParseException;
  6. import java.text.SimpleDateFormat;
  7. import java.util.Date;
  8.  
  9. /**
  10. * 自定义日期转换器
  11. */
  12. public class MyDateConverter implements Converter<String, Date> {
  13. private String datePatten = "yyyy-MM-dd";
  14.  
  15. @Override
  16. public Date convert(String source) {
  17. System.out.println("自定义的类型转换器生效;前端页面传递过来的时间为:" + source);
  18. SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePatten);
  19. try {
  20. return simpleDateFormat.parse(source);
  21. } catch (ParseException e) {
  22. throw new IllegalArgumentException("无效的日期格式,请使用正确的日期格式" + datePatten);
  23. }
  24. }
  25. }

 
6. 在 net.biancheng.c.interceptor 包下,创建一个自定义的拦截器 MyInterceptor,代码如下。

  1. package net.biancheng.c.interceptor;
  2.  
  3. import org.springframework.web.servlet.HandlerInterceptor;
  4. import org.springframework.web.servlet.ModelAndView;
  5.  
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8.  
  9. //自定义拦截器
  10. public class MyInterceptor implements HandlerInterceptor {
  11.  
  12. @Override
  13. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  14. System.out.println("拦截器 MyInterceptor 成功拦截请求:preHandle 执行");
  15. return true;
  16. }
  17.  
  18. @Override
  19. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  20. System.out.println("拦截器 MyInterceptor 成功拦截请求:postHandle 执行");
  21. }
  22.  
  23. @Override
  24. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  25. System.out.println("拦截器 MyInterceptor 成功拦截请求:afterCompletion 执行");
  26. }
  27. }


7. 在 net.biancheng.c.controller 包下,创建一个名为 TestController 的控制器类,代码如下。

  1. package net.biancheng.c.controller;
  2.  
  3. import net.biancheng.c.entity.User;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.ui.Model;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.bind.annotation.ResponseBody;
  10. import org.springframework.web.multipart.MultipartFile;
  11.  
  12. import javax.annotation.Resource;
  13. import javax.servlet.http.HttpServletRequest;
  14. import java.io.File;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. import java.util.UUID;
  18.  
  19. @Controller
  20. public class TestController {
  21. @Resource
  22. private User user;
  23.  
  24. /**
  25. * 测试 Spring 配置是否生效
  26. *
  27. * @return
  28. */
  29. @ResponseBody
  30. @GetMapping("/test")
  31. public User get() {
  32. return user;
  33. }
  34.  
  35. /**
  36. * 测试异常映射是否生效
  37. *
  38. * @return
  39. */
  40. @GetMapping("/testException")
  41. public User get2() {
  42. int a = 10 / 0;
  43. return user;
  44. }
  45.  
  46.  
  47. @RequestMapping(value = "/user", method = RequestMethod.POST)
  48. public String login(User user, HttpServletRequest request, Model model) {
  49. List<String> newFileNameList = new ArrayList<>();
  50. List<MultipartFile> photos = user.getPhotos();
  51. for (MultipartFile photo : photos) {
  52. String realPath = request.getServletContext().getRealPath("/upload/");
  53. System.out.println(realPath);
  54. File fileDir = new File(realPath);
  55. if (!fileDir.exists()) {
  56. fileDir.mkdir();
  57. }
  58. String filename = photo.getOriginalFilename();
  59. System.err.println("正在上传的图片为:" + filename);
  60. String newFileName = UUID.randomUUID() + filename;
  61.  
  62. try {
  63. //将文件保存指定目录
  64. photo.transferTo(new File(realPath + newFileName));
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. }
  68. newFileNameList.add(newFileName);
  69. }
  70. System.out.println(user);
  71. model.addAttribute("type", "success");
  72. model.addAttribute("user", user);
  73. model.addAttribute("filePath", "/upload/");
  74. model.addAttribute("fileNameList", newFileNameList);
  75. return "success";
  76. }
  77. }


8. 在 webapp 下新建一个 js 目录,并将 jquery-3.6.0.min.js 引入该目录下。

9. 在 webapp/WEB-INF 下新建一个 templates 目录,并在该目录下创建一个 user.html,代码如下。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>C语言中文网</title>
  6. </head>
  7. <body>
  8. <form th:action="@{/user}" method="post" enctype="multipart/form-data">
  9. <table>
  10. <tr>
  11. <td>姓名:</td>
  12. <td><input type="text" name="userName" required><br></td>
  13. </tr>
  14.  
  15. <tr>
  16. <td>生日:</td>
  17. <td><input type="date" name="birth" required><br></td>
  18. </tr>
  19. <tr>
  20. <td>身高:</td>
  21. <td><input type="text" name="height" required><br></td>
  22. </tr>
  23. <tr>
  24. <td>照片:</td>
  25. <td><input type="file" name="photos" multiple="multiple" required><br></td>
  26. </tr>
  27. <tr>
  28. <td colspan="2" align="center">
  29. <input type="submit" value="提交">
  30. <input type="reset" value="重置">
  31. </td>
  32. </tr>
  33. </table>
  34. </form>
  35. </body>
  36. </html>


10. 在 webapp/WEB-INF/templates 目录下,新建一个 success.html,代码如下。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>C语言中文网</title>
  6. </head>
  7. <body>
  8. <table>
  9. <tr>
  10. <td>用户名:</td>
  11. <td th:text="${user.getUserName()}"></td>
  12. </tr>
  13. <tr>
  14. <td>生日:</td>
  15. <td th:text="${#dates.format(user.getBirth(),'yyyy-MM-dd')}"></td>
  16. </tr>
  17. <tr>
  18. <td>身高:</td>
  19. <td th:text="${user.getHeight()}"></td>
  20. </tr>
  21. <tr>
  22. <td>照片:</td>
  23. <td th:each="p:${fileNameList}">
  24. <img th:src="${#servletContext.getContextPath()}+${filePath}+${p}" width='200px' height='200px'/><br>
  25. </td>
  26. </tr>
  27. </table>
  28. </body>
  29. </html>


11. 在 webapp/WEB-INF/templates 目录下,新建一个 error.html,代码如下。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>程序发生异常!</h1>
  9. <h1 th:text="${ex}"></h1>
  10. </body>
  11. </html>


12. 将 springmvc-annotation-config-demo 部署到 Tomcat 服务器中,启动 Tomcat,使用浏览器访问“http://localhost:8080/springmvc-annotation-config-demo/”,结果如下图。


图1:注解配置-1


13. 在表单中填写响应的信息,并上传三种图片,如下图。


图2:注解配置-2

14. 点击下方的“提交”按钮,结果如下图。


图3:注解配置-3


15. 使用浏览器访问“http://localhost:8080/springmvc-annotation-config-demo/test”,结果如下。

{"userName":"小明","birth":1649402504930,"height":180.0,"photos":null}


16. 使用浏览器访问“http://localhost:8080/springmvc-annotation-config-demo/testException”,结果如下。

程序发生异常!
java.lang.ArithmeticException: / by zero

17. 使用浏览器访问“http://localhost:8080/springmvc-annotation-config-demo/js/jquery-3.6.0.min.js”,对静态文件 jquery-3.6.0.min.js 进行访问,结果如下。


图4:访问静态文件
posted @ 2022-07-31 14:42  随遇而安==  阅读(287)  评论(0编辑  收藏  举报