拓展Spring MVC介绍
Spring Boot 摒弃了传统 xml 配置文件,通过配置类(标注 @Configuration 的类,相当于一个 xml 配置文件)以 JavaBean 形式进行相关配置。
Spring Boot 对 Spring MVC 的自动配置可以满足我们的大部分需求,但是我们也可以通过自定义配置类(标注 @Configuration 的类)并实现 WebMvcConfigurer 接口来定制 Spring MVC 配置,例如拦截器、格式化程序、视图控制器等等。
SpringBoot 1.5 及以前是通过继承 WebMvcConfigurerAdapter 抽象类来定制 Spring MVC 配置的,
但在 SpringBoot 2.0 后,WebMvcConfigurerAdapter 抽象类就被弃用了,改为实现 WebMvcConfigurer
接口来定制 Spring MVC 配置。
WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的,且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以定制 Spring MVC 的配置。
参考博客:地址
官方文档
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
编写一个@Configuration注解类,并且类型
要为WebMVCConfigurer,还不能写@EnableWebMVC注解,我们自己去写一个,我们新建一个包叫config,写一个类MyMvcConfig;
- MyMvcConfig
//要实现WebMvcConfigurer接口
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//浏览器发送/test,就会跳转test页面
registry.addViewController("/test").setViewName("test");
}
}
2.在resources/templates创建一个login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
</body>
</html>
启动Spring Boot发现运行出现错误
cannot resolve MVC view
不能解析MVC的视图
解决方案:
导入thymeleaf依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
声明版本
<properties>
<java.version>1.8</java.version>
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
再次启动主启动类
分析一下拓展SpringMVC的原理
- 找到我们的WebMvcAutoConfiguration,里面有一个类WebMvcAutoConfigurationAdapter
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
- 发现有一个EnableWebMvcConfiguration类,点击查看
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware
- 找到父类DelegatingWebMvcConfiguration
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//从容器中获取所有的webmvcConfiguruers
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
/.../
- 我们可以在这个类中去寻找一个我们刚才设置的viewController当做参考,发现它调用了一个
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
- 我们
点进去addViewControllers()方法
查看
public void addViewControllers(ViewControllerRegistry registry) {
//添加WebMvcConfigurer的每一个委托
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
//将所有的WebMvcConfigurer相关配置一起调用,包括我们自己配置的
}
结论: 所有的WebMvcConfigurer都会起作用,不止Spring自己的配置类,还有我们的配置类也会被调用。
全面接管Spring MVC
官方文档
If you want to take complete control of Spring MVC
you can add your own @Configuration annotated with @EnableWebMvc.
全面接管即:Spring Boot 对SpringMVC的自动配置不需要了,所有都是我们自己去配置,只需要在我们的配置类添加@EnableWebMvc即可生效。
在一些特殊情况下,我们才会全面接管Spring MVC,全面接管之后,Spring Boot 对Spring MVC的自动配置将完全失效。
1.在MyMvcConfig配置类上标注@EnableWebMvc
package com.liang.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebMvc
//要实现WebMvcConfigurer接口
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//浏览器发送/test,就会跳转test页面
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
}
- 启动 Spring Boot,在浏览器地址栏输入“http://localhost:8080/”访问登录页,结果如下图。
- 浏览器地址栏输入“http://localhost:8080/public/hello.html”,结果为下图
我们知道,Spring Boot能够访问位于静态资源文件的静态文件,这是Spring Boot 对Spring MVC 的默认自动配置中定义的,当我们全面接管Spring MVC后,Spring Boot 对Spring MVC的默认配置都会失效,此时再访问静态资源文件夹中的静态资源就会报404错误。
思考:
为什么加了一个注解,自动配置就失效了?
- 点击EnableWebMvc注解
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2.继续点击DelegatingWebMvcConfiguration类,找到父类WebMvcConfigurationSupport
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
- 回到我们的WebMvcAutoConfiguration类
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//这个注解的意思是: 容器中没有这个组件的时候,这个自动配置类生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
从而知道了Spring Boot 全面接管的原理,导入@EnableWebMvc,实质上是导入了WebMvcConfiguration组件让WebMvc自动配置类失效了