文章目錄
使用SpringBoot
進行web開發更加簡單:
- 在創建SpringBoot應用時,選中我們需要的模塊。
- SpringBoot已經默認將許多場景配置好了,只需要在配置文件中指定少量的配置就可以運行了。
- 剩下的就是自己編寫業務代碼。
想要將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內容的模板引擎。類似JSP
,Velocity
,FreeMaker
等,它也可以輕易的與Spring MVC等Web框架進行集成作爲Web應用的模板引擎。與其它模板引擎相比,Thymeleaf最大的特點是能夠直接在瀏覽器中打開並正確顯示模板頁面
,而不需要啓動整個Web應用。
Spring Boot推薦使用Thymeleaf
、Freemarker
等後現代的模板引擎技術;一但導入相關依賴,會自動配置ThymeleafAutoConfiguration
、FreeMarkerAutoConfiguration
。
引入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) 包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
。
- ①自動配置了
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) 自動註冊了
Converter
、GenericConverter
、Formatter
的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最基本的功能。