目录
1)、所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;
2)、"/**" 访问当前项目的任何资源,都去(静态资源的文件夹,如下)找映射
3)、欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;
4)、所有的 **/favicon.ico 都是在静态资源文件下找;
Ⅴ.ConfigurableWebBindingInitializer
3.全面接管SpringMVC,只要在配置类添加@EnableWebMvc即可
一、Spring Boot与Web开发
1.使用Spring Boot
1.和之前一样创建Spring Boot项目,选择Web模块,XX模块等
2.可自己指定配置
3.自己编写业务代码
2.Spring Boot对静态资源的映射
WebMvcAutoConfiguration.java中的addResourceHandlers方法添加资源映射
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}
①Integer cachePeriod = this.resourceProperties.getCachePeriod();相关的配置文件
//可以设置和静态资源有关的参数,缓存时间等
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
②String staticPathPattern = this.mvcProperties.getStaticPathPattern();
private String staticPathPattern = "/**";
this.resourceProperties.getStaticLocations()
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
③WebMvcAutoConfiguration.java中的welcomePageHandlerMapping方法添加首页映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
resourceProperties.getWelcomePage()
public Resource getWelcomePage() {
for (String location : getStaticWelcomePageLocations()) {
Resource resource = this.resourceLoader.getResource(location);
try {
if (resource.exists()) {
resource.getURL();
return resource;
}
}
catch (Exception ex) {
// Ignore
}
}
return null;
}
getStaticWelcomePageLocations() 静态资源路径下的路径拼接上index.html
private String[] getStaticWelcomePageLocations() {
String[] result = new String[this.staticLocations.length];
for (int i = 0; i < result.length; i++) {
String location = this.staticLocations[i];
if (!location.endsWith("/")) {
location = location + "/";
}
result[i] = location + "index.html";
}
return result;
}
④WebMvcAutoConfiguration.java中的FaviconConfiguration配置喜欢的图标
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
public static class FaviconConfiguration {
private final ResourceProperties resourceProperties;
public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
//所有 **/favicon.ico
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler
.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
this.resourceProperties.getFaviconLocations()也是在静态资源路径上找
List<Resource> getFaviconLocations() {
List<Resource> locations = new ArrayList<Resource>(
this.staticLocations.length + 1);
if (this.resourceLoader != null) {
for (String location : this.staticLocations) {
locations.add(this.resourceLoader.getResource(location));
}
}
locations.add(new ClassPathResource("/"));
return Collections.unmodifiableList(locations);
}
1)、所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;
webjars:以jar包的方式引入静态资源;
webjars官网:WebJars - Web Libraries in Jars
webjars官网中有不同的静态资源jar包,可以用Maven的方式引入
举例: 启动项目可以通过路径访问静态资源。在访问的时候只需要写webjars下面资源的名称即可
localhost:8080/webjars/jquery/3.3.1/jquery.js
<!--引入jquery-webjar-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
2)、"/**" 访问当前项目的任何资源,都去(静态资源的文件夹,如下)找映射
"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根路径
localhost:8080/stestAdd === 去静态资源文件夹里面找stestAdd
3)、欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;
localhost:8080/ 默认找index页面
4)、所有的 **/favicon.ico 都是在静态资源文件下找;
标题栏左侧的图标
二、模板引擎
JSP、Velocity、Freemarker、Thymeleaf
模板引擎的思想:写一个模板,数据填充,通过模板引擎,输出一个带数据的完整页面等等
SpringBoot推荐的Thymeleaf;语法更简单,功能更强大;
1.Thymeleaf模板引擎
Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成 作为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用
Spring Boot推荐使用Thymeleaf、Freemarker等后现代的模板引擎技术;一但导入相关依赖,会自动配置ThymeleafAutoConfiguration、FreeMarkerAutoConfiguration。
1)引入thymeleaf;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 切换thymeleaf版本 在pom.xml文件中 properties属性中进行指定版本切换-->
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!-- 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 -->
<!-- thymeleaf2 layout1-->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
2)Thymeleaf使用
ThymeleafProperties.java文件
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染;
使用:
1、html中导入thymeleaf的名称空间:作用:可使用语法提示
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2、使用thymeleaf语法;
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF‐8">
<title>Title</title>
</head>
<body>
<h1>Hello World</h1>
<!‐‐th:text 将div里面的文本内容设置为 ‐‐>
<div th:text="${hello}">这是显示欢迎信息</div>
</body>
</html>
Controller层,如下:
@RequestMapping("/hello")
public String success(Map<String,Object> map){
map.put("hello","你好");
return "hello";
}
3)语法规则
Thymeleaf官网:Thymeleaf
Thymeleaf官网Docs,可下载pdf文档。
1.th:text;改变当前元素里面的文本内容;
th:任意html属性;来替换原生属性的值
th:属性的优先级,从上到下依次递减
Order Feature Attributes
1 片段包含 th:insert
th:replace
2 遍历 th:each
3 条件判断 th:if
th:unless
th:switch
th:case
4 声明变量 th:object
th:with
5 任意属性修改 th:attr
th:attrprepend
th:attrappend
6 修改指定属性默认值 th:value
th:href
th:src
...
7 修改标签体内容 th:text //转义特殊字符
th:utext //不转义特殊字符
8 声明片段 th:fragment
9 片段移除 th:remove
2.表达式语法
Simple expressions: //表达式语法
Variable Expressions: ${...} //:获取变量值;OGNL;
1)、获取对象的属性、调用方法
2)、使用内置的基本对象:
Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;
Message Expressions: #{...} :获取国际化内容
Link URL Expressions: @{...}:定义URL;
Fragment Expressions: ~{...}:片段引用表达式
Literals //字面量
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations://文本操作
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations://数学运算
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations://布尔运算
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality://比较运算
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators://条件运算(三元运算符)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No-Operation: _
三、SpringMVC自动配置
官网介绍SpringMVC自动配置
Spring MVC auto-configuration
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
Support for serving static resources, including support for WebJars (see below).//静态资源路径和webjars支持
Automatic registration of Converter, GenericConverter, Formatter beans.
Support for HttpMessageConverters (see below).
Automatic registration of MessageCodesResolver (see below).
Static index.html support.//静态首页访问
Custom Favicon support (see below).//favicon.ico图标
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
If you want to keep Spring Boot MVC features, and you just want to add additional MVC
configuration (interceptors, formatters, view controllers etc.) you can add your own
@Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you
wish to provide custom instances of RequestMappingHandlerMapping,
RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a
WebMvcRegistrationsAdapter instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc.
1.SpringMVC自动配置
Ⅰ.自动配置了ViewResolver
SpringBoot对SpringMVC的默认配置:WebMvcAutoConfiguration.java
自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发/重定向))
WebMvcAutoConfiguration.java中的
ContentNegotiatingViewResolver:作用:组合所有的视图解析器的;
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
ContentNegotiatingViewResolver.java解析视图
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("No acceptable view found; returning null");
return null;
}
}
getCandidateViews
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
throws Exception {
List<View> candidateViews = new ArrayList<View>();
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}
if (!CollectionUtils.isEmpty(this.defaultViews)) {
candidateViews.addAll(this.defaultViews);
}
return candidateViews;
}
viewResolvers
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
implements ViewResolver, Ordered, InitializingBean {
......
private List<ViewResolver> viewResolvers;
.....
@Override
protected void initServletContext(ServletContext servletContext) {
Collection<ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), ViewResolver.class).values();
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.size());
for (ViewResolver viewResolver : matchingBeans) {
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
}
else {
for (int i = 0; i < viewResolvers.size(); i++) {
if (matchingBeans.contains(viewResolvers.get(i))) {
continue;
}
String name = viewResolvers.get(i).getClass().getName() + i;
getApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolvers.get(i), name);
}
}
if (this.viewResolvers.isEmpty()) {
logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
"'viewResolvers' property on the ContentNegotiatingViewResolver");
}
AnnotationAwareOrderComparator.sort(this.viewResolvers);
this.cnmFactoryBean.setServletContext(servletContext);
}
BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), ViewResolver.class).values();会把所有的ViewResolver视图解析器组合起来。
如何自己添加视图解析器:我们可以自己给容器中添加一个视图解析器;SpringBoot会自动的将其组合进来;
例子:
@SpringBootApplication
public class SpringBootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestApplication .class, args);
}
@Bean
public ViewResolver myViewReolver(){
return new MyViewResolver();
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
如何查看自己加的视图是否添加进去了呢?
在DispatcherServlet.java中doDispatch方法处打一个断点。因为所有请求一进来会先执行doDispatch方法。
启动Spring Boot项目,随便访问一个请求,查看DispatcherServlet对象中是否有自己添加的ViewResolver。
Ⅱ.Converter、Formatter
Converter:转换器,页面输入值和后台类型之间的转换,类型转换使用Converter
Formatter :格式化器,日期,2018.2.18;
WebMvcAutoConfiguration.java中配置了日期的格式化器
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}
可在application.properties文件中指定日期格式:spring.mvc.date-format=yyyy-MM-dd
WebMvcAutoConfiguration.java把格式化器等添加进容器中addFormatters
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
private <T> Collection<T> getBeansOfType(Class<T> type) {
return this.beanFactory.getBeansOfType(type).values();
}
自己添加的格式化器转换器,我们只需要放在容器中即可
Ⅲ.HttpMessageConverter
HttpMessageConverter:SpringMVC用来转换Http请求和响应的;
WebMvcAutoConfiguration.java HttpMessageConverter
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
.........
// Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not
// on the classpath
@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
......
private final HttpMessageConverters messageConverters;
......
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties,
WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
@Lazy HttpMessageConverters messageConverters,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConverters = messageConverters;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider
.getIfAvailable();
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.addAll(this.messageConverters.getConverters());
}
HttpMessageConverters 是从容器中确定;获取所有的HttpMessageConverter;
自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中 (@Bean,@Component)
Ⅳ.MessageCodesResolver
MessageCodesResolver:定义错误代码生成规则
WebMvcAutoConfiguration.java MessageCodesResolver
@Override
public MessageCodesResolver getMessageCodesResolver() {
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
resolver.setMessageCodeFormatter(
this.mvcProperties.getMessageCodesResolverFormat());
return resolver;
}
return null;
}
getMessageCodesResolverFormat()
public DefaultMessageCodesResolver.Format getMessageCodesResolverFormat() {
return this.messageCodesResolverFormat;
}
this.messageCodesResolverFormat
/**
* Formatting strategy for message codes (PREFIX_ERROR_CODE, POSTFIX_ERROR_CODE).
*/
private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
Format--->error code
public enum Format implements MessageCodeFormatter {
/**
* Prefix the error code at the beginning of the generated message code. e.g.:
* {@code errorCode + "." + object name + "." + field}
*/
PREFIX_ERROR_CODE {
@Override
public String format(String errorCode, String objectName, String field) {
return toDelimitedString(errorCode, objectName, field);
}
},
.......
Ⅴ.ConfigurableWebBindingInitializer
ConfigurableWebBindingInitializer:初始化WebDataBinder;请求数据绑定JavaBean;
WebMvcAutoConfiguration.java ConfigurableWebBindingInitializer
@Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
try {
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}
catch (NoSuchBeanDefinitionException ex) {
return super.getConfigurableWebBindingInitializer();
}
}
this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);从容器中拿ConfigurableWebBindingInitializer
我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)
super.getConfigurableWebBindingInitializer()
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(mvcConversionService());
initializer.setValidator(mvcValidator());
initializer.setMessageCodesResolver(getMessageCodesResolver());
return initializer;
}
ConfigurableWebBindingInitializer
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
if (this.messageCodesResolver != null) {
binder.setMessageCodesResolver(this.messageCodesResolver);
}
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
if (this.validator != null && binder.getTarget() != null &&
this.validator.supports(binder.getTarget().getClass())) {
binder.setValidator(this.validator);
}
if (this.conversionService != null) {
binder.setConversionService(this.conversionService);
}
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
propertyEditorRegistrar.registerCustomEditors(binder);
}
}
}
初始化WebDataBinder;请求数据绑定JavaBean;
不止以上这些自动配置
想了解更多auto-configuration :org.springframework.boot.autoconfigure.web:web的所有自动场景;
2.扩展SpringMVC
① 编写一个配置类(@Configuration),
②是WebMvcConfigurerAdapter类型;
③不能标注@EnableWebMvc;
既保留了SpringBoot所有的自动配置,也能用我们扩展的配置;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hello1 请求来到 hello
registry.addViewController("/hello1").setViewName("hello");
}
}
原理:
1、WebMvcAutoConfiguration是SpringMVC的自动配置类
2、WebMvcAutoConfiguration.java
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
从容器中获取所有的WebMvcConfigurer放到configurers中
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
....
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
.....
this.configurers.addViewControllers(registry);//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
3、容器中所有的WebMvcConfigurer都会一起起作用;
4、我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
3.全面接管SpringMVC,只要在配置类添加@EnableWebMvc即可
SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc即可;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hello1 请求来到 hello
registry.addViewController("/hello1").setViewName("hello");
}
}
证明效果:
不加@EnableWebMvc,启动项目,会在控制台打印出 filter: 'hiddenHttpMethodFilter'等log
加@EnableWebMvc,则不输出该log。
2021-11-06 21:19:17.243 INFO 5836 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
因为WebMvcAutoConfiguration.java 中定义hiddenHttpMethodFilter过滤器
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
...
原理:为什么@EnableWebMvc自动配置就失效了;
1、@EnableWebMvc的核心
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2、DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3、WebMvcAutoConfiguration
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
4、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;导致WebMvcAutoConfiguration 判断条件使自动配置失效。
5、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能
4.如何修改SpringBoot的默认配置
模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如 果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默 认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
Spring Boot入门+深入(一):Spring Boot入门+深入(一)
Spring Boot入门+深入(五):Spring Boot入门+深入(五)-Web开发实例