Spring Boot入门+深入(四)-Web开发

目录

一、Spring Boot与Web开发

1.使用Spring Boot

2.Spring Boot对静态资源的映射

1)、所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;

 2)、"/**" 访问当前项目的任何资源,都去(静态资源的文件夹,如下)找映射

3)、欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;

4)、所有的 **/favicon.ico 都是在静态资源文件下找;

 二、模板引擎

1.Thymeleaf模板引擎

1)引入thymeleaf;

2)Thymeleaf使用

3)语法规则

三、SpringMVC自动配置

官网介绍SpringMVC自动配置

1.SpringMVC自动配置

Ⅰ.自动配置了ViewResolver

Ⅱ.Converter、Formatter

Ⅲ.HttpMessageConverter

Ⅳ.MessageCodesResolver

Ⅴ.ConfigurableWebBindingInitializer

2.扩展SpringMVC

3.全面接管SpringMVC,只要在配置类添加@EnableWebMvc即可

4.如何修改SpringBoot的默认配置


一、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开发实例

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杀神lwz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值