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>

編寫一個繼承了WebMvcConfigurationSupport的配置類(@Configuration),不要標註@EnableWebMvc註解。既保留了所有的自動配置,也能用我們擴展的配置。

@Configuration
public class MyMvcConfig extends WebMvcConfigurationSupport {
    @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最基本的功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章