(四)SpringBoot與Web開發

1.簡介css

使用SpringBoot;html

1.建立SpringBoot應用,選中咱們須要的模塊前端

2.SpringBoot已經默認將這些場景配置好了,只須要在配置文件中指定少許配置就能夠運行起來java

3.本身編寫業務代碼jquery

 

自動配置原理?web

這個場景SpringBoot幫咱們配置了什麼?能不能修改?能修改哪些配置?能不能擴展?spring

 

1 xxxAutoConfiguration:幫咱們給容器中自動配置組件
2 xxxProperties:配置類來封裝配置文件的內容
 //能夠設置和靜態資源有關的參數,緩存時間

 

 

2.SpringBoot對靜態資源的映射規則;express

1 @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
2 public class ResourceProperties implements ResourceLoaderAware {
3   //能夠設置和靜態資源有關的參數,緩存時間等

 

 1 @Override
 2         public void addResourceHandlers(ResourceHandlerRegistry registry) {
 3             if (!this.resourceProperties.isAddMappings()) {
 4                 logger.debug("Default resource handling disabled");
 5                 return;
 6             }
 7             Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
 8             CacheControl cacheControl = this.resourceProperties.getCache()
 9                     .getCachecontrol().toHttpCacheControl();
10             if (!registry.hasMappingForPattern("/webjars/**")) {
11                 customizeResourceHandlerRegistration(registry
12                         .addResourceHandler("/webjars/**")
13                         .addResourceLocations("classpath:/META-INF/resources/webjars/")
14                         .setCachePeriod(getSeconds(cachePeriod))
15                         .setCacheControl(cacheControl));
16             }
17             String staticPathPattern = this.mvcProperties.getStaticPathPattern();
18             if (!registry.hasMappingForPattern(staticPathPattern)) {
19                 customizeResourceHandlerRegistration(
20                         registry.addResourceHandler(staticPathPattern)
21                                 .addResourceLocations(getResourceLocations(
22                                         this.resourceProperties.getStaticLocations()))
23                                 .setCachePeriod(getSeconds(cachePeriod))
24                                 .setCacheControl(cacheControl));
25             }
26         }

1.全部/webjars/**,都去classpath:/META-INF/resources/webjar/找資源;json

  webjars:以jar包的方式引入靜態資源bootstrap

 

localhost:8080/jquery/3.3.1/jquery.js

<!-- 引入jquery-webjar -->在訪問的時候只須要寫webjars下面資源的名稱便可
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.3.1</version>
</dependency>

 

2."/**"訪問當前項目的任何資源,(靜態資源的文件夾)

1 "classpath:/META-INF/resources/", 
2 "classpath:/resources/",
3 "classpath:/static/", 
4 "classpath:/public/" 
5 "/":當前項目的根路徑

localhost:8080/abc ===> 去靜態資源文件夾裏面找abc

3.歡迎頁;靜態資源文件夾下的全部index.html頁面;被"/**"映射;

  localhost:8080/ 找index頁面

4.全部的**/favicon.ico 都是在靜態資源文件夾找

 

3.模板引擎

jsp、Velocity、Thymeleaf

SpringBoot推薦的Thymeleaf

語法更簡單,功能更強大

1.引入thymeleaf

1 <dependency>
2             <groupId>org.springframework.boot</groupId>
3             <artifactId>spring-boot-starter-thymeleaf</artifactId>
4         </dependency>

切換thymeleaf版本

<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
        <!-- 佈局功能的支持程序 thymeleaf3主程序 layout2以上版本 -->
        <!-- thymeleaf2 layout1 -->
        <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>

 

2.Thymeleaf使用&語法

1 @ConfigurationProperties(prefix = "spring.thymeleaf")
2 public class ThymeleafProperties {
3 
4     private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
5 
6     public static final String DEFAULT_PREFIX = "classpath:/templates/";
7 
8     public static final String DEFAULT_SUFFIX = ".html";
 

只要咱們把HTML頁面放在classpath:/templates/,thymeleaf就能自動渲染

使用:

1.導入thymeleaf的名稱空間

1 <html lang="en" xmlns:th="http://www.thymeleaf.org">

2.使用thymeleaf語法

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <h1>成功!</h1>
 9     <!-- th:text 將div裏面的文本內容設置爲 -->
10     <div th:text="${hello}"></div>
11 </body>
12 </html>
 

3.語法規則

1.th:text;改變當前元素裏面的文本內容

  th:任意html屬性;來替換原生屬性的值


2.表達式

 1 Simple expressions:(表達式語法)
 2     Variable Expressions: ${...}:獲取變量值;OGNL;
 3             1)、獲取對象的屬性、調用方法
 4             2)、使用內置的基本對象:
 5                 #ctx : the context object.
 6                 #vars: the context variables.
 7                 #locale : the context locale.
 8                 #request : (only in Web Contexts) the HttpServletRequest object.
 9                 #response : (only in Web Contexts) the HttpServletResponse object.
10                 #session : (only in Web Contexts) the HttpSession object.
11                 #servletContext : (only in Web Contexts) the ServletContext object.
12                 
13                 ${session.foo}
14             3)、內置的一些工具對象:
15 #execInfo : information about the template being processed.
16 #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
17 #uris : methods for escaping parts of URLs/URIs
18 #conversions : methods for executing the configured conversion service (if any).
19 #dates : methods for java.util.Date objects: formatting, component extraction, etc.
20 #calendars : analogous to #dates , but for java.util.Calendar objects.
21 #numbers : methods for formatting numeric objects.
22 #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
23 #objects : methods for objects in general.
24 #bools : methods for boolean evaluation.
25 #arrays : methods for arrays.
26 #lists : methods for lists.
27 #sets : methods for sets.
28 #maps : methods for maps.
29 #aggregates : methods for creating aggregates on arrays or collections.
30 #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
31 
32     Selection Variable Expressions: *{...}:選擇表達式:和${}在功能上是同樣;
33         補充:配合 th:object="${session.user}:
34    <div th:object="${session.user}">
35     <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
36     <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
37     <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
38     </div>
39     
40     Message Expressions: #{...}:獲取國際化內容
41     Link URL Expressions: @{...}:定義URL;
42             @{/order/process(execId=${execId},execType='FAST')}
43     Fragment Expressions: ~{...}:片斷引用表達式
44             <div th:insert="~{commons :: main}">...</div>
45             
46 Literals(字面量)
47       Text literals: 'one text' , 'Another one!' ,…
48       Number literals: 0 , 34 , 3.0 , 12.3 ,…
49       Boolean literals: true , false
50       Null literal: null
51       Literal tokens: one , sometext , main ,…
52 Text operations:(文本操做)
53     String concatenation: +
54     Literal substitutions: |The name is ${name}|
55 Arithmetic operations:(數學運算)
56     Binary operators: + , - , * , / , %
57     Minus sign (unary operator): -
58 Boolean operations:(布爾運算)
59     Binary operators: and , or
60     Boolean negation (unary operator): ! , not
61 Comparisons and equality:(比較運算)
62     Comparators: > , < , >= , <= ( gt , lt , ge , le )
63     Equality operators: == , != ( eq , ne )
64 Conditional operators:條件運算(三元運算符)
65     If-then: (if) ? (then)
66     If-then-else: (if) ? (then) : (else)
67     Default: (value) ?: (defaultvalue)
68 Special tokens:
69     No-Operation: _ 

4.SpringMVC自動配置

1. Spring MVC auto-configuration

Spring Boot自動配置好了SpringMVC

如下是SpringBoot對SpringMVC的默認:

A.Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans

  自動配置了ViewResolver(視圖解析器:根據方法的返回值獲得視圖對象(View),視圖對象決定如何渲染(轉發?重定向))

  ContentNegotiatingViewResolver :組合全部的視圖解析器的;

  如何定製:咱們能夠本身給容器中添加一個視圖解析器;自動的將其組合進來

B.Support for serving static resource,including support for Webjars(see below).靜態資源文件家路徑webjars

C.Static index.html support.靜態首頁訪問

D.Custom Fvicon support(see below).favicon.ico

E.自動註冊了 Converter,GenericConverter,Formatter beans

  Converter:轉換器;public String hello(User user):類型轉換使用Converter

  Formatter:格式化器;2017-12-17===Date;

 

@Bean
@Override
public FormattingConversionService mvcConversionService() {
            WebConversionService conversionService = new WebConversionService(
                    this.mvcProperties.getDateFormat());
            addFormatters(conversionService);
            return conversionService;
}

 

  本身添加的格式化器轉換器,咱們只須要放在容器中便可

 

F.Support for HttpMessageConverters(see below).

  HttpMessageConverter:SpirngMVC用來轉換Http請求和響應的;User---json;

  HttpMessageConverters是從容器中肯定;獲取全部的HttpMessageConverter;

  本身給容器中添加HttpMessageConverter,只須要將本身的組件註冊容器中(@Bean,@Component)

G.MessageCodesResolver

  定義錯誤代碼生成規則

H.ConfigurableWebBindingInitializer

  咱們能夠配置一個ConfigurableWebBindingInitializer來替換默認的;(添加到容器)

1 初始化WebDataBinder;

2 請求數據=====JavaBean;

org.springframework.boot.autoconfigure.web:web的全部自動場景;

2. 擴展SpringMVC

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

編寫一個配置類(@Configuration),是WebMvcConfigurerAdapter類型;不能標註@EnableWebMvc

即保留了全部的自動配置,也能用咱們擴展的配置

 

 1 //使用WebMvcConfigurerAdapter能夠擴展SpringMVC的功能
 2 @Configuration
 3 public class MyMvcConfig extends WebMvcConfigurerAdapter {
 4 
 5     @Override
 6     public void addViewControllers(ViewControllerRegistry registry) {
 7         //super.addViewControllers(registry);
 8         //瀏覽器發送 /young 請求,來到success頁面
 9         registry.addViewController("/young").setViewName("success");
10     }
11 }

 

原理:

  1.WebMvcAutoConfiguration是SpingMVC的自動配置類

  2.在作其餘自動配置時會導入:@Import(EnableWebMvcConfiguration.class)

 1 @Configuration
 2     public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
 3       private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
 4 
 5      //從容器中獲取全部的WebMvcConfigurer
 6       @Autowired(required = false)
 7       public void setConfigurers(List<WebMvcConfigurer> configurers) {
 8           if (!CollectionUtils.isEmpty(configurers)) {
 9               this.configurers.addWebMvcConfigurers(configurers);
10                 //一個參考實現;將全部的WebMvcConfigurer相關配置都來一塊兒調用;  
11                 @Override
12              // public void addViewControllers(ViewControllerRegistry registry) {
13               //    for (WebMvcConfigurer delegate : this.delegates) {
14                //       delegate.addViewControllers(registry);
15                //   }
16               }
17           }
18     }

  3.容器中全部的WebMvcConfigurer 都會一塊兒起做用

  4.咱們的配置類也會被調用

  效果:SpringMVC的自動配置和咱們的擴展配置都會起做用

3. 全面接管SpringMVC

SpringBoot對SpringMVC的自動配置不須要了,全部都是咱們本身配;全部的SpringMVC的自動配置都失效了

咱們須要在配置類中添加@EnableWebMvc便可;

 

 1 //使用WebMvcConfigurerAdapter能夠擴展SpringMVC的功能
 2 @EnableWebMvc
 3 @Configuration
 4 public class MyMvcConfig extends WebMvcConfigurerAdapter {
 5 
 6     @Override
 7     public void addViewControllers(ViewControllerRegistry registry) {
 8         //super.addViewControllers(registry);
 9         //瀏覽器發送 /young 請求,來到success頁面
10         registry.addViewController("/young").setViewName("success");
11     }
12 }

 

原理:

爲何@EnableWebMvc自動配置就失效了?

1.EnableWebMvc的核心

1 @Import(DelegatingWebMvcConfiguration.class)
2 public @interface EnableWebMvc {
3 }

2.

1 @Configuration
2 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3.

 

1 @Configuration
2 @ConditionalOnWebApplication(type = Type.SERVLET)
3 @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
4 //容器中沒有這個組件的時候,這個自動配置類才生效
5 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
6 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
7 @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
8         ValidationAutoConfiguration.class })
9 public class WebMvcAutoConfiguration {

4.@EnableWebMvc將WebMvcConfigurationSupport這個組件導入進來了;

5.導入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

 

5.如何修改SpringBoot的默認配置

模式:

  1.SpringBoot在自動配置不少組件的時候,先看容器中有沒有用戶本身配置的(@Bean、@Component)若是有就用用戶配置的,若是沒有,才自動配置;若是有些組件能夠有多個(ViewResolver)將用戶配置的和本身默認的組合起來;

  2.在SpringBoot中會有很是多的xxxConfigurer幫助咱們進行擴展配置 

  3.在SpringBoot中會有不少的xxxCustomizer幫助咱們進行定製配置

 

6.RestfulCRUD

  1.默認訪問首頁

 1 //使用WebMvcConfigurerAdapter能夠來擴展SpringMVC的功能
 2 //@EnableWebMvc   不要接管SpringMVC
 3 @Configuration
 4 public class MyMvcConfig extends WebMvcConfigurerAdapter {
 5 
 6     @Override
 7     public void addViewControllers(ViewControllerRegistry registry) {
 8        // super.addViewControllers(registry);
 9         //瀏覽器發送 /atguigu 請求來到 success
10         registry.addViewController("/atguigu").setViewName("success");
11     }
12 
13     //全部的WebMvcConfigurerAdapter組件都會一塊兒起做用
14     @Bean //將組件註冊在容器
15     public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
16         WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
17             @Override
18             public void addViewControllers(ViewControllerRegistry registry) {
19                 registry.addViewController("/").setViewName("login");
20                 registry.addViewController("/index.html").setViewName("login");
21             }
22         };
23         return adapter;
24     }
25 }

 

  2.國際化

    1.編寫國際化配置文件

    2.使用ResourceBundleMessageSource管理國際化資源文件

    3.在頁面使用fmt:message取出國家化內容

    

    步驟:

      1.編寫國家化配置文件,抽取頁面須要顯示的國家化消息

 

      2.SpringBoot自動配置好了管理國際化資源文件的組件

 1 @ConfigurationProperties(prefix = "spring.messages")
 2 public class MessageSourceAutoConfiguration {
 3     
 4     /**
 5      * Comma-separated list of basenames (essentially a fully-qualified classpath
 6      * location), each following the ResourceBundle convention with relaxed support for
 7      * slash based locations. If it doesn't contain a package qualifier (such as
 8      * "org.mypackage"), it will be resolved from the classpath root.
 9      */
10     private String basename = "messages";  
11     //咱們的配置文件能夠直接放在類路徑下叫messages.properties;
12     
13     @Bean
14     public MessageSource messageSource() {
15         ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
16         if (StringUtils.hasText(this.basename)) {
17             //設置國際化資源文件的基礎名(去掉語言國家代碼的)
18             messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
19                     StringUtils.trimAllWhitespace(this.basename)));
20         }
21         if (this.encoding != null) {
22             messageSource.setDefaultEncoding(this.encoding.name());
23         }
24         messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
25         messageSource.setCacheSeconds(this.cacheSeconds);
26         messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
27         return messageSource;
28     }

      3.去頁面獲取國際化的值

 

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3     <head>
 4         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 6         <meta name="description" content="">
 7         <meta name="author" content="">
 8         <title>Signin Template for Bootstrap</title>
 9         <!-- Bootstrap core CSS -->
10         <link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
11         <!-- Custom styles for this template -->
12         <link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
13     </head>
14 
15     <body class="text-center">
16         <form class="form-signin" action="dashboard.html">
17             <img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
18                 <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
19             <label class="sr-only" th:text="#{login.username}">Username</label>
20             <input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
21             <label class="sr-only" th:text="#{login.password}">Password</label>
22             <input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
23             <div class="checkbox mb-3">
24                 <label>
25           <input type="checkbox" value="remember-me"/> [[#{login.remember}]]
26         </label>
27             </div>
28             <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
29             <p class="mt-5 mb-3 text-muted">© 2017-2018</p>
30             <a class="btn btn-sm">中文</a>
31             <a class="btn btn-sm">English</a>
32         </form>
33 
34     </body>
35 
36 </html>

效果:根據瀏覽器語言設置的信息切換了國際化

 

原理:

  國際化Locale(區域信息對象);LocaleResolver(獲取區域信息對象)

 1         @Bean
 2         @ConditionalOnMissingBean
 3         @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
 4         public LocaleResolver localeResolver() {
 5             if (this.mvcProperties
 6                     .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
 7                 return new FixedLocaleResolver(this.mvcProperties.getLocale());
 8             }
 9             AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
10             localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
11             return localeResolver;
12         }//默認的就是根據請求頭帶來的區域信息獲取Locale進行國家化

      4.點擊連接切換國際化

 1 /**
 2  * 能夠在鏈接上攜帶區域信息
 3  */
 4 public class MyLocaleResolver implements LocaleResolver {
 5     
 6     @Override
 7     public Locale resolveLocale(HttpServletRequest request) {
 8         String l = request.getParameter("l");
 9         Locale locale = Locale.getDefault();
10         if(!StringUtils.isEmpty(l)){
11             String[] split = l.split("_");
12             locale = new Locale(split[0],split[1]);
13         }
14         return locale;
15     }
16 
17     @Override
18     public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
19 
20     }
21 }
22 
23 
24  @Bean
25 public LocaleResolver localeResolver(){
26     return new MyLocaleResolver();
27    }
28 }

  3.登錄

  開發期間模板引擎頁面修改之後,要實時生效

    1.禁用模板引擎的緩存

1 # 禁用緩存
2 spring.thymeleaf.cache=false

    2.頁面修改完成之後ctrl+F9,從新編譯

    登錄錯誤消息的顯示

1 <!-- 判斷 -->
2 <p style="color: red;" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

    3.鏈接器進行登錄檢查

 1 /**
 2  * 登錄檢查
 3  */
 4 public class LoginHandlerInterceptor implements HandlerInterceptor {
 5 
 6     //目標方法執行以前
 7     @Override
 8     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 9         Object user = request.getSession().getAttribute("loginUser");
10         if(user == null){
11             //未登錄,返回登錄頁面
12             request.setAttribute("msg","沒有權限請先登錄");
13             request.getRequestDispatcher("/index.html").forward(request,response);
14             return false;
15         }else{
16             //已登陸,放行請求
17             return true;
18         }
19     }
20 
21 }

    4.註冊攔截器

//全部的WebMvcConfigurerAdapter組件都會一塊兒其做用
    @Bean//將組件註冊在容器中
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("dashboard");
            }

            //註冊攔截器
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //靜態資源: *.css,*.js
                //SpringBoot已經作好了靜態資源映射
                registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
                        .excludePathPatterns("/index.html","/","/user/login");
            }
        };
        return webMvcConfigurerAdapter;
    }

    5.員工列表-CRUD

      要求:

     1.RestfulCRUD:CRUD知足Rest風格;

     URI:/資源名稱/資源標識  HTTP請求方式區分對資源CRUD操做

  普通CRUD(uri來區分操做) RestfulCRUD:CRUD
查詢 getEmp emp---GET
添加 addEMP?xxx emp---POST
修改 updateEmp?id=xxx&xxx=xxx emp/{id}---PUT
刪除 deleteEmp?id=1 emp/{id}---DELETE

      2.實驗請求架構

  請求URI 請求方式
查詢全部員工 emps GET
查詢某個員工(來到修改頁面) emp/{id} GET
來到添加頁面 emp GET
添加員工 emp POST
來到修改頁面(查出員工進行信息回顯) emp/{id} GET
修改員工 emp PUT
刪除員工 emp/{id} DELETE

      3.員工列表:

      thymeleaf公共頁面元素抽取

 1 一、抽取公共片斷
 2 <div th:fragment="copy">
 3 &copy; 2011 The Good Thymes Virtual Grocery
 4 </div>
 5 
 6 二、引入公共片斷
 7 <div th:insert="~{footer :: copy}"></div>
 8 ~{templatename::selector}:模板名::選擇器
 9 ~{templatename::fragmentname}:模板名::片斷名
10 
11 三、默認效果:
12 insert的公共片斷在div標籤中
13 若是使用th:insert等屬性進行引入,能夠不用寫~{}:
14 行內寫法能夠加上:[[~{}]];[(~{})];

      

三種引入公共片斷的th屬性:

a.th:insert,將公共片斷整個插入到聲明引入的元素中

b.th:replace,將聲明引入的元素替換爲公共片斷

c.th:include,將被引入的片斷的內容包含進這個標籤中

 1 <footer th:fragment="copy">
 2 &copy; 2011 The Good Thymes Virtual Grocery
 3 </footer>
 4 
 5 引入方式
 6 <div th:insert="footer :: copy"></div>
 7 <div th:replace="footer :: copy"></div>
 8 <div th:include="footer :: copy"></div>
 9 
10 效果
11 <div>
12     <footer>
13     &copy; 2011 The Good Thymes Virtual Grocery
14     </footer>
15 </div>
16 
17 <footer>
18 &copy; 2011 The Good Thymes Virtual Grocery
19 </footer>
20 
21 <div>
22 &copy; 2011 The Good Thymes Virtual Grocery
23 </div>

 

7.錯誤處理機制

1)、SpringBoot默認的錯誤處理機制

默認效果:

    1)、返回一個默認的錯誤頁面

瀏覽器發送請求的請求頭:

    2)、若是是其餘客戶端,默認響應一個json數據

    

原理:

  能夠參照ErrorMvcAutoConfiguration;錯誤處理的自動配置;

  給容器中添加了一下組件

  一、DefaultErrorAttributes;

幫咱們在頁面共享信息;
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
        errorAttributes.put("timestamp", new Date());
        addStatus(errorAttributes, requestAttributes);
        addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
        addPath(errorAttributes, requestAttributes);
        return errorAttributes;
}

 

  二、BasicErrorController;處理默認/error請求

1 @Controller
2 @RequestMapping("${server.error.path:${error.path:/error}}")
3 public class BasicErrorController extends AbstractErrorController {

  

 1 @RequestMapping(produces = "text/html")//產生html類型的數據,瀏覽器發送的請求來到這個方法處理
 2     public ModelAndView errorHtml(HttpServletRequest request,
 3             HttpServletResponse response) {
 4         HttpStatus status = getStatus(request);
 5         Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
 6                 request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
 7         response.setStatus(status.value());

      //去哪一個頁面做爲錯誤頁面;包含頁面地址和頁面內容
8 ModelAndView modelAndView = resolveErrorView(request, response, status, model); 9 return (modelAndView != null ? modelAndView : new ModelAndView("error", model)); 10 } 11 12 @RequestMapping 13 @ResponseBody //產生json數據,其餘客戶端來到這個方法處理 14 public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { 15 Map<String, Object> body = getErrorAttributes(request, 16 isIncludeStackTrace(request, MediaType.ALL)); 17 HttpStatus status = getStatus(request); 18 return new ResponseEntity<Map<String, Object>>(body, status); 19 }

 

  三、ErrorPageCustomizer;

1 @Value("${error.path:/error}")
2 private String path = "/error";系統出現錯誤之後來到error請求進行處理;()web.xml註冊的錯誤頁面規則)

  

  四、DefaultErrorViewResolver;

  

 1 @Override
 2     public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
 3             Map<String, Object> model) {
 4         ModelAndView modelAndView = resolve(String.valueOf(status), model);
 5         if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
 6             modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
 7         }
 8         return modelAndView;
 9     }
10 
11     private ModelAndView resolve(String viewName, Map<String, Object> model) {
12                 //默認SpringBoot能夠去找到一個頁面? error/404
13         String errorViewName = "error/" + viewName;
14 
15                 //模板引擎能夠解析這個頁面地址就用模板引擎解析
16         TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
17                 .getProvider(errorViewName, this.applicationContext);
18         if (provider != null) {
19                         //模板引擎可用的狀況下返回到errorViewName指定的視圖地址
20             return new ModelAndView(errorViewName, model);
21         }
22                 模板引擎不能夠用,就在靜態資源文件夾下找errorViewName對應的頁面    error/404
23         return resolveResource(errorViewName, model);
24     }

 

  步驟:

    一旦系統出現4xx或者5xx之類的錯誤:ErrorPageCustomizer就會生效(定製錯誤的響應規則);就會來到/error請求;就會被BasicErrorController處理;

    1)、響應頁面;去哪一個頁面是由DefaultErrorViewResolver解析獲得的

 1 protected ModelAndView resolveErrorView(HttpServletRequest request,
 2             HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
 3                 //全部的ErrorViewResolver獲得ModelAndView
 4         for (ErrorViewResolver resolver : this.errorViewResolvers) {
 5             ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
 6             if (modelAndView != null) {
 7                 return modelAndView;
 8             }
 9         }
10         return null;
11     }

 

 

2)、如何定製錯誤響應:

  1)、如何定製錯誤的頁面;

      1)、有模板引擎的狀況下;error/狀態碼;【將錯誤頁面命名爲 錯誤狀態碼.html放在模板引發文件夾裏面的error文件下】,發生此狀態碼的錯誤就會來到對應的頁面;

        咱們可使用4xx和5xx做爲錯誤頁面的文件夾名來匹配這種類型的全部錯誤,精確優先(優先尋找精確的狀態碼.html)

        頁面能獲取的信息;

        timestamp:時間戳

          status:狀態碼

          error:錯誤提示

          exception:異常對象

          message:異常消息

          errors:JSR303數據

      2)、沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態資源文件夾下找;

      3)、以上都沒有錯誤頁面,就是默認來到SpringBoot默認的錯誤提示頁面

  2)、如何定製錯誤的json數據;

    1)、自定義異常處理&返回定製json數據;

 1 @ControllerAdvice
 2 public class MyExceptionHandler {
 3 
 4     @ResponseBody
 5     @ExceptionHandler(UserNotExistException.class)
 6     public Map<String,Object> handleException(Exception e){
 7 
 8         Map<String,Object> map = new HashMap<>();
 9         map.put("code","user.notexist");
10         map.put("message",e.getMessage());
11 
12         return map;
13     }
14 
15 }//沒有自適應效果...

    2)、轉發到/error進行自適應響應效果處理

 1     @ExceptionHandler(UserNotExistException.class)
 2     public String handleException(Exception e, HttpServletRequest request){
 3 
 4         Map<String,Object> map = new HashMap<>();
 5         //傳入咱們本身的錯誤狀態碼 4xx 5xx,不然就不會進入定製錯誤頁面的解析流程
 6         /*
 7         Integer statusCode = (Integer) request
 8                 .getAttribute("javax.servlet.error.status_code");
 9         */
10         request.setAttribute("javax.servlet.error.status_code",500);
11         map.put("code","user.notexist");
12         map.put("message",e.getMessage());
13         //轉發到/error
14         return "forward:/error";
15     }
16 
17 }

    3)、將咱們的定製數據攜帶出去;

      出現錯誤之後,會來到/error請求,會被BasicErrorController處理,響應出去能夠獲取的數據是由getErrorAttributes獲得的(是AbstractErrorController(ErrorController)規定的方法);

      1)、徹底來編寫一個ErrorController的實現類(或者是編寫AbstractErrorController的子類),放在容器中;

      2)、頁面上能用的數據,或者是json返回能用的數據都是經過errorAttributes.getErrorAttributes獲得;容器中DefaultErrorAtrributes.getErrorAttributes默認進行數據處理的;

自定義ErrorAttributes

 1 //給容器中加入咱們本身定義的ErrorAttributes
 2 @Component
 3 public class MyErrorAttributes extends DefaultErrorAttributes{
 4 
 5     @Override
 6     public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
 7         Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
 8         map.put("company","youngyoung");
 9         return map;
10     }
11 }

最終的效果:響應是自適應的,能夠經過定製ErrorAttributes改變須要返回的內容

 

八、配置嵌入式Servlet

SpringBoot默認使用Tomcat做爲嵌入式的Servlet容器

 

問題?

1)、如何定製和修改Servlet容器的相關配置;

一、修改和server有關的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】)

1 server.port=8081
2 server.context-path=/young
3 
4 server.tomcat.uri-encoding=utf-8
5 
6 //通用的Servlet容器設置
7 server.xxx
8 //Tomcat的設置
9 server.tomcat.xxx

二、編寫一個EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定製器;來修改Servlet容器的配置

 1     @Bean
 2     public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
 3         return new EmbeddedServletContainerCustomizer() {
 4 
 5             //定製嵌入式的Servlet容器相關的規則
 6             @Override
 7             public void customize(ConfigurableEmbeddedServletContainer container) {
 8                 container.setPort(8083);
 9             }
10         };
11     }

 

2)、註冊Servlet三大組件【Servlet、Filter、Listener】

因爲SpringBoot默認是以jar包的方式啓動嵌入式的Servlet容器來啓動SpringBoot的web應用,沒有web.xml文件.

註冊三大組件用如下方式

ServletRegistrationBean

1 @Bean
2 public ServletRegistrationBean myServlet(){
3     ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
4     return registrationBean;
5 }

FilterRegistrationBean

1 @Bean
2     public FilterRegistrationBean myFilter(){
3         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
4         filterRegistrationBean.setFilter(new MyFilter());
5         filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myservlet"));
6         return filterRegistrationBean;
7     }

ServletListenerRegistrationBean

1     @Bean
2     public ServletListenerRegistrationBean myListener(){
3         ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
4         registrationBean.setListener(new MyListener());
5         return registrationBean;
6     }

 

SpringBoot幫咱們自動SpringMVC的時候,自動的註冊SpringMVC的前端控制器;DispatcherServlet;

 1 @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
 2 @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
 3 public ServletRegistrationBean dispatcherServletRegistration(
 4       DispatcherServlet dispatcherServlet) {
 5    ServletRegistrationBean registration = new ServletRegistrationBean(
 6          dispatcherServlet, this.serverProperties.getServletMapping());
 7     //默認攔截: /  全部請求;包靜態資源,可是不攔截jsp請求;   /*會攔截jsp
 8     //能夠經過server.servletPath來修改SpringMVC前端控制器默認攔截的請求路徑
 9     
10    registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
11    registration.setLoadOnStartup(
12          this.webMvcProperties.getServlet().getLoadOnStartup());
13    if (this.multipartConfig != null) {
14       registration.setMultipartConfig(this.multipartConfig);
15    }
16    return registration;
17 }

 

3)、替換爲其餘嵌入式Servlet容器

默認支持:

Tomcat(默認使用)

 

1 <dependency>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-web</artifactId>
4    引入web模塊默認就是使用嵌入式的Tomcat做爲Servlet容器;
5 </dependency>

 

Jetty

 

 1 <!-- 引入web模塊 -->
 2 <dependency>
 3    <groupId>org.springframework.boot</groupId>
 4    <artifactId>spring-boot-starter-web</artifactId>
 5    <exclusions>
 6       <exclusion>
 7          <artifactId>spring-boot-starter-tomcat</artifactId>
 8          <groupId>org.springframework.boot</groupId>
 9       </exclusion>
10    </exclusions>
11 </dependency>
12 
13 <!--引入其餘的Servlet容器-->
14 <dependency>
15    <artifactId>spring-boot-starter-jetty</artifactId>
16    <groupId>org.springframework.boot</groupId>
17 </dependency>

 

Undertow

 

 1 <!-- 引入web模塊 -->
 2 <dependency>
 3    <groupId>org.springframework.boot</groupId>
 4    <artifactId>spring-boot-starter-web</artifactId>
 5    <exclusions>
 6       <exclusion>
 7          <artifactId>spring-boot-starter-tomcat</artifactId>
 8          <groupId>org.springframework.boot</groupId>
 9       </exclusion>
10    </exclusions>
11 </dependency>
12 
13 <!--引入其餘的Servlet容器-->
14 <dependency>
15    <artifactId>spring-boot-starter-undertow</artifactId>
16    <groupId>org.springframework.boot</groupId>
17 </dependency>

 

 

4)、嵌入式Servlet容器自動配置原理

EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自動配置?

 1 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
 2 @Configuration
 3 @ConditionalOnWebApplication
 4 @Import(BeanPostProcessorsRegistrar.class)
 5 //導入BeanPostProcessorsRegistrar:Spring註解版;給容器中導入一些組件
 6 //導入了EmbeddedServletContainerCustomizerBeanPostProcessor:
 7 //後置處理器:bean初始化先後(建立完對象,還沒賦值賦值)執行初始化工做
 8 public class EmbeddedServletContainerAutoConfiguration {
 9     
10     @Configuration
11     @ConditionalOnClass({ Servlet.class, Tomcat.class })//判斷當前是否引入了Tomcat依賴;
12     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判斷當前容器沒有用戶本身定義EmbeddedServletContainerFactory:嵌入式的Servlet容器工廠;做用:建立嵌入式的Servlet容器
13     public static class EmbeddedTomcat {
14 
15         @Bean
16         public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
17             return new TomcatEmbeddedServletContainerFactory();
18         }
19 
20     }
21     
22     /**
23      * Nested configuration if Jetty is being used.
24      */
25     @Configuration
26     @ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
27             WebAppContext.class })
28     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
29     public static class EmbeddedJetty {
30 
31         @Bean
32         public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
33             return new JettyEmbeddedServletContainerFactory();
34         }
35 
36     }
37 
38     /**
39      * Nested configuration if Undertow is being used.
40      */
41     @Configuration
42     @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
43     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
44     public static class EmbeddedUndertow {
45 
46         @Bean
47         public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
48             return new UndertowEmbeddedServletContainerFactory();
49         }
50 
51     }

1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工廠)

 1 public interface EmbeddedServletContainerFactory {
 2 
 3     /**
 4      * Gets a new fully configured but paused {@link EmbeddedServletContainer} instance.
 5      * Clients should not be able to connect to the returned server until
 6      * {@link EmbeddedServletContainer#start()} is called (which happens when the
 7      * {@link ApplicationContext} has been fully refreshed).
 8      * @param initializers {@link ServletContextInitializer}s that should be applied as
 9      * the container starts
10      * @return a fully configured and started {@link EmbeddedServletContainer}
11      * @see EmbeddedServletContainer#stop()
12      */
13     EmbeddedServletContainer getEmbeddedServletContainer(//獲取嵌入式的Servlet容器
14             ServletContextInitializer... initializers);
15 
16 }

 

2)、EmbeddedServletContainer(嵌入式的Servlet容器)

3)、以TomcatEmbeddedServletContainerFactory爲例

 1 @Override
 2 public EmbeddedServletContainer getEmbeddedServletContainer(
 3       ServletContextInitializer... initializers) {
 4     //建立一個Tomcat
 5    Tomcat tomcat = new Tomcat();
 6     
 7     //配置Tomcat的基本環節
 8    File baseDir = (this.baseDirectory != null ? this.baseDirectory
 9          : createTempDir("tomcat"));
10    tomcat.setBaseDir(baseDir.getAbsolutePath());
11    Connector connector = new Connector(this.protocol);
12    tomcat.getService().addConnector(connector);
13    customizeConnector(connector);
14    tomcat.setConnector(connector);
15    tomcat.getHost().setAutoDeploy(false);
16    configureEngine(tomcat.getEngine());
17    for (Connector additionalConnector : this.additionalTomcatConnectors) {
18       tomcat.getService().addConnector(additionalConnector);
19    }
20    prepareContext(tomcat.getHost(), initializers);
21     
22     //將配置好的Tomcat傳入進去,返回一個EmbeddedServletContainer;而且啓動Tomcat服務器
23    return getTomcatEmbeddedServletContainer(tomcat);
24 }

4)、咱們對嵌入式容器的配置修改是怎麼生效的?

1 ServerProperties、EmbeddedServletContainerCustomizer
EmbeddedServletContainerCustomizer:定製器幫咱們修改了Servlet容器的配置?

怎麼修改的原理?

5)、容器中導入了EmbeddedServletContainerCustomizerBeanPostProcessor

 1 //初始化以前
 2 @Override
 3 public Object postProcessBeforeInitialization(Object bean, String beanName)
 4       throws BeansException {
 5     //若是當前初始化的是一個ConfigurableEmbeddedServletContainer類型的組件
 6    if (bean instanceof ConfigurableEmbeddedServletContainer) {
 7        //
 8       postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
 9    }
10    return bean;
11 }
12 
13 private void postProcessBeforeInitialization(
14             ConfigurableEmbeddedServletContainer bean) {
15     //獲取全部的定製器,調用每個定製器的customize方法來給Servlet容器進行屬性賦值;
16     for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
17         customizer.customize(bean);
18     }
19 }
20 
21 private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
22     if (this.customizers == null) {
23         // Look up does not include the parent context
24         this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
25             this.beanFactory
26             //從容器中獲取全部這葛類型的組件:EmbeddedServletContainerCustomizer
27             //定製Servlet容器,給容器中能夠添加一個EmbeddedServletContainerCustomizer類型的組件
28             .getBeansOfType(EmbeddedServletContainerCustomizer.class,
29                             false, false)
30             .values());
31         Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
32         this.customizers = Collections.unmodifiableList(this.customizers);
33     }
34     return this.customizers;
35 }
36 
37 ServerProperties也是定製器

步驟:

1)、SpringBoot根據導入的依賴狀況,給容器中添加相應的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】

2)、容器中某個組件要建立對象就會驚動後置處理器;EmbeddedServletContainerCustomizerBeanPostProcessor;

只要是嵌入式的Servlet容器工廠,後置處理器就工做

3)、後置處理器,從容器中獲取全部的EmbeddedServletContainerCustomizer,調用定製器的定製方法

 

5)、嵌入式Servlet容器啓動原理;

何時建立嵌入式的Servlet容器工廠?何時獲取嵌入式的Servlet容器並啓動Tomcat;

獲取嵌入式的Servlet容器工廠:

1)、SpringBoot應用啓動運行run方法

2)、refreshContext(context);SpringBoot刷新IOC容器【建立IOC容器對象,並初始化容器,建立容器中的每個組件】;若是是web應用建立AnnotationConfigEmbeddedWebApplicationContext,不然建立AnnotationConfigEmbeddedWebApplicationContext

 

3)、refresh(context)刷新剛纔建立好的Ioc容器

 

 1 public void refresh() throws BeansException, IllegalStateException {
 2    synchronized (this.startupShutdownMonitor) {
 3       // Prepare this context for refreshing.
 4       prepareRefresh();
 5 
 6       // Tell the subclass to refresh the internal bean factory.
 7       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 8 
 9       // Prepare the bean factory for use in this context.
10       prepareBeanFactory(beanFactory);
11 
12       try {
13          // Allows post-processing of the bean factory in context subclasses.
14          postProcessBeanFactory(beanFactory);
15 
16          // Invoke factory processors registered as beans in the context.
17          invokeBeanFactoryPostProcessors(beanFactory);
18 
19          // Register bean processors that intercept bean creation.
20          registerBeanPostProcessors(beanFactory);
21 
22          // Initialize message source for this context.
23          initMessageSource();
24 
25          // Initialize event multicaster for this context.
26          initApplicationEventMulticaster();
27 
28          // Initialize other special beans in specific context subclasses.
29          onRefresh();
30 
31          // Check for listener beans and register them.
32          registerListeners();
33 
34          // Instantiate all remaining (non-lazy-init) singletons.
35          finishBeanFactoryInitialization(beanFactory);
36 
37          // Last step: publish corresponding event.
38          finishRefresh();
39       }
40 
41       catch (BeansException ex) {
42          if (logger.isWarnEnabled()) {
43             logger.warn("Exception encountered during context initialization - " +
44                   "cancelling refresh attempt: " + ex);
45          }
46 
47          // Destroy already created singletons to avoid dangling resources.
48          destroyBeans();
49 
50          // Reset 'active' flag.
51          cancelRefresh(ex);
52 
53          // Propagate exception to caller.
54          throw ex;
55       }
56 
57       finally {
58          // Reset common introspection caches in Spring's core, since we
59          // might not ever need metadata for singleton beans anymore...
60          resetCommonCaches();
61       }
62    }
63 }

 

 

 

4)、onRefresh();web的ioc容器重寫了onRefresh方法

5)、webioc容器會建立嵌入式的Servlet容器;createEmbeddedServletContainer();

6)、獲取嵌入式的Servlet容器工廠:

EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

  從IOC容器中獲取EmbeddedServletContainerFactory 組件;

  TomcatEmbeddedServletContainerFactory建立對象,後置處理器一看是這個對象,就獲取全部的定製器來先定製Servlet容器的相關配置;

7)、使用容器工廠獲取嵌入式的Servlet容器:

this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());

8)、嵌入式的Servlet容器建立對象並啓動Servlet容器;

先啓動嵌入式的Servlet容器,再將ioc容器中剩下沒有建立出的對象獲取出來;

IOC容器啓動建立嵌入式的Servlet容器

 

九、使用外置的Servlet容器

嵌入式Servlet容器:應用打成可執行的jar

  優勢:簡單、便攜;

  缺點:默認不支持JSP、優化定製比較複雜(使用定製器【ServerProperties、自定義EmbeddedServletContainerCustomizer】,本身編寫嵌入式Servlet容器的建立工廠【EmbeddedServletContainerFactory】);

 

外置的Servlet容器:外面安裝Tomcat---應用war包的方式打包;

步驟:

1)、必須建立一個war項目;(利用idea建立好目錄結構)

2)、將嵌入式的Tomact指定爲provided;

 

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency>

 

3)、必須編寫一個SpringBootServletInitializer的子類,並調用configure方法

1 public class ServletInitializer extends SpringBootServletInitializer {
2 
3     @Override
4     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
5         return application.sources(SpringBoot04WebJspApplication.class);//須要傳入SpringBoot應用的主程序
6     }
7 
8 }

4)、啓動服務器就可使用;

 

 

原理

jar包:執行SpringBoot主類的main方法,啓動ioc容器,再來建立嵌入式的Servlet容器;

war包:啓動服務器,服務器啓動SpringBoot應用【SpringBootServletInitializer ,啓動ioc容器;

 

servlet3.0:

規則:

  1)、服務器啓動(web應用啓動)會建立當前web應用裏面每個jar包裏面ServletContainerInitializer實例;

  2)、ServletContainerInitializer的實現放在jar包的META-INF/services文件夾下,有一個名爲javax.servlet.ServletContainerInitializer的文件,內容就是ServletContainerInitializer的實現類的全類名

  3)、還可使用@HandlesTypes,在應用啓動的時候加載咱們感興趣的類;

  

流程:

1)、啓動Tomcat

2)、org\springframework\spring-web\4.3.18.RELEASE\spring-web-4.3.18.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer

Spring的web模塊裏面有個這個文件:org.springframework.web.SpringServletContainerInitializer

3)、ServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標註的全部類型的類都傳入到onStartup放發的Set<Class<?>>;爲這些WebApplicationInitializer類型的類建立實例;

4)、每個WebApplicationInitializer都調用本身的onStartup;

5)、至關於咱們的SpringBootServletInitializer的類會被建立對象,並執行onStartup方法

6)、SpringBootServletInitializer實例執行onStartup的時候會建立createRootApplicationContext;建立容器

 1 protected WebApplicationContext createRootApplicationContext(
 2       ServletContext servletContext) {
 3     //一、建立SpringApplicationBuilder
 4    SpringApplicationBuilder builder = createSpringApplicationBuilder();
 5    StandardServletEnvironment environment = new StandardServletEnvironment();
 6    environment.initPropertySources(servletContext, null);
 7    builder.environment(environment);
 8    builder.main(getClass());
 9    ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
10    if (parent != null) {
11       this.logger.info("Root context already created (using as parent).");
12       servletContext.setAttribute(
13             WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
14       builder.initializers(new ParentContextApplicationContextInitializer(parent));
15    }
16    builder.initializers(
17          new ServletContextApplicationContextInitializer(servletContext));
18    builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
19     
20     //調用configure方法,子類重寫了這個方法,將SpringBoot的主程序類傳入了進來
21    builder = configure(builder);
22     
23     //使用builder建立一個Spring應用
24    SpringApplication application = builder.build();
25    if (application.getSources().isEmpty() && AnnotationUtils
26          .findAnnotation(getClass(), Configuration.class) != null) {
27       application.getSources().add(getClass());
28    }
29    Assert.state(!application.getSources().isEmpty(),
30          "No SpringApplication sources have been defined. Either override the "
31                + "configure method or add an @Configuration annotation");
32    // Ensure error pages are registered
33    if (this.registerErrorPageFilter) {
34       application.getSources().add(ErrorPageFilterConfiguration.class);
35    }
36     //啓動Spring應用
37    return run(application);
38 }

7)、Spring的應用就啓動而且建立IOC容器

 1 public ConfigurableApplicationContext run(String... args) {
 2    StopWatch stopWatch = new StopWatch();
 3    stopWatch.start();
 4    ConfigurableApplicationContext context = null;
 5    FailureAnalyzers analyzers = null;
 6    configureHeadlessProperty();
 7    SpringApplicationRunListeners listeners = getRunListeners(args);
 8    listeners.starting();
 9    try {
10       ApplicationArguments applicationArguments = new DefaultApplicationArguments(
11             args);
12       ConfigurableEnvironment environment = prepareEnvironment(listeners,
13             applicationArguments);
14       Banner printedBanner = printBanner(environment);
15       context = createApplicationContext();
16       analyzers = new FailureAnalyzers(context);
17       prepareContext(context, environment, listeners, applicationArguments,
18             printedBanner);
19        
20        //刷新IOC容器
21       refreshContext(context);
22       afterRefresh(context, applicationArguments);
23       listeners.finished(context, null);
24       stopWatch.stop();
25       if (this.logStartupInfo) {
26          new StartupInfoLogger(this.mainApplicationClass)
27                .logStarted(getApplicationLog(), stopWatch);
28       }
29       return context;
30    }
31    catch (Throwable ex) {
32       handleRunFailure(context, listeners, analyzers, ex);
33       throw new IllegalStateException(ex);
34    }
35 }

啓動Servlet容器,再啓動SpringBoot應用

相關文章
相關標籤/搜索