Spring Boot |SpringBoot的web开发原理


使用SpringBoot进行web开发更加简单:

  1. 在创建SpringBoot应用时,选中我们需要的模块。
  2. SpringBoot已经默认将许多场景配置好了,只需要在配置文件中指定少量的配置就可以运行了。
  3. 剩下的就是自己编写业务代码。

想要将SpringBoot使用的很清楚,就需要搞清楚每一个组件SpringBoot是帮我们怎么配置的,用到了配置类的哪些信息,如何修改等。

  • xxxAutoConfiguration:帮我们给容器中自动配置组件。
  • xxxxProperties:配置类来封装配置文件的内容。

一、SpringBoot对静态资源的映射规则

SpringBoot中关于SpringMVC的相关配置都在WebMvcAutoConfiguration中。

WebMvcAutoConfiguration源码:
public class WebMvcAutoConfiguration {
		...
		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}
			Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
			CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
			if (!registry.hasMappingForPattern("/webjars/**")) {
				customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
						.addResourceLocations("classpath:/META-INF/resources/webjars/")
						.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
			}
			String staticPathPattern = this.mvcProperties.getStaticPathPattern();
			if (!registry.hasMappingForPattern(staticPathPattern)) {
				customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
						.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
						.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
			}
		}
		//配置欢迎页映射
		@Bean
		public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
				FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
			WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
					new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
					this.mvcProperties.getStaticPathPattern());
			welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
			return welcomePageHandlerMapping;
		}
		...
}
--------------------------------------------------------------------------------------------------------------
【关键语句(1):添加资源映射】:addResourceHandler("/webjars/**")

【关键语句(2):缓存时间】:resourceProperties,设置缓存时间
{
	@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
	public class ResourceProperties {在ResourceProperties中可以设置和静态资源有关的参数,缓存时间等.}
}
【关键语句(3):添加资源映射】:addResourceHandler(staticPathPattern)

1.1 /webjars/映射

addResourceHandler("/webjars/**"):所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源。

  • webjars:即以jar包的方式引入静态资源。
  • 可以去 WebJars官网查找对应的jar包版本的Maven形式。
    在这里插入图片描述
    导入jar包后,重启项目,使用http://localhost:8080/webjars/jquery/3.3.1/jquery.js 就可以访问到资源了。

1.2 staticPathPattern映射

addResourceHandler(staticPathPattern):"/**" 访问当前项目的任何资源,都去静态资源的文件夹找映射。

  • staticPathPattern = “/**”;
静态资源的文件夹:
			"classpath:/META-INF/resources/",
			"classpath:/resources/", 
			"classpath:/static/", 
			"classpath:/public/" 
			"/":当前项目的根路径

可以在类路径resources下创建上面的静态资源文件夹,将静态资源放入,以后查找静态资源时,默认就会到这些文件夹中查找。

1.3 欢迎页映射

欢迎页: 静态资源文件夹下的所有index.html页面,被"/**"映射。

即输入localhost:8080/ 默认会去找index页面。

1.4 标题图标映射

标题图标:所有的 **/favicon.ico 都是在静态资源文件下找;

  • 即将标题图标
    在这里插入图片描述

可以手动在application.properties中配置静态资源文件夹的路径:

spring.resources.static-locations=classpath:/mydisk1/,classpath:/mydisk2/

二、使用Thymeleaf模板引擎

2.1 Thymeleaf介绍

模板引擎的思想:页面模板Template中有一些动态的值需要使用到表达式,这些表达式来自我们组装的数据Data。将页面模板Template组装数据Data交给模板引擎Thymeleaf后,模板引擎按照组装数据将页面模板中的表达式解析并填充进而写出。
在这里插入图片描述
Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSPVelocityFreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用。
Spring Boot推荐使用ThymeleafFreemarker等后现代的模板引擎技术;一但导入相关依赖,会自动配置ThymeleafAutoConfigurationFreeMarkerAutoConfiguration

引入Thymeleaf

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

自动渲染

ThymeleafProperties源码:
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

	private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
	//前缀
	public static final String DEFAULT_PREFIX = "classpath:/templates/";
	//后缀
	public static final String DEFAULT_SUFFIX = ".html";

只要我们把HTML页面放在classpath:/templates/thymeleaf就能自动渲染。

2.2 语法规则

首先,导入thymeleaf的名称空间:xmlns:th="http://www.thymeleaf.org"

(1)th:text:改变当前元素里面的文本内容。

  • Controller
    @RequestMapping("/success")
    public String success(Map<String,Object> map){
        map.put("hello","你好");
        return "success";
    }
  • success页面
<body>
    <h1>成功1</h1>
    <div th:text="${hello}">这是欢迎信息</div>
</body>
  • th:text取值成功
    在这里插入图片描述

除了使用th:text,还可以使用th:任意html属性,来替换原生属性的值。可以在 Thymeleaf官网 查看到属性的优先级。

在这里插入图片描述

2.3 表达式

可以在 Thymeleaf官网Standard Expression Syntax一栏查看表达式语法。

  • ${…}:获取变量值
		1)、获取对象的属性、调用方法
		2)、使用内置的基本对象:
			#ctx : the context object.
			#vars: the context variables.
			#vars: the context variables.
			#locale : the context locale.
			#request : (only in Web Contexts) the HttpServletRequest object.
			#response : (only in Web Contexts) the HttpServletResponse object.
			#session : (only in Web Contexts) the HttpSession object.
			#servletContext : (only in Web Contexts) the ServletContext object.
		例:${session.foo}
		3)、内置的一些工具对象:
			#execInfo : information about the template being processed.
			#messages : methods for obtaining externalized messages inside variables expressions, in the
			same way as they would be obtained using #{} syntax.
			#uris : methods for escaping parts of URLs/URIs
			#conversions : methods for executing the configured conversion service (if any).
			#dates : methods for java.util.Date objects: formatting, component extraction, etc.
			#calendars : analogous to #dates , but for java.util.Calendar objects.
			#numbers : methods for formatting numeric objects.
			#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
			#objects : methods for objects in general.
			#bools : methods for boolean evaluation.
			#arrays : methods for arrays.
			#lists : methods for lists.
			#sets : methods for sets.
			#maps : methods for maps.
			#aggregates : methods for creating aggregates on arrays or collections.
			#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
  • *{…}:选择表达式,当前对象/变量取值
*{}和`${}`在功能上是一样,不过有了改进:
使用
	<div th:object="${session.user}">
		<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
		<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
		<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
	</div>
替代↓
	<div>
		<p>Name: <span th:text="${session.userfirstName}">Sebastian</span>.</p>
		<p>Surname: <span th:text="${session.userlastName}">Pepper</span>.</p>
		<p>Nationality: <span th:text="${session.usernationality}">Saturn</span>.</p>
	</div>
  • #{...}:国际化消息

  • @{…}:定义url链接

		@{/order/process(execId=${execId},execType='FAST')}
  • ~{…}:片段引用表达式
		<div th:insert="~{commons :: main}">...</div>

举例:

Controller控制器

    @RequestMapping("/success")
    public String success(Map<String,Object> map){
        map.put("hello","<h1>你好</h1>");
        map.put("users", Arrays.asList("张三","李四","王五"));
        return "success";
    }

前台页面

<body>
    <h1>成功1</h1>
    <!--th:text 将div中的文本内容设置为指定值-->
    <div th:text="${hello}">转义</div>
    <div th:utext="${hello}">不转义</div>
    <hr/>
    <!--th:each每次遍历都会生成当前这个标签-->
    <h4 th:text="${user}" th:each="user:${users}"></h4>
    <hr/>
    <h4>
        <span th:each="user:${users}">[[${user}]]</span>
    </h4>
</body>

在这里插入图片描述

三、SpringMVC自动配置

3.1 SpringMVC auto-configuration

SpringMVC的自动配置可以参照SpringBoot官网第27节。
在这里插入图片描述

Spring Boot 自动配置好了SpringMVC,以下是SpringBoot对SpringMVC的默认配置:WebMvcAutoConfiguration

(1) 包含ContentNegotiatingViewResolverBeanNameViewResolver

  • ①自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染or转发or重定向)
  • ContentNegotiatingViewResolver:组合所有的视图解析器,选择合适的视图解析器。
  • ③定制:我们可以自己给容器中添加一个视图解析器,ContentNegotiatingViewResolver会自动的将其组合进来。

演示定制视图解析器:

    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }

    private static class MyViewResolver implements ViewResolver{

        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }

在这里插入图片描述

(2) 支持提供静态资源,包括对WebJars的支持。上文已经介绍过,这里不做赘述。

(3) 自动注册了 ConverterGenericConverterFormatter 的beans.

  • Converter:类型转换器。
    如果页面带来的数据和Bean中的属性一一对应,SpringMVC就会进行自动封装。但容易出现类型转换问题,如将String文本信息转换为Integer类型。

  • Formatter:格式化器。
    如将页面带来的数据转换为Date类型,2017.12.17===Date。

自己添加的格式化转换器,放在容器中即可。

源码:
public class WebMvcAutoConfiguration {
		...
		@Override
		public void addFormatters(FormatterRegistry registry) {
			ApplicationConversionService.addBeans(registry, this.beanFactory);
		}
		...
}

(4) 配置了消息转换器HttpMessageConverters

  • HttpMessageConverters:消息转换器,SpringMVC用来转换Http请求和响应的。
  • HttpMessageConverters是从容器中确定,底层仍是获取所有的HttpMessageConverter,所以也可以将自己的组件注册到容器(@Bean,@Component)。

(5) MessageCodesResolver:定义错误代码生成规则

(6) ConfigurableWebBindingInitializer:定义错误代码生成规则

可以手动配置一个ConfigurableWebBindingInitializer来替换默认的,添加到容器中。
ConfigurableWebBindingInitializer可以初始化数据绑定器WebDataBinder
请求数据封装为JavaBean时需要用到WebDataBinder(其中涉及类型转换、格式化等)。

除了上面SpringMVC的几种自动配置,web场景还有很多的自动配置在org.springframework.boot.autoconfigure.web包中。

3.2 修改SpringBoot的默认配置

  • SpringBoot在自动配置组件的时候,先看容器中有没有用户自己配置的(@Bean@Component)如果有就用用户配置的;如果没有,才自动配置;如果有些组件可以有多个(如ViewResolver)就会将用户配置的和自己默认的组合起来;
  • 扩展配置:在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置。
  • 定制配置:在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置。

3.3 扩展SpringMVC

实际开发过程中,仅靠SpringBoot的这些自动配置是不够用的。假设现在需要扩展下面两个功能。

        <mvc:view-controller path="/hello" view-name="success"/>
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/hello"/>
                <bean></bean>
            </mvc:interceptor>
        </mvc:interceptors>

编写一个继承了WebMvcConfigurer的配置类(@Configuration),不要标注@EnableWebMvc注解。既保留了所有的自动配置,也能用我们扩展的配置。

@Configuration
public class MyMvcConfig extends WebMvcConfigurer{
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        //功能:浏览器发送 /hello请求,也来到 success
        registry.addViewController("/hello").setViewName("success");
    }
}

扩展原理

  • WebMvcAutoConfiguration是SpringMVC的自动配置类
  • ②在做其他自动配置时会导入@Import(EnableWebMvcConfiguration.class)
    即容器中所有的WebMvcConfigurer会一起起作用。
源码:
public class WebMvcAutoConfiguration {
	...
	@Configuration(proxyBeanMethods = false)
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {....}
	...
}
EnableWebMvcConfiguration 继承了父类DelegatingWebMvcConfiguration
------------------------------------------------------------------------------------------
@Configuration(proxyBeanMethods = false)
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);
					//一个参考实现;将所有的WebMvcConfigurer相关的配合都调用一次,
					//@Override
					//public void addViewControllers(ViewControllerRegistry registry) {
					//	for (WebMvcConfigurer delegate : this.delegates) {
					//		delegate.addViewControllers(registry);
					//	}
					//}
		}
	}
	...
}
  • ③扩展配置类也会被调用。

效果:SpringMVC的自动配置和我们的扩展配置都会起作用

3.4 全面接管SpringMVC

只需要在配置类中添加@EnableWebMvc,就可以全面接管SpringMVC。使所有的SpringMVC的自动配置都失效,所有都是我们自己配置。

为什么使用了@EnableWebMvc后,自动配置就失效了?

源码:
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
-------------------------------------------------------------------
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
	...
}

WebMvcAutoConfiguration类上有一个@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)注解,该注解作用是:当容器中没有WebMvcConfigurationSupport组件的时候,自动配置才生效。

@EnableWebMvc注解导入了DelegatingWebMvcConfiguration组件,而DelegatingWebMvcConfiguration组件继承了WebMvcConfigurationSupport

导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能。

原创文章 475 获赞 1731 访问量 58万+

猜你喜欢

转载自blog.csdn.net/weixin_43691058/article/details/105887875