整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          關于 HTML5 你需要了解的基礎知識

          TML5 是第五個且是當前的 HTML 版本,它是用于在萬維網上構建和呈現內容的標記語言。本文將幫助讀者了解它。 -- Palak Shah

          本文導航
          • -新標簽和元素 …… 08%

          • -HTML5 的高級功能 …… 16%

          • -地理位置 …… 16%

          • -網絡存儲 …… 33%

          • -應用緩存(AppCache) …… 44%

          • -視頻 …… 50%

          • -音頻 …… 61%

          • -畫布(Canvas) …… 71%

          • -HTML5 工具 …… 78%

          編譯自: http://opensourceforu.com/2017/06/introduction-to-html5/

          作者: Palak Shah

          譯者: geekpi

          HTML5 是第五個且是當前的 HTML 版本,它是用于在萬維網上構建和呈現內容的標記語言。本文將幫助讀者了解它。

          HTML5 通過 W3C 和Web 超文本應用技術工作組Web Hypertext Application Technology Working Group之間的合作發展起來。它是一個更高版本的 HTML,它的許多新元素可以使你的頁面更加語義化和動態。它是為所有人提供更好的 Web 體驗而開發的。HTML5 提供了很多的功能,使 Web 更加動態和交互。

          HTML5 的新功能是:

          • 新標簽,如 <header> 和 <section>

          • 用于 2D 繪圖的 <canvas> 元素

          • 本地存儲

          • 新的表單控件,如日歷、日期和時間

          • 新媒體功能

          • 地理位置

          HTML5 還不是正式標準(LCTT 譯注:HTML5 已于 2014 年成為“推薦標準”),因此,并不是所有的瀏覽器都支持它或其中一些功能。開發 HTML5 背后最重要的原因之一是防止用戶下載并安裝像 Silverlight 和 Flash 這樣的多個插件。

          新標簽和元素

          • 語義化元素: 圖 1 展示了一些有用的語義化元素。

          • 表單元素: HTML5 中的表單元素如圖 2 所示。

          • 圖形元素: HTML5 中的圖形元素如圖 3 所示。

          • 媒體元素: HTML5 中的新媒體元素如圖 4 所示。

          圖 1:語義化元素

          圖 2:表單元素

          圖 3:圖形元素

          圖 4:媒體元素

          HTML5 的高級功能

          地理位置

          這是一個 HTML5 API,用于獲取網站用戶的地理位置,用戶必須首先允許網站獲取他或她的位置。這通常通過按鈕和/或瀏覽器彈出窗口來實現。所有最新版本的 Chrome、Firefox、IE、Safari 和 Opera 都可以使用 HTML5 的地理位置功能。

          地理位置的一些用途是:

          • 公共交通網站

          • 出租車及其他運輸網站

          • 電子商務網站計算運費

          • 旅行社網站

          • 房地產網站

          • 在附近播放的電影的電影院網站

          • 在線游戲

          • 網站首頁提供本地標題和天氣

          • 工作職位可以自動計算通勤時間

          工作原理: 地理位置通過掃描位置信息的常見源進行工作,其中包括以下:

          • 全球定位系統(GPS)是最準確的

          • 網絡信號 - IP地址、RFID、Wi-Fi 和藍牙 MAC地址

          • GSM/CDMA 蜂窩 ID

          • 用戶輸入

          該 API 提供了非常方便的函數來檢測瀏覽器中的地理位置支持:

          if (navigator.geolocation) {

          // do stuff

          }

          getCurrentPosition API 是使用地理位置的主要方法。它檢索用戶設備的當前地理位置。該位置被描述為一組地理坐標以及航向和速度。位置信息作為位置對象返回。

          語法是:

          getCurrentPosition(showLocation, ErrorHandler, options);
          • showLocation:定義了檢索位置信息的回調方法。

          • ErrorHandler(可選):定義了在處理異步調用時發生錯誤時調用的回調方法。

          • options (可選): 定義了一組用于檢索位置信息的選項。

          我們可以通過兩種方式向用戶提供位置信息:測地和民用。

          1. 描述位置的測地方式直接指向緯度和經度。

          2. 位置信息的民用表示法是人類可讀的且容易理解。

          如下表 1 所示,每個屬性/參數都具有測地和民用表示。

          圖 5 包含了一個位置對象返回的屬性集。

          圖5:位置對象屬性

          網絡存儲

          在 HTML 中,為了在本機存儲用戶數據,我們需要使用 JavaScript cookie。為了避免這種情況,HTML5 已經引入了 Web 存儲,網站利用它在本機上存儲用戶數據。

          與 Cookie 相比,Web 存儲的優點是:

          • 更安全

          • 更快

          • 存儲更多的數據

          • 存儲的數據不會隨每個服務器請求一起發送。只有在被要求時才包括在內。這是 HTML5 Web 存儲超過 Cookie 的一大優勢。

          有兩種類型的 Web 存儲對象:

          1. 本地 - 存儲沒有到期日期的數據。

          2. 會話 - 僅存儲一個會話的數據。

          如何工作: localStorage 和 sessionStorage 對象創建一個 key=value 對。比如: key="Name", value="Palak"。

          這些存儲為字符串,但如果需要,可以使用 JavaScript 函數(如 parseInt() 和 parseFloat())進行轉換。

          下面給出了使用 Web 存儲對象的語法:

          • 存儲一個值:

          • localStorage.setItem("key1", "value1");

          • localStorage["key1"] = "value1";

          • 得到一個值:

          • alert(localStorage.getItem("key1"));

          • alert(localStorage["key1"]);

          • 刪除一個值: -removeItem("key1");

          • 刪除所有值:

          • localStorage.clear();

          應用緩存(AppCache)

          使用 HTML5 AppCache,我們可以使 Web 應用程序在沒有 Internet 連接的情況下脫機工作。除 IE 之外,所有瀏覽器都可以使用 AppCache(截止至此時)。

          應用緩存的優點是:

          • 網頁瀏覽可以脫機

          • 頁面加載速度更快

          • 服務器負載更小

          cache manifest 是一個簡單的文本文件,其中列出了瀏覽器應緩存的資源以進行脫機訪問。 manifest 屬性可以包含在文檔的 HTML 標簽中,如下所示:

          <html manifest="test.appcache">

          ...

          </html>

          它應該在你要緩存的所有頁面上。

          緩存的應用程序頁面將一直保留,除非:

          1. 用戶清除它們

          2. manifest 被修改

          3. 緩存更新

          視頻

          在 HTML5 發布之前,沒有統一的標準來顯示網頁上的視頻。大多數視頻都是通過 Flash 等不同的插件顯示的。但 HTML5 規定了使用 video 元素在網頁上顯示視頻的標準方式。

          目前,video 元素支持三種視頻格式,如表 2 所示。

          下面的例子展示了 video 元素的使用:

          <! DOCTYPE HTML>

          <html>

          <body>

          <video src=" vdeo.ogg" width="320" height="240" controls="controls">

          This browser does not support the video element.

          </video>

          </body>

          </html>

          例子使用了 Ogg 文件,并且可以在 Firefox、Opera 和 Chrome 中使用。要使視頻在 Safari 和未來版本的 Chrome 中工作,我們必須添加一個 MPEG4 和 WebM 文件。

          video 元素允許多個 source 元素。source 元素可以鏈接到不同的視頻文件。瀏覽器將使用第一個識別的格式,如下所示:

          <video width="320" height="240" controls="controls">

          <source src="vdeo.ogg" type="video/ogg" />

          <source src=" vdeo.mp4" type="video/mp4" />

          <source src=" vdeo.webm" type="video/webm" />

          This browser does not support the video element.

          </video>

          圖6:Canvas 的輸出

          音頻

          對于音頻,情況類似于視頻。在 HTML5 發布之前,在網頁上播放音頻沒有統一的標準。大多數音頻也通過 Flash 等不同的插件播放。但 HTML5 規定了通過使用音頻元素在網頁上播放音頻的標準方式。音頻元素用于播放聲音文件和音頻流。

          目前,HTML5 audio 元素支持三種音頻格式,如表 3 所示。

          audio 元素的使用如下所示:

          <! DOCTYPE HTML>

          <html>

          <body>

          <audio src=" song.ogg" controls="controls">

          This browser does not support the audio element.

          </video>

          </body>

          </html>

          此例使用 Ogg 文件,并且可以在 Firefox、Opera 和 Chrome 中使用。要在 Safari 和 Chrome 的未來版本中使 audio 工作,我們必須添加一個 MP3 和 Wav 文件。

          audio 元素允許多個 source 元素,它可以鏈接到不同的音頻文件。瀏覽器將使用第一個識別的格式,如下所示:

          <audio controls="controls">

          <source src="song.ogg" type="audio/ogg" />

          <source src="song.mp3" type="audio/mpeg" />

          This browser does not support the audio element.

          </audio>

          畫布(Canvas)

          要在網頁上創建圖形,HTML5 使用 畫布 API。我們可以用它繪制任何東西,并且它使用 JavaScript。它通過避免從網絡下載圖像而提高網站性能。使用畫布,我們可以繪制形狀和線條、弧線和文本、漸變和圖案。此外,畫布可以讓我們操作圖像中甚至視頻中的像素。你可以將 canvas 元素添加到 HTML 頁面,如下所示:

          <canvas id="myCanvas" width="200" height="100"></canvas>

          畫布元素不具有繪制元素的功能。我們可以通過使用 JavaScript 來實現繪制。所有繪畫應在 JavaScript 中。

          <script type="text/javascript">

          var c=document.getElementById("myCanvas");

          var cxt=c.getContext("2d");

          cxt.fillStyle="blue";

          cxt.storkeStyle = "red";

          cxt.fillRect(10,10,100,100);

          cxt.storkeRect(10,10,100,100);

          </script>

          以上腳本的輸出如圖 6 所示。

          你可以繪制許多對象,如弧、圓、線/垂直梯度等。

          HTML5 工具

          為了有效操作,所有熟練的或業余的 Web 開發人員/設計人員都應該使用 HTML5 工具,當需要設置工作流/網站或執行重復任務時,這些工具非常有幫助。它們提高了網頁設計的可用性。

          以下是一些幫助創建很棒的網站的必要工具。

          • HTML5 Maker: 用來在 HTML、JavaScript 和 CSS 的幫助下與網站內容交互。非常容易使用。它還允許我們開發幻燈片、滑塊、HTML5 動畫等。

          • Liveweave: 用來測試代碼。它減少了保存代碼并將其加載到屏幕上所花費的時間。在編輯器中粘貼代碼即可得到結果。它非常易于使用,并為一些代碼提供自動完成功能,這使得開發和測試更快更容易。

          • Font dragr: 在瀏覽器中預覽定制的 Web 字體。它會直接載入該字體,以便你可以知道看起來是否正確。也提供了拖放界面,允許你拖動字形、Web 開放字體和矢量圖形來馬上測試。

          • HTML5 Please: 可以讓我們找到與 HTML5 相關的任何內容。如果你想知道如何使用任何一個功能,你可以在 HTML Please 中搜索。它提供了支持的瀏覽器和設備的有用資源的列表,語法,以及如何使用元素的一般建議等。

          • Modernizr: 這是一個開源工具,用于給訪問者瀏覽器提供最佳體驗。使用此工具,你可以檢測訪問者的瀏覽器是否支持 HTML5 功能,并加載相應的腳本。

          • Adobe Edge Animate: 這是必須處理交互式 HTML 動畫的 HTML5 開發人員的有用工具。它用于數字出版、網絡和廣告領域。此工具允許用戶創建無瑕疵的動畫,可以跨多個設備運行。

          • Video.js: 這是一款基于 JavaScript 的 HTML5 視頻播放器。如果要將視頻添加到你的網站,你應該使用此工具。它使視頻看起來不錯,并且是網站的一部分。

          • The W3 Validator: W3 驗證工具測試 HTML、XHTML、SMIL、MathML 等中的網站標記的有效性。要測試任何網站的標記有效性,你必須選擇文檔類型為 HTML5 并輸入你網頁的 URL。這樣做之后,你的代碼將被檢查,并將提供所有錯誤和警告。

          • HTML5 Reset: 此工具允許開發人員在 HTML5 中重寫舊網站的代碼。你可以使用這些工具為你網站的訪問者提供一個良好的網絡體驗。


          Palak Shah

          作者是高級軟件工程師。她喜歡探索新技術,學習創新概念。她也喜歡哲學。你可以通過 palak311@gmail.com[1] 聯系她。


          via: http://opensourceforu.com/2017/06/introduction-to-html5/

          作者:Palak Shah[2] 譯者:geekpi 校對:wxy

          本文由 LCTT 原創編譯,Linux中國 榮譽推出

          點擊“了解更多”可訪問文內鏈接

          SpringBoot的Web開發支持

          在Spring Boot的Web開發中,有許多支持類和配置文件可以幫助我們快速搭建和配置Web應用程序。其中一些重要的支持類和配置文件包括:

          1.1 ServerPropertiesAutoConfiguration和ServerProperties

          這兩個類用于配置服務器的相關屬性,比如監聽端口、上下文路徑等。

          ServerPropertiesAutoConfiguration定義服務器配置參數加載工具Bean serverProperties ServerPropertiesAutoConfiguration是Springboot的另外一個自動配置類,位于包

          package org.springframework.boot.autoconfigure.web

          它定義了bean serverProperties,對應實現類ServerProperties,這是負責加載服務器配置參數的工具類。

          // 該代碼引用略去與本主題無關部分
          @Configuration
          @EnableConfigurationProperties
          @ConditionalOnWebApplication
          public class ServerPropertiesAutoConfiguration {
          
              // 定義加載服務器配置參數的工具bean
              @Bean
              @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
              public ServerProperties serverProperties() {
                  return new ServerProperties();
              }
          }

          ServerProperties讀取服務器配置參數 ServerProperties是springboot的自動配置autoconfigure工具,位于包

          org.springframework.boot.autoconfigure.web

          該類用于提供服務器的端口,路徑,SSL等參數設置,它實現了接口EmbeddedServletContainerCustomizer,是專門設計給EmbeddedServletContainerCustomizerBeanPostProcessor用來定制EmbeddedServletContainerFactory實例的。

          ServerProperties在容器啟動時會被作為bean定義注冊到容器,在容器啟動過程中應用EmbeddedServletContainerCustomizerBeanPostProcessor的階段,ServerProperties bean會被實例化,此時配置文件會被該bean讀取。

          1.2 HttpEncodingAutoConfiguration和HttpEncodingProperties

          這兩個類用于配置HTTP請求和響應的字符編碼方式。

          HttpEncodingAutoConfiguration源碼如下:

          @AutoConfiguration
          @EnableConfigurationProperties(ServerProperties.class)
          @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
          @ConditionalOnClass(CharacterEncodingFilter.class)
          @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
          public class HttpEncodingAutoConfiguration {
          
              private final Encoding properties;
          
              public HttpEncodingAutoConfiguration(ServerProperties properties) {
                  this.properties = properties.getServlet().getEncoding();
              }
          
              @Bean
              @ConditionalOnMissingBean
              public CharacterEncodingFilter characterEncodingFilter() {
                  //  。。。
              }
          
              @Bean
              public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
                  // 。。。
              }
              
              // ...
          }
          
          • @AutoConfiguration : 該類是一個自動配置類,Spring Boot 會根據項目中的依賴自動配置這個類的實例。
          • @EnableConfigurationProperties(ServerProperties.class) :啟用 ServerProperties 類的配置屬性,這樣在配置文件中就可以使用 server.servlet.encoding 屬性來配置字符編碼。
          • @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) :該配置類只有在基于 servlet 的 web 應用程序中才會被實例化。
          • @ConditionalOnClass(CharacterEncodingFilter.class) :只有在項目中存在 CharacterEncodingFilter 類時才會生效。
          • @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) :只有在配置文件中 server.servlet.encoding 屬性的值為 "enabled" 時才會生效;當然如果配置文件中沒有這個屬性,也默認會生效。
          • @Bean :用于聲明一個方法創建的對象是一個 Spring 管理的 Bean。Spring 容器會自動管理這個 Bean 的生命周期,包括依賴注入、初始化和銷毀等。
          • @ConditionalOnMissingBean :只有在當前 Spring 容器中不存在指定類型的 Bean 時,才會執行被注解的方法。這樣可以用于確保在需要的時候才創建某個 Bean,避免重復創建。

          其中 ServerProperties 類的屬性值對應著 application.yml 或 application.properties 中的配置,通過注解@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) 實現的屬性注入。

          有關屬性注入來看看ServerProperties 類相關的部分源碼 和 對應的配置參數:

          @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
          public class ServerProperties {
              // 。。。
              private final Servlet servlet = new Servlet();
              // 。。。
              public static class Servlet {
                  // 。。。
                  @NestedConfigurationProperty
                  private final Encoding encoding = new Encoding();
                  // 。。。
              }
              // 。。。
          }
          
          public class Encoding {
              // 默認的HTTP編碼,用于Servlet應用程序。
              public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
          
              // HTTP請求和響應的字符集。如果未顯式設置,將添加到"Content-Type"頭中
              private Charset charset = DEFAULT_CHARSET;
          
              // 是否強制在HTTP請求和響應上使用配置的字符集的標志
              private Boolean force;
          
              // 是否強制在HTTP請求上使用配置的字符集的標志。當"force"未指定時,默認為true。
              private Boolean forceRequest;
          
              // 是否強制在HTTP響應上使用配置的字符集的標志。
              private Boolean forceResponse;
          
              // 將區域設置映射到字符集以進行響應編碼的映射。
              private Map<Locale, Charset> mapping;
              // 。。。
          }
          

          當然在 application.properties 中,我們就可以添加如下的配置:

          server.servlet.encoding.force=true
          server.servlet.encoding.charset=UTF-8
          # server.servlet.encoding.force-request=true 
          # ...其他配置省略

          注意: server.servlet.encoding.force=true 和 server.servlet.encoding.force-request=true 這兩個配置項實際上具有相同的功能,它們都決定是否強制對客戶端請求進行字符編碼。當這些配置項設置為 true時,服務器將要求客戶端發送的請求內容使用指定的字符集進行編碼。 另外,從 Spring Boot 2.3.5 版本開始,server.servlet.encoding.enabled 配置項已被棄用。因此,推薦的做法是直接設置 server.servlet.encoding.charset 來指定字符集,然后通過設置server.servlet.encoding.force=true 來開啟對請求/響應的編碼集強制控制。

          1.3 MultipartAutoConfiguration和MultipartProperties

          這兩個類用于配置文件上傳功能。

          MultipartAutoConfiguration和MultipartProperties源碼如下:

          @Configuration(proxyBeanMethods = false)
          //類路徑下存在類Servlet, StandardServletMultipartResolver, MultipartConfigElement
          @ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
          //文件上傳開關,默認開啟
          @ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
          //servlet web應用環境
          @ConditionalOnWebApplication(type = Type.SERVLET)
          //文件上傳配置信息MultipartProperties
          @EnableConfigurationProperties(MultipartProperties.class)
          public class MultipartAutoConfiguration {
          
              private final MultipartProperties multipartProperties;
          
              public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
                  this.multipartProperties = multipartProperties;
              }
              //不存在MultipartConfigElement、CommonsMultipartResolver時創建MultipartConfigElement 
              @Bean
              @ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class })
              public MultipartConfigElement multipartConfigElement() {
                  return this.multipartProperties.createMultipartConfig();
              }
              
              //不存在時創建MultipartResolver
              @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
              @ConditionalOnMissingBean(MultipartResolver.class)
              public StandardServletMultipartResolver multipartResolver() {
                  StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
                  multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
                  return multipartResolver;
              }
          
          }
          

          MultipartProperties源碼:

          @ConfigurationProperties(prefix = "spring.servlet.multipart", ignoreUnknownFields = false)
          public class MultipartProperties {
          
              /**
               * Whether to enable support of multipart uploads.
               */
               //文件上傳開關
              private boolean enabled = true;
          
              /**
               * Intermediate location of uploaded files.
               */
               //文件上傳中間路徑
              private String location;
          
              /**
               * Max file size.
               */
               //文件最大大小
              private DataSize maxFileSize = DataSize.ofMegabytes(1);
          
              /**
               * Max request size.
               */
               //最大請求文件大小
              private DataSize maxRequestSize = DataSize.ofMegabytes(10);
          
              /**
               * Threshold after which files are written to disk.
               */
               //閾值,超過后文件將被寫入磁盤
              private DataSize fileSizeThreshold = DataSize.ofBytes(0);
          
              /**
               * Whether to resolve the multipart request lazily at the time of file or parameter
               * access.
               */
               //延遲解析
              private boolean resolveLazily = false;
          
              /**
               * Create a new {@link MultipartConfigElement} using the properties.
               * @return a new {@link MultipartConfigElement} configured using there properties
               */
               //根據默認或自定義配置項創建MultipartConfigElement 
              public MultipartConfigElement createMultipartConfig() {
                  MultipartConfigFactory factory = new MultipartConfigFactory();
                  PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
                  map.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold);
                  map.from(this.location).whenHasText().to(factory::setLocation);
                  map.from(this.maxRequestSize).to(factory::setMaxRequestSize);
                  map.from(this.maxFileSize).to(factory::setMaxFileSize);
                  return factory.createMultipartConfig();
              }
          
          }

          常用配置如下

          spring.servlet.multipart.enabled=true
          spring.servlet.multipart.max-file-size=10485760000
          spring.servlet.multipart.max-request-size=52428800000
          spring.servlet.multipart.location=d:/tmp

          1.4 JacksonHttpMessageConvertersConfiguration

          這個類用于配置JSON轉換器,方便在Web應用中處理JSON數據。

          JacksonHttpMessageConvertersConfiguration源碼:

          @Configuration(
                  proxyBeanMethods = false
          )
          class JacksonHttpMessageConvertersConfiguration {
              JacksonHttpMessageConvertersConfiguration() {
              }
           
              @Configuration(
                      proxyBeanMethods = false
              )
              @ConditionalOnClass({XmlMapper.class})
              @ConditionalOnBean({Jackson2ObjectMapperBuilder.class})
              protected static class MappingJackson2XmlHttpMessageConverterConfiguration {
                  protected MappingJackson2XmlHttpMessageConverterConfiguration() {
                  }
           
                  @Bean
                  @ConditionalOnMissingBean
                  public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(Jackson2ObjectMapperBuilder builder) {
                      return new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build());
                  }
              }
           
              /**
               * @Configuration - 配置類注解
               * @ConditionalOnXxx
               *      - 為條件注解,當添加了Jackson依賴,就有了ObjectMapper.class和屬性,后面的配置就會生效
               */
              @Configuration(
                      proxyBeanMethods = false
              )
              @ConditionalOnClass({ObjectMapper.class})
              @ConditionalOnBean({ObjectMapper.class})
              @ConditionalOnProperty(
                      name = {"spring.mvc.converters.preferred-json-mapper"},
                      havingValue = "jackson",
                      matchIfMissing = true
              )
              static class MappingJackson2HttpMessageConverterConfiguration {
                  MappingJackson2HttpMessageConverterConfiguration() {
                  }
           
                  /**
                   * MappingJackson2HttpMessageConverter就是Jackson的消息轉換工具類
                   * @ConditionalOnMissingBean
                   *   - 表示如果我們沒有配置這個Bean,就自動創建一個默認的,當我們配置了就使用我們自定義的Bean。
                   *
                   * @param objectMapper
                   * @return
                   */
                  @Bean
                  @ConditionalOnMissingBean(
                          value = {MappingJackson2HttpMessageConverter.class},
                          ignoredType = {"org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter", "org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter"}
                  )
                  MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
                      // JSON中序列化對象主要用ObjectMapper工具類
                      return new MappingJackson2HttpMessageConverter(objectMapper);
                  }
              }

          通過查看上面源碼,可以知道我們修改生成的JSON的全局格式有以下兩種方式:

          1)自定義MappingJackson2HttpMessageConverter類

          自己創建一個Bean,取代JacksonHttpMessageConvertersConfiguration中項目自帶的。

          例如:刪除 @JsonFormat注解,新建一個配置類,內容如下:

          @Configuration
          public class WebMVCConfig {
           
              @Bean
              MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
                  MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
                  ObjectMapper objectMapper = new ObjectMapper();
                  objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
                  converter.setObjectMapper(objectMapper);
                  return converter;
              }
          }

          2)自定義ObjectMapper類

          通過上面的類可以看到類中主要起作用的是ObjectMapping,ObjectMapping是直接注入的。它是在配置類JacksonAutoConfiguration 類中提供的。

          例如:在WebMVCConfig配置類中,注入自定義的ObjectMapping,內容如下:

          @Configuration
          public class WebMVCConfig {
           
              @Bean
              ObjectMapper objectMapper(){
                  ObjectMapper objectMapper = new ObjectMapper();
                  objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
                  return objectMapper;
              }
          }

          1.5 WebMvcAutoConfiguration和WebMvcProperties

          這兩個類用于配置Spring MVC的相關屬性,比如視圖解析器、攔截器等。

          WebMvcAutoConfiguration源碼:

          // 我的自動配置類在這些自動配置之后配置
          @AutoConfiguration(
          	after = { 
          		DispatcherServletAutoConfiguration.class, 
          		TaskExecutionAutoConfiguration.class,
          		ValidationAutoConfiguration.class 
          	}) 
          	
          // 如果是web應用就生效,類型SERVLET、REACTIVE 響應式web
          @ConditionalOnWebApplication(type = Type.SERVLET)
          
          // 容器中沒有這個Bean,才生效。默認就是沒有
          @ConditionalOnClass({ 
          	Servlet.class, 
          	DispatcherServlet.class,
          	WebMvcConfigurer.class 
          	})
          // 容器中沒有WebMvcConfigurationSupport類,才生效
          @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 
          
          // 優先級
          @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
          
          // 導入運行時的指標統計
          @ImportRuntimeHints(WebResourcesRuntimeHints.class)
          public class WebMvcAutoConfiguration { 
          }
          

          給容器中放了WebMvcConfigurer組件;給SpringMVC添加各種定制功能

          所有的功能最終會和配置文件進行綁定 WebMvcProperties: spring.mvc配置文件 WebProperties: spring.web配置文件

          @Configuration(proxyBeanMethods = false)
          @Import(EnableWebMvcConfiguration.class) // 額外導入了其他配置
          @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
          @Order(0)
          public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware{
          
          }

          2 Thymeleaf模版引擎

          2.1 Thymeleaf基礎知識

          Thymeleaf是適用于Web和獨立環境的現代服務器端Java引擎模板

          (1)模板引擎介紹 模板引擎(這里特指用于Web開發的模板引擎)是為了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用于網站的模板引擎就會生成一個標準的html文檔。從字面上理解模板引擎,最重要的就是模板二字,這個意思就是做好一個模板后套入對應位置的數據,最終以html的格式展示出來,這就是模板引擎的作用。 對于模板引擎的理解,可以這樣形象的做一個類比:開會! 相信你在上學初高中時候每次開會都要提前布置場地、拿小板凳、收拾場地。而你上了大學之后每次開會再也不去大操場了,每次開會都去學校的大會議室,桌子板凳音響主席臺齊全,來個人即可,還可復用……。

          模板引擎的功能就類似我們的會議室開會一樣開箱即用,將模板設計好之后直接填充數據即可而不需要重新設計整個頁面。提高頁面、代碼的復用性。 不僅如此,在Java中模板引擎還有很多,模板引擎是動態網頁發展進步的產物,在最初并且流傳度最廣的jsp它就是一個模板引擎。jsp是官方標準的模板,但是由于jsp的缺點比較多也挺嚴重的,所以很多人棄用jsp選用第三方的模板引擎,市面上開源的第三方的模板引擎也比較多,有Thymeleaf、FreeMaker、Velocity等模板引擎受眾較廣。

          (2)Thymeleaf介紹 Thymeleaf是眾多模板引擎的一種,從官方的介紹來看,Thymeleaf的目標很明確:

          Thymeleaf的主要目標是為開發工作流程帶來優雅自然的模板-HTML可以在瀏覽器中正確顯示,也可以作為靜態原型工作,從而可以在開發團隊中加強協作。 Thymeleaf擁有適用于Spring Framework的模塊,與開發者喜歡的工具的大量集成以及插入開發者自己的功能的能力,對于現代HTML5 JVM Web開發而言,Thymeleaf是理想的選擇——盡管它還有很多工作要做。 并且隨著市場使用的驗證Thymeleaf也達到的它的目標和大家對他的期望,在實際開發有著廣泛的應用。Thymeleaf作為被Springboot官方推薦的模板引擎,一定有很多過人和不尋同之處:

          • 動靜分離: Thymeleaf選用html作為模板頁,這是任何一款其他模板引擎做不到的!Thymeleaf使用html通過一些特定標簽語法代表其含義,但并未破壞html結構,即使無網絡、不通過后端渲染也能在瀏覽器成功打開,大大方便界面的測試和修改。
          • 開箱即用: Thymeleaf提供標準和Spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、改JSTL、改標簽的困擾。同時開發人員也可以擴展和創建自定義的方言。

          Springboot官方大力推薦和支持,Springboot官方做了很多默認配置,開發者只需編寫對應html即可,大大減輕了上手難度和配置復雜度。

          2.2 引入 Thymeleaf 依賴

          (1)pml引用

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

          (2)配置文件

          全局配置文件application.properties配置Thymeleaf模板的一些參數。如設置模板緩存、模板編碼、模板樣式、指定模板頁面存放路徑、指定模板頁面名稱的后綴

          spring.thymeleaf.cache=true
          spring.thymeleaf.encoding=UTF-8   
          spring.thymeleaf.mode=HTML5   
          spring.thymeleaf.prefix=classpath:/templates/  
          spring.thymeleaf.suffix=.html   

          (3)Thymeleaf命名空間的聲明

          <!DOCTYPE html>  
          <html xmlns:th="http://www.thymeleaf.org">  
          <head>  
              <title>My Thymeleaf Template</title>  
              <!-- 其他head元素,如meta, link, script等 -->  
          </head>  
          <body>  
              <!-- 頁面內容 -->  
          </body>  
          </html>
          
          <html xmlns:th="http://www.thymeleaf.org">

          xmlns:th聲明了Thymeleaf的命名空間。這個命名空間允許你在HTML標簽中使用Thymeleaf特定的屬性,如th:text、th:each等。Thymeleaf引擎在處理模板時會識別這些屬性,并根據它們的值動態地生成或修改HTML內容。

          2.3 常用配置

          雖然Springboot官方對Thymeleaf做了很多默認配置,但引入Thymeleaf的jar包依賴后很可能需要根據開發者特定需求進行更細化的配置,例如頁面緩存、字體格式設置等等。

          Springboot官方提供的配置內容有以下:

          # 是否啟用模板緩存,默認為true。啟用后,模板在第一次編譯后會被緩存,提高渲染效率。
          spring.thymeleaf.cache=true 
          
          # 在渲染模板之前是否檢查模板是否存在,默認為false。
          spring.thymeleaf.check-template=true 
          
          # 是否檢查模板位置是否存在,默認為true。
          spring.thymeleaf.check-template-location=true 
          
          # 是否啟用Thymeleaf視圖解析,適用于Web框架,默認為true。
          spring.thymeleaf.enabled=true 
          
          # 是否在SpringEL表達式中啟用SpringEL編譯器,默認為false。啟用后可以提高表達式的執行效率。
          spring.thymeleaf.enable-spring-el-compiler=false 
          
          # 模板文件的編碼方式,默認為"UTF-8"。
          spring.thymeleaf.encoding=UTF-8 
          
          # 逗號分隔的視圖名稱列表(允許使用模式),這些視圖將被排除在解析之外。
          spring.thymeleaf.excluded-view-names= 
          
          # 應用于模板的模板模式,默認為"HTML"。也可以參考Thymeleaf的TemplateMode枚舉了解其他模式。
          spring.thymeleaf.mode=HTML 
          
          # 構建URL時,視圖名稱前綴,默認為"classpath:/templates/"。
          spring.thymeleaf.prefix=classpath:/templates/ 
          
          # 當設置了最大塊大小時,只有這些視圖名稱(允許使用模式)會以CHUNKED模式執行。
          spring.thymeleaf.reactive.chunked-mode-view-names= 
          
          # 即使設置了最大塊大小,這些視圖名稱(允許使用模式)也會以FULL模式執行。
          spring.thymeleaf.reactive.full-mode-view-names= 
          
          # 用于寫入響應的數據緩沖區的最大大小,以字節為單位,默認為0。
          spring.thymeleaf.reactive.max-chunk-size=0 
          
          # 視圖技術支持的媒體類型。
          spring.thymeleaf.reactive.media-types= 
          
          # 寫入HTTP響應的Content-Type值,默認為"text/html"。
          spring.thymeleaf.servlet.content-type=text/html 
          
          # 構建URL時,視圖名稱的后綴,默認為".html"。
          spring.thymeleaf.suffix=.html 
          
          # 模板解析器在鏈中的順序。
          spring.thymeleaf.template-resolver-order= 
          
          # 逗號分隔的視圖名稱列表(允許使用模式),這些視圖可以被解析。
          spring.thymeleaf.view-names= 
          

          2.4 常用語法

          Thymeleaf 作為一種模板引擎,它擁有自己的語法規則。Thymeleaf 語法分為以下 2 類:

          • th屬性
          • 標準表達式語法

          2.4.1 th屬性



          • th:eache:status中,有count(獲取循環的次數,從1開始)、first(判斷是否為第一次循環)、index(獲取循環的索引號,從0開始)、event(判斷count是否為偶數)、last(判斷是否是最后一次循環)、odd(判斷count是否為奇數)、size(獲取集合的長度)
          <tr th:each="employee,status : ${employees}">
          	<td th:text="${status.count}"></td>
          </tr>
          1
          • th:field:獲取域對象的屬性值,后臺不能用reques.setAttribute()來傳值,可以用model.addAttribute()來傳值;而這兩種方式th:value都可以接收;在單選框中,當th:field中的屬性值與value的值一樣,單選框就會被選中

          2.4.2 標準表達式語法

          Thymeleaf 模板引擎支持多種表達式:

          • 變量表達式:${...}
          • 選擇變量表達式:*{...}
          • 鏈接表達式:@{...}
          • 國際化表達式:#{...}
          • 片段引用表達式:~{...}

          變量表達式和國際化表達式都屬于OGNL(Objects-Graph Navigation Language,對象導航圖語言)是應用于Java中的一個開源的表達式語言

          2.4.2.1 變量表達式

          變量表達式(Variable Expressions):用于在模板中引用和顯示變量的值。例如,${variable}表示引用名為variable的變量

          使用 ${} 包裹的表達式被稱為變量表達式,該表達式具有以下功能:

          • 獲取對象的屬性或方法
          • 獲取內置的基本對象并使用
          • 獲取內置的工具對象并使用

          ${對象.屬性/方法名}:獲取對象的屬性或方法

          //獲取對象的方法
          ${book.getName()}

          ${#內置的基本對象}:獲取內置的基本對象并使用

          • ctx :上下文對象
          • vars :上下文變量
          • locale:上下文的語言環境
          • request:HttpServletRequest 對象(僅在 Web 應用中可用)
          • response:HttpServletResponse 對象(僅在 Web 應用中可用)
          • session:HttpSession 對象(僅在 Web 應用中可用)
          • servletContext:ServletContext 對象(僅在 Web 應用中可用)
          //獲取Session域對象中存儲的List集合對象
          //方式一:
          ${#session.getAttribute('books')
          //方式二:
          ${session.books}

          ${#內置的工具對象}:獲取內置的工具對象并使用

          • strings:字符串工具對象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等
          • numbers:數字工具對象,常用的方法有:formatDecimal 等
          • bools:布爾工具對象,常用的方法有:isTrue 和 isFalse 等
          • arrays:數組工具對象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等
          • lists/sets:List/Set 集合工具對象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等
          • maps:Map 集合工具對象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等
          • dates:日期工具對象,常用的方法有:format、year、month、hour 和 createNow 等
          //使用內置工具對象 strings 的 equals 方法,來判斷字符串與對象的某個屬性是否相等
          ${#strings.equals('張三',name)}

          2.4.2.2 選擇表達式

          選擇表達式(Selection Expressions):用于從對象中選擇屬性或方法。例如,*{user.name}表示選擇user對象的name屬性。

          選擇變量也可以稱為星號表達式,表達式與變量表達式功能基本一致,只是在變量表達式的基礎上增加了與 th:object 的配合使用。當使用 th:object 存儲一個對象后,我們可以在其后代中使用選擇變量表達式{...}獲取該對象中的屬性,其中,即代表該對象

          <div th:object="${session.user}" >
              <!--直接獲取user對象中的userName屬性的值-->
              <p th:text="*{userName}">firstname</p>
          </div>

          2.4.2.3 URL表達式

          URL表達式(URL Expressions):用于生成動態URL鏈接。例如,@{/path}會生成相對于當前上下文路徑的URL。

          鏈接表達式的形式結構如下:

          • 無參請求:@{/xxx}
          • 有參請求:@{/xxx(k1=v1,k2=v2)}

          2.4.2.4 鏈接表達式

          鏈接表達式(Link Expressions):類似于URL表達式,用于生成頁面內部的錨點鏈接。例如,#fragmentId會生成一個指向具有相應片段標識符的位置的鏈接。

          鏈接表達式是用于生成頁面內部的錨點鏈接(即片段標識符)。它們使用#符號作為前綴,后跟片段標識符。例如,#fragmentId會生成一個指向具有相應片段標識符的位置的鏈接。鏈接表達式主要用于在同一頁面內部進行導航和定位。

          <!DOCTYPE html>
          <html xmlns:th="http://www.thymeleaf.org">
          <head>
              <meta charset="UTF-8">
              <title>Link and URL Expression Demo</title>
          </head>
          <body>
              <h1>Link and URL Expression Demo</h1>
              
              <p>Link Expression:</p>
              <a th:href="#section1">Go to Section 1</a>
              <a th:href="#section2">Go to Section 2</a>
              
              <p>URL Expression:</p>
              <a th:href="@{/path1}">Link to Path 1</a>
              <a th:href="@{/path2}">Link to Path 2</a>
          
              <!-- Assume there are corresponding sections and paths in the application -->
              <section id="section1">
                  <h2>Section 1</h2>
                  <p>This is section 1 content.</p>
              </section>
              <section id="section2">
                  <h2>Section 2</h2>
                  <p>This is section 2 content.</p>
              </section>
          </body>
          </html>

          在上面的示例中,我們使用Thymeleaf的鏈接表達式和URL表達式創建了一些鏈接。

          鏈接表達式使用#符號,并通過th:href屬性生成到相應片段標識符的錨點鏈接。例如,<a th:href="#section1">Go to Section 1</a>會生成一個鏈接,點擊后將滾動至具有section1片段標識符的位置。

          URL表達式使用@符號,并通過th:href屬性生成動態的URL鏈接。例如,<a th:href="@{/path1}">Link to Path 1</a>會生成相對于當前上下文路徑的URL,點擊后將導航到/path1。

          4.2.2.5 國際化表達式

          國際表達式使用的基本步驟:

          配置國際化資源文件:首先,在項目中配置對應的國際化資源文件,按照不同語言創建不同的屬性文件,如messages_en.properties(英語)、messages_zh_CN.properties(中文)等。每個屬性文件中包含了對應語言的鍵值對,用于表示不同語言下的文本信息。

          設置 Locale 解析器:在 Spring MVC 中,需要配置 LocaleResolver 來解析用戶的語言偏好,并將其應用到 Thymeleaf 視圖中。常見的 LocaleResolver 有 CookieLocaleResolver、SessionLocaleResolver等,你可以根據需求選擇合適的LocaleResolver。

          在 Thymeleaf 模板中使用國際化表達式:在 Thymeleaf 模板中,可以使用國際化表達式來獲取對應語言的文本信息。通過#{}來包裹鍵名,Thymeleaf 會根據當前 Locale 自動尋找對應的屬性值。例如,<span th:text="#{welcome.message}"></span> 表示從國際化資源文件中獲取鍵為 “welcome.message” 的文本信息并顯示在HTML中。

          4.2.2.6 片段引用表達式

          Thymeleaf的片段引用表達式(Fragment Expression)是一種在模板中引用和渲染片段的方式。它允許將一個或多個片段從其他模板中提取出來并在當前模板中進行引用和渲染。

          Thymeleaf的片段引用表達式使用~{}包裹片段名稱,并可以傳遞參數。以下是使用片段引用表達式的基本語法:

          <div th:insert="~{templateName :: fragmentName(parameter1='value1', parameter2='value2')}"></div>

          其中,templateName表示模板文件名,fragmentName表示片段名稱。通過::符號來連接模板文件名和片段名稱。在片段引用表達式中,還可以傳遞參數給被引用的片段。參數以鍵值對的形式傳遞,使用逗號分隔。

          示例中的parameter1和parameter2是片段中定義的參數名稱,value1和value2是要傳遞的實際值。

          使用片段引用表達式可以將片段從其他模板中提取出來并插入到當前模板的指定位置。這有助于模塊化開發和代碼復用,可以將通用的部分抽離出來,減少重復代碼的編寫。

          需要注意的是,被引用的片段必須在對應的模板文件中存在,并且在片段定義處使用th:fragment屬性進行標記。例如,在templateName.html模板文件中定義一個片段:

          <div th:fragment="fragmentName">
              <!-- 片段內容 -->
          </div>

          然后在另一個模板中使用片段引用表達式來引用和渲染該片段:

          <div th:insert="~{templateName :: fragmentName}"></div>

          通過使用Thymeleaf的片段引用表達式,我們可以方便地將模板中的特定部分提取出來并在其他模板中重復使用,提高了代碼的可維護性和重用性。

          3 Web相關配置

          3.1 SpringBoot提供的自動配置

          3.1.1 自動配置的ViewResolver

          (1)ContentNegotiatingViewResolver

          • ContentNegotiatingViewResolver支持在Spring MVC下輸出不同的格式
          • ContentNegotiatingViewResolver是ViewResolver的一個實現
          • ContentNegotiatingViewResolver使用request的媒體類型,根據擴展名選擇不同的view輸出不同的格式
          • ContentNegotiatingViewResolver不是自己處理view,而是代理給不同的ViewResolver來處理不同的view;

          Spring在解析視圖的時候有兩個重要的接口:ViewResolverView

          ViewResolver 中只有一個方法 resolveViewName ,提供 view name 和 實際 view的映射; View 中兩個方法 getContentTyperender ,解析請求中的參數并把這個請求處理成某一種 View.

          對于一個請求,應該返回什么樣的視圖是 ViewResolver 來決定的,spring3.0提供的 ViewResolver 包括 AbstractCachingViewResolver,XmlViewResolver,ResourceBundleViewResolver,UrlBasedViewResolver,InternalResourceViewResolver,VelocityViewResolver/FreeMarkerViewResolver,ContentNegotiatingViewResolver等

          ContentNegotiatingViewResolver

          根據官方文檔:The ContentNegotiatingViewResolver does not resolve views itself but rather delegates to other view resolvers,就是說ContentNegotiatingViewResolver 本身并不自己去解析,只是分配給其他的ViewResolver 去解析。并選擇一個看起來像是客戶端請求需要返回的一種 View 返回。

          • spring檢查setFavorPathExtension(boolean) ,如果這個屬性為true(默認為true),檢查請求的后綴名,來返回一種 mediaType ,而后綴名和mediaType是通過ContentNegotiatingViewResolver 配置中的mediaTypes指定的
          • spring檢查 setFavorParameter(boolean) 這個屬性是否為true(默認為false),而如果你打開這個屬性,那么默認的參數名應為 format_
          • 沒有找到合適的mediaType,并且 ignoreAcceptHeader 這個屬性為false(默認為false),spring則根據 你請求頭里面設置的 ContentType 來找適合的 mediaType

          要想返回JSON數據所代表的MappingJacksonJsonView ,要么在請求頭中設置contentType為application/json,要么使用 .json 或者 ?format=json

          例子:

          /user/showUserListMix.html     //返回一個html的頁面顯示用戶列表
          /user/showUserListMix.html ?content=xml   //返回一個xml的頁面顯示用戶列表
          /user/showUserListMix.html ?content=json   //返回一個json的頁面顯示用戶列表

          (2)BeanNameViewResolver

          1)BeanNameViewResolver概述

          BeanNameViewResolver是Spring MVC框架提供的一個視圖解析器,它根據視圖名稱直接查找Spring容器中的同名Bean作為視圖對象。這種方式的好處在于簡單直觀,當視圖名稱與Bean名稱一一對應時,可以快速地解析出視圖對象。

          2)BeanNameViewResolver工作原理

          • 查找視圖Bean 當Spring MVC接收到一個請求并需要解析視圖時,它會調用BeanNameViewResolver的resolveViewName方法。該方法會根據請求的視圖名稱,在Spring容器中查找與之同名的Bean。如果找到了匹配的Bean,就將其返回作為視圖對象;如果沒有找到,則繼續嘗試其他視圖解析器。
          • 視圖Bean的創建與管理 在Spring容器中,視圖Bean的創建和管理與其他Bean沒有本質區別。可以通過XML配置或注解的方式定義視圖Bean,并指定其生命周期和依賴關系。Spring容器會負責這些Bean的創建、初始化和銷毀等過程。
          • 視圖Bean的調用 當BeanNameViewResolver解析出視圖Bean后,Spring MVC會調用該Bean的相應方法(通常是render方法)來渲染視圖。這取決于視圖Bean的具體實現和配置。

          3)BeanNameViewResolver的適用場景

          BeanNameViewResolver適用于視圖名稱與Bean名稱一一對應的情況,特別是當視圖實現較為簡單且數量不多時。在這種情況下,使用BeanNameViewResolver可以簡化配置和代碼,提高開發效率。

          然而,當視圖實現較為復雜或數量較多時,使用BeanNameViewResolver可能會導致Spring容器中的Bean數量過多,增加管理難度。此時,可以考慮使用其他更靈活的視圖解析器,如InternalResourceViewResolver或自定義的視圖解析器。

          4)總結

          BeanNameViewResolver作為Spring MVC框架中的一種視圖解析器,具有簡單直觀的特點。它通過直接查找Spring容器中的同名Bean來解析視圖對象,適用于視圖名稱與Bean名稱一一對應的情況。然而,在復雜或大規模的項目中,可能需要考慮使用其他更靈活的視圖解析器來滿足需求。

          在使用BeanNameViewResolver時,需要注意以下幾點:

          • 確保視圖名稱與Spring容器中的Bean名稱一致;
          • 合理管理視圖Bean的生命周期和依賴關系;
          • 根據項目實際情況選擇合適的視圖解析器。
          • 通過對BeanNameViewResolver原理的解析,我們可以更好地理解和使用這一視圖解析器,為Spring MVC項目的開發提供便利。

          (3)InteranlResourceViewResolver

          InternalResourceViewResolver 是 Spring MVC 中的一個視圖解析器,用于解析視圖名稱并將其解析為服務器上的實際資源。它主要用于將邏輯視圖名稱(例如 “index”)解析為實際的視圖資源路徑(例如 “/WEB-INF/views/index.jsp”)。

          InternalResourceViewResolver 可以配置在 Spring MVC 的配置文件中,并用于處理控制器方法返回的邏輯視圖名稱。當控制器方法返回一個字符串作為視圖名稱時,InternalResourceViewResolver 會將這個邏輯視圖名稱解析為實際的視圖資源路徑,然后將該路徑返回給客戶端進行展示。

          通過配置 InternalResourceViewResolver,可以簡化控制器方法的返回處理邏輯,并提供一種方便的方式來管理視圖資源的路徑。

          @Bean
          public ViewResolver viewResolver() {
              InternalResourceViewResolver irv = new InternalResourceViewResolver();
              irv.setPrefix("/WEB-INF/");
              irv.setSuffix(".jsp");
          
              return irv;
          
          }

          3.1.2 自動配置的靜態資源

          一般客戶端發送請求到web服務器,web服務器從內存在取到相應的文件,返回給客戶端,客戶端解析并渲染顯示出來。

          例如:css,js等文件。

          (1)使用webjar實現

          SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 這個配置類里面,默認為我們提供了靜態資源處理。

          我們進入WebMvcAutoConfigurationAdapter源碼里面進行查看,發現有這么一個方法: addResourceHandlers 添加資源處理;

          @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();
          // webjars 配置
                  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));
                  }
                  }

          所有的 /webjars/** , 都需要去 classpath:/META-INF/resources/webjars/ 找對應的資源; 什么是webjars 呢?

          Webjars本質就是以jar包的方式引入我們的靜態資源 。

          • 顯而易見,因為簡單。但不僅是依賴這么簡單:
          • 清晰的管理 web 依賴
          • 通過 Maven, Gradle 等項目管理工具就可以下載 web 依賴
          • 解決 web 組件中傳遞依賴的問題以及版本問題

          頁面依賴的版本自動檢測功能

          WebJars是將這些通用的Web前端資源打包成Java的Jar包,然后借助Maven工具對其管理,保證這些Web資源版本唯一性,升級也比較容易。關于webjars資源,有一個專門的網站https://www.webjars.org/,我們可以到這個網站上找到自己需要的資源,在自己的工程中添加入maven依賴,即可直接使用這些資源了。

          1)pom中引入依賴

          我們可以從WebJars官方查看maven依賴,如下圖


          例如:將bootstrap和jquery引入pom文件中

          <dependency>
             <groupId>org.webjars</groupId>
             <artifactId>jquery</artifactId>
             <version>3.5.1</version>
          </dependency>
          
          <dependency>
             <groupId>org.webjars</groupId>
             <artifactId>bootstrap</artifactId>
             <version>4.5.0</version>
          </dependency>

          2)訪問引入的js文件

          在html內訪問靜態資源可以使用如下方式:

          <script src="/webjars/jquery/3.5.1/jquery.min.js "></script>
          
          <script src="/webjars/bootstrap/4.5.0/js/bootstrap.min.js"></script>

          (2)將靜態資源文件放至靜態資源文件夾

          ResourceProperties類部分源碼

          @ConfigurationProperties(
            prefix = "spring.resources",
            ignoreUnknownFields = false
          )
          public class ResourceProperties {
            //springboot默認的加載路徑
            private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
            private String[] staticLocations;
            private boolean addMappings;
            private final ResourceProperties.Chain chain;
            private final ResourceProperties.Cache cache;
          

          映射規則總結

          在springboot靜態資源加載規則中,除了”標準“靜態資源位置之外,還有一個較為特殊的WebJars “標準”靜態資源映射規則。 所有的“/**”的請求,如果沒有對應的處理,那么就去默認映射的靜態資源目錄下去找,如下所示:

          "classpath:/META-INF/resources/"
          "classpath:/resources/"
          "classpath:/static/",
          "classpath:/public/"
          "/**"    //當前項目的根路徑

          (3)SpringBoot配置靜態資源

          1)通過配置文件配置

          配置節點:spring.web.resources.static-locations

          值為要配置的靜態資源存放目錄

          spring:
              web:     
                  resources:
                      static-locations: classpath:/test/

          以上配置中,設置靜態資源目錄為src/main/resources/test/目錄。

          假如在test目錄下存放文件test.txt,程序啟動后,便能通過瀏覽器訪問ip:port/test.txt訪問文件。

          2) 通過config類配置

          新建WebMvcConfig類,繼承WebMvcConfigurationSupport類,并添加注解@Configuration。

          重寫WebMvcConfigurationSupport類的addResourceHandlers方法。

          通過參數ResourceHandlerRegistry的addResourceHandler方法和addResourceLocations添加訪問路徑與資源目錄的映射。

          @Configuration
          public class WebMvcConfig extends WebMvcConfigurationSupport {
              @Override
              protected void addResourceHandlers(ResourceHandlerRegistry registry) {
                  registry.addResourceHandler("/test/**").addResourceLocations("classpath:/test/");
              }
          }

          上述配置代碼中,添加了路徑/test/**對資源目錄src/main/resources/test/的映射。

          假如在test目錄下存放文件test.txt,程序啟動后,便能在瀏覽器訪問ip:port/test/test.txt訪問文件內容

          區別:

          • 通過配置文件配置時,只能覆蓋默認配置設置一個靜態資源目錄(默認目錄為static),但無需添加根目錄名即可訪問。如“一”中訪問test.txt時,并沒有/test/路徑,而是直接訪問test.txt。
          • 通過代碼配置時,可以配置多對訪問路徑和資源目錄的映射,但訪問路徑需要包含根目錄名。如“二”中,訪問test.txt時,需要添加/test/路徑。

          共同點:

          • 以上兩種方法,一旦選擇其一進行配置,默認配置(static)目錄即失效。
          • 當同時使用兩種方法時,配置文件方法失效,僅代通過配置類配置的方法生效。

          3.1.3 自動配置的Formatter和Conventer

          只要我們定義了Converter,GenericConverter和Formatter接口的實現類的Bean,這些Bean就會自動注冊到SpringMVC中。 參考一下源碼(位于WebMvcAutoConfiguration類中)

          @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();
          }

          3.1.4 自動配置的HttpMessageConverters

          在WebMvcAutoConfiguration中,注冊了messageConverters:

          private final HttpMessageConverters messageConverters;
          @Override
                  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                      converters.addAll(this.messageConverters.getConverters());
                  }

          在Spring Boot中,如果要新增自定義的HttpMessageVoncerter,需要定義一個自己的HttpMessageConverters的Bean,然后在這個Bean中注冊自定義的HttpMessageConverter即可。 例如:

          @Bean
          public HttpMessageConverters customConverters() {
              HttpMessageConverter<?> customConverter1 = new CustomConverter1();
              HttpMessageConverter<?> customConverter2 = new CustomConverter2();
              return new HttpMessageConverters(customConverter1, customConverter2);
          }

          3.1.5 靜態首頁的支持

          將靜態首頁index.html文件放置在如下目錄:

          • classpath:/META-INF/resources/index.html
          • classpath:/resources/index.html
          • classpath:/static/index.html
          • classpath:/public/index.html 當訪問應用根目錄http://localhost:8080/時,會直接映射。

          3.2 接管SpringBoot的Web配置

          • 可以通過一個配置類(注解有@Configuration的類)加上@EnableWebMvc注解來實現自己控制的MVC配置。
          • 可以定義一個配置類并繼承WebMvcConfigurationAdapter,無需使用@EnableWebMvc注解,然后按照Spring MVC的配制方法來添加Spring Boot
          @Configuration
          public class WebMvcConfig extends WebMvcConfigurationAdapter{
              @Override
              public void addViewControllers(ViewCOntrolllerRegistery residtry) {
                  registery.addViewController("/xx").setViewName("/xx");
              }
          }

          注意,這里重寫的addViewControllers方法,并不會覆蓋WebMvcAutoConfiguration中的addViewControllers方法,即自己配置和Spring Boot的自動配置同時有效。

          3.3 注冊Servlet,Filter,Listener

          當使用嵌入式Servlet容器(Tomcat,Jetty等)時,通過將Servlet,Filter,Listener生命為Spring Bean來達到注冊的效果,或者注冊ServletRegistrationBean、FilterRegistrationBean、ServletListenerRigistrationBean的Bean。

          (1) 直接注冊Bean:

          @Bean
          pubilc XxServlet xxServlet (){
              return new XxServlet();
          }
          
          @Bean
          public YyFilter yyFilter() {
              return new YyServlet();
          }
          
          @Bean
          public ZzListener zzListener() {
              return new ZzListener();
          }

          (2) 通過RegistrationBean

          @Bean
          public ServletRegistrationBean serletRegistrationBean() {
              return new ServletRegistrationBean(new XxServlet(), "/xx/*");
          }
          
          @Bean 
          public FilterRegistrationBean filterRegistrationBean() {
              FilterRegistrationBean  registrationBean = new FilterRegistrationBean();
              registrationBean.setFilter( new YyFilter());
              registrationBean.setOrder(2);
              return registrationBean;
          }
          
          @Bean
          public ServletListenerRegistrationBean<ZzListener> zzListenerRegistrationBean() {
              return new ServletListenerRegistrationBean<ZzListener> (new ZzListener())
          }

          4 Tomcat配置

          4.1 配置Tomcat

          SpringBoot 項目中,可以內置 TomcatJettyUndertowNetty 等服務器容器。當我們添加了 spring-boot-starter-web 依賴后,默認會使用 Tomcat 作為 Web 容器。

          在SpringBoot框架的自動配置類中,Web項目中不顯式更換其他服務依賴時,默認提供了對Tomcat服務的管理;

          @ConditionalOnWebApplication(type = Type.SERVLET)
          @EnableConfigurationProperties(ServerProperties.class)
          @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
          		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class})
          public class ServletWebServerFactoryAutoConfiguration {
          
          	@Bean
          	@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
          	public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
          			ServerProperties serverProperties) {
          		return new TomcatServletWebServerFactoryCustomizer(serverProperties);
          	}
          }

          4.2 常用配置

          4.2.1 基本配置

          在配置文件中,對Tomcat做一些基礎性的設置,查看下面的配置類可以知道,這些屬性存在默認值;

          server:
            port: 8082                # 端口號
            tomcat:                   # Tomcat組件
              uri-encoding: UTF-8     # URI編碼
              max-threads: 100        # 最大工作線程
              min-spare-threads: 10   # 最小工作線程

          4.2.2 常用配置

          #端口號,默認8080
          server.port = 80
           
          #服務器綁定的網絡地址,默認0.0.0.0,允許通過所有IPv4地址進行連接
          server.address = yourIp
           
          #標準錯誤網頁,Whitelabel。它默認啟用,可以關閉
          server.error.whitelabel.enabled = false
           
          #Whitelabel默認路徑是/error,可以通過設置server.error.path參數來自定義它
          server.error.path = /user-error
           
          #設置屬性,以確定顯示有關錯誤的信息。可以包含錯誤消息和堆棧跟蹤
          server.error.include-exception= true
          server.error.include-stacktrace= always
           
          #工作線程的最大數量
          server.tomcat.max-threads= 200
           
          #設置服務器連接超時時間
          server.connection-timeout= 5s
           
          #定義請求頭的最大大小
          server.max-http-header-size= 8KB
           
          #請求正文的最大大小
          server.tomcat.max-swallow-size= 2MB
           
          #整個POST請求的最大大小
          server.tomcat.max-http-post-size= 2MB
           
          #啟用SSL支持,定義SSL協議
          server.ssl.enabled = true
          server.ssl.protocol = TLS
           
          #配置保存證書密鑰庫的密碼,類型和路徑
          server.ssl.key-store-password=my_password
          server.ssl.key-store-type=keystore_type
          server.ssl.key-store=keystore-path
           
          #定義標識密鑰庫中密鑰的別名
          server.ssl.key-alias=tomcat
           
          #啟用訪問日志
          server.tomcat.accesslog.enabled = true
           
          #配置參數,如附加到日志文件的目錄名,前綴,后綴和日期格式
          server.tomcat.accesslog.directory=logs
          server.tomcat.accesslog.file-date-format=yyyy-MM-dd
          server.tomcat.accesslog.prefix=access_log
          server.tomcat.accesslog.suffix=.log

          4.3 替換Tomcat

          4.3.2 替換為Jetty

          (1)改Maven依賴

          排除Tomcat依賴:首先,你需要在pom.xml文件中的spring-boot-starter-web依賴里排除Tomcat。這可以通過<exclusions>標簽實現。

          <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
                  <exclusions>
                      <exclusion>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-starter-tomcat</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
          </dependencies>

          添加Jetty依賴:接下來,在pom.xml中添加Jetty的起步依賴。

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

          配置文件調整(可選) 雖然通常情況下僅上述步驟就足夠了,但如果你需要對Jetty進行額外的配置,可以在application.properties中添加相應的配置項。例如,調整端口:

          # 端口配置
          server.port=8081
          
          # 啟動線程數
          server.jetty.acceptors=2
          
          # Selector線程數
          server.jetty.selectors=4
          
          # 訪問日志配置
          server.jetty.accesslog.enabled=true
          server.jetty.accesslog.filename=access.log
          server.jetty.accesslog.file-date-format=.yyyy-MM-dd
          
          # SSL/TLS配置
          server.ssl.key-store=classpath:keystore.p12
          server.ssl.key-store-type=PKCS12
          server.ssl.key-store-password=changeit
          server.ssl.keyAlias=tomcat
          
          # 請求和響應緩沖區大小
          server.jetty.max-http-header-size=10KB
          server.jetty.max-http-form-post-size=20MB

          4.3.2 替換為Undertow

          (1)依賴處理

          先排除Tomcat依賴 ,然后引入undertow依賴

          <dependency>
          	<groupId>org.springframework.boot</groupId>
          	<artifactId>spring-boot-starter-web</artifactId>
          	<exclusions>
          		<exclusion>
          			<groupId>org.springframework.boot</groupId>
          			<artifactId>spring-boot-starter-tomcat</artifactId>
          		</exclusion>
          	</exclusions>
          </dependency>
           <dependency>
          	<groupId>org.springframework.boot</groupId>
          	<artifactId>spring-boot-starter-undertow</artifactId>
          </dependency>

          (2)yml的配置項

          server:
            # 服務器的HTTP端口,默認為80
            port: 80
            servlet:
              # 應用的訪問路徑
              context-path: /
            # undertow 配置
            undertow:
              # HTTP post內容的最大大小。當值為-1時,默認值為大小是無限的
              max-http-post-size: -1
              # 以下的配置會影響buffer,這些buffer會用于服務器連接的IO操作,有點類似netty的池化內存管理
              # 每塊buffer的空間大小,越小的空間被利用越充分
              buffer-size: 512
              # 是否分配的直接內存
              direct-buffers: true
              threads:
                # 設置IO線程數, 它主要執行非阻塞的任務,它們會負責多個連接, 默認設置每個CPU核心一個線程
                io: 8
                # 阻塞任務線程池, 當執行類似servlet請求阻塞操作, undertow會從這個線程池中取得線程,它的值設置取決于系統的負載
                worker: 256

          4.4 SSL配置

          通過HTTP協議傳輸數據,并不會對數據進行加密,所以存在著一定的風險,容易被抓包破解數據,而且現在各種瀏覽器對使用HTTP協議的網站也會提示不安全。

          通過將HTTP協議升級為HTTPS協議可以提高安全系數。使用HTTPS協議就需要了解一下SSL協議。

          SSL(Secure Sockets Layer 安全套接字協議),及其繼任者傳輸層安全(Transport Layer Security,TLS)是為網絡通信提供安全及數據完整性的一種安全協議。

          TLS與SSL在傳輸層與應用層之間對網絡連接進行加密。

          SSL協議位于TCP/IP協議與各種應用層協議之間,為數據通訊提供安全支持。

          SSL協議可分為兩層:

          • SSL記錄協議(SSL Record Protocol):它建立在可靠的傳輸協議(如TCP)之上,為高層協議提供數據封裝、壓縮、加密等基本功能的支持。
          • SSL握手協議(SSL Handshake Protocol):它建立在SSL記錄協議之上,用于在實際的數據傳輸開始前,通訊雙方進行身份認證、協商加密算法、交換加密密鑰等。

          服務器認證階段:

          1)客戶端向服務器發送一個開始信息“Hello”以便開始一個新的會話連接;

          2)服務器根據客戶的信息確定是否需要生成新的主密鑰,如需要則服務器在響應客戶的“Hello”信息時將包含生成主密鑰所需的信息;

          3)客戶根據收到的服務器響應信息,產生一個主密鑰,并用服務器的公開密鑰加密后傳給服務器;

          4)服務器恢復該主密鑰,并返回給客戶一個用主密鑰認證的信息,以此讓客戶認證服務器。

          用戶認證階段:

          • 在此之前,服務器已經通過了客戶認證,這一階段主要完成對客戶的認證。
          • 經認證的服務器發送一個提問給客戶,客戶則返回(數字)簽名后的提問和其公開密鑰,從而向服務器提供認證。

          SSL協議提供的安全通道有以下三個特性:

          • 機密性:SSL協議使用密鑰加密通信數據。
          • 可靠性:服務器和客戶都會被認證,客戶的認證是可選的。
          • 完整性:SSL協議會對傳送的數據進行完整性檢查。

          從SSL 協議所提供的服務及其工作流程可以看出,SSL協議運行的基礎是商家對消費者信息保密的承諾,這就有利于商家而不利于消費者。

          4.4.1 配置證書

          keytool -genkeypair -alias tomcat -keyalg RSA -keystore tomcat.key

          依次填入以下內容:

          mcat.key
          輸入密鑰庫口令:
          再次輸入新口令:
          您的名字與姓氏是什么?
            [Unknown]:  localhost
          您的組織單位名稱是什么?
            [Unknown]:  localhost
          您的組織名稱是什么?
            [Unknown]:  xxx Co,.Ltd
          您所在的城市或區域名稱是什么?
            [Unknown]:  KunShan
          您所在的省/市/自治區名稱是什么?
            [Unknown]:  SuZhou
          該單位的雙字母國家/地區代碼是什么?
            [Unknown]:  China
          CN=localhost, OU=localhost, O="xxxCo,.Ltd", L=KunShan, ST=SuZhou, C=Chin
          a是否正確?
            [否]:y
          
          輸入 <tomcat> 的密鑰口令
                  (如果和密鑰庫口令相同, 按回車):
          再次輸入新口令:

          把生成的證書放入 resources目錄

          4.4.2 SpringBoot配置SSL

          配置application.yml

          server:
            port: 8110
            tomcat:
              max-threads: 800
              accept-count: 30000
              min-spare-threads: 20
              max-connections: 30000
            ssl:
              key-store: classpath:tomcat.key
              key-store-type: JKS
              key-alias: tomcat
              #證書密碼
              key-store-password: xxxx

          新增一個組件類

          @Component
          public class CustomContainer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
          
              @Value("${server.port}")
              int serverPort;
          
              @Override
              public void customize(ConfigurableServletWebServerFactory factory) {
                  factory.setPort(serverPort);
              }
          }

          4.4.3 http轉向https

          當用戶使用http訪問的時候,將http協議重定向到https端口

          (1)修改配置文件

          custom:  # 自定義http啟動端口
            http-port: 8089
          配置
          server:
            port: 8090 #端口配置  
            ssl: #ssl配置
              enabled: true  # 默認為true
              #key-alias: alias-key # 別名(可以不進行配置)
              # 保存SSL證書的秘鑰庫的路徑
              key-store: classpath:ssl/service.一級域名.jks
              key-password: 私鑰密碼
              #key-store-password: 證書密碼
              key-store-type: JKS
          

          (2)添加配置類

          package cn.zlc.servicehttps.config;
          
          import org.apache.catalina.Context;
          import org.apache.catalina.connector.Connector;
          import org.apache.tomcat.util.descriptor.web.SecurityCollection;
          import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          
          /**
           * https配置,將http請求全部轉發到https
           * @author Jacob
           */
          @Configuration
          public class HttpsConfig {
          
              @Value("${custom.http-port: 8080}")
              private Integer httpPort;
          
              @Value("${server.port}")
              private Integer port;
          
              @Bean
              public TomcatServletWebServerFactory servletContainer() {
                  // 將http請求轉換為https請求
                  TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
                      @Override
                      protected void postProcessContext(Context context) {
                          SecurityConstraint constraint = new SecurityConstraint();
                          // 默認為NONE
                          constraint.setUserConstraint("CONFIDENTIAL");
                          SecurityCollection collection = new SecurityCollection();
                          // 所有的東西都https
                          collection.addPattern("/*");
                          constraint.addCollection(collection);
                          context.addConstraint(constraint);
                      }
                  };
                  tomcat.addAdditionalTomcatConnectors(httpConnector());
                  return tomcat;
              }
          
              /**
               * 強制將所有的http請求轉發到https
               * @return httpConnector
               */
              @Bean
              public Connector httpConnector() {
                  Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
                  connector.setScheme("http");
                  // connector監聽的http端口號
                  connector.setPort(httpPort);
                  connector.setSecure(false);
                  // 監聽到http的端口號后轉向到的https的端口號
                  connector.setRedirectPort(port);
                  return connector;
              }
          }
          

          4.5 Favicon配置

          4.5.1 默認的Favicon

          Spring Boot提供了一個默認的Favicon,每次訪問應用的時候都能看到,如圖所示。



          4.5.2 關閉Favicon

          我們可以在application.properties中設置關閉Favicon,默認為開啟。

          spring.mvc.favicon.enabled=false

          4.5.3 設置自己的Favicon

          若需要設置自己的Favicon,則只需將自己的favicon.ico(文件名不能變動)文件放置在類路徑根目錄、類路徑META-INF/resources/下、類路徑resources/下、類路徑static/下或類路徑public/下。這里將favicon.ico放置在src/main/resources/static下。

          注意:配置文件不要配置spring.mvc.static-path-pattern參數,否則不能看到Favicon圖標

          4.6 WebSocket

          4.6.1 什么是WebSocket?

          WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協議,它允許在瀏覽器和服務器之間進行實時的、雙向的通信。相對于傳統的基于請求和響應的 HTTP 協議,WebSocket 提供了一種更有效、更實時的通信方式,適用于需要實時更新、實時通知和實時交互的應用。

          WebSocket 的一些關鍵特點包括:

          1. 全雙工通信: WebSocket 允許服務器和客戶端在同一連接上同時進行雙向通信。這意味著服務器可以隨時向客戶端推送數據,而不必等待客戶端發送請求。
          2. 持久連接: WebSocket 連接一旦建立,會一直保持打開狀態,不會像傳統的 HTTP 連接那樣在每次請求和響應之后關閉。這減少了每次連接建立和關閉的開銷,使通信更加高效。
          3. 低延遲: 由于連接保持打開狀態,WebSocket 通信具有較低的延遲,適用于實時性要求較高的應用,如實時聊天、實時數據更新等。
          4. 少量的數據交換: 與 HTTP 請求和響應相比,WebSocket 數據交換的開銷較小。WebSocket 的幀頭相對較小,因此有效載荷的比例更高。
          5. 兼容性: 現代瀏覽器和大多數服務器支持 WebSocket。此外,WebSocket 協議還定義了一個子協議 STOMP(Streaming Text Oriented Messaging Protocol),用于更高級的消息傳遞和訂閱功能。
          6. 安全性: 與其他網絡通信協議一樣,WebSocket 通信也需要一些安全性的考慮。可以使用加密協議(如 TLS)來保護數據在網絡傳輸中的安全性。

          4.6.2 代碼實戰

          (1)SpringBoot導入依賴

          在pom.xml中導入以下依賴,版本由SpringBoot管理

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

          (2)創建配置類

          創建WebSocketConfig配置類,并將其注入到Bean容器中

          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.web.socket.server.standard.ServerEndpointExporter;
           
          @Configuration
          public class WebSocketConfig {
              @Bean
              public ServerEndpointExporter serverEndpointExporter() {
                  return new ServerEndpointExporter();
              }
          }

          (3)創建WebSocketServer類

          創建WebSocketServer類,并將其注入到Bean容器中

          注意:@ServerEndpoint("/WebSocket"),該注解用于配置建立WebSocket連接的路徑,可以按需修改。

          該類一般擁有以下功能:

          1. WebSocket 端點注冊: WebSocket 服務器需要注冊一個或多個 WebSocket 端點(Endpoints)。每個端點對應一種處理邏輯,可以處理客戶端發送過來的消息,以及向客戶端發送消息。這些端點通過注解或配置來定義。
          2. 建立和維護連接: WebSocket 服務器負責監聽客戶端的連接請求,一旦有客戶端連接,服務器會創建一個 WebSocket 會話(Session)來管理這個連接。服務器需要能夠維護這些連接,包括打開、關閉、保持心跳等操作。
          3. 消息處理: 一旦客戶端連接成功,WebSocket 服務器需要處理客戶端發送過來的消息。這可以在 WebSocket 端點中的方法上定義處理邏輯。服務器可以根據不同的業務需求處理不同類型的消息。
          4. 處理異常: 與任何網絡通信一樣,WebSocket 連接可能會面臨各種異常情況,如斷開連接、網絡問題等。WebSocket 服務器需要能夠處理這些異常情況,進行適當的清理和處理。

          可以將該類理解為WebSocket生命周期中會調用的方法。

          import lombok.extern.slf4j.Slf4j;
          import org.springframework.stereotype.Component;
           
          import javax.websocket.*;
          import javax.websocket.server.ServerEndpoint;
           
          @Slf4j
          @Component
          @ServerEndpoint("/WebSocket")
          public class WebSocketServer {
           
              private Session session;
           
              @OnOpen
              public void onOpen(Session session) {
                  this.session = session;
                  WebSocketManager.sentToUser(session, "WebSocket is connected!");
                  WebSocketManager.addWebSocketServer(this);
                  log.info("與SessionId:{}建立連接", session.getId());
              }
           
              @OnClose
              public void onClose() {
                  WebSocketManager.removeWebSocketServer(this);
                  log.info("WebSocket連接關閉");
              }
           
              @OnMessage
              public void onMessage(String message, Session session) {
                  log.info("來自SessionId:{}的消息:{}", session.getId(), message);
              }
           
              @OnError
              public void onError(Session session, Throwable error) {
                  log.error("Session:{}的WebSocket發生錯誤", session.getId(), error);
              }
           
              public Session getSession() {
                  return session;
              }
           
              public String getSessionId() {
                  return session.getId();
              }
          }

          (4)創建WebSocketServer管理類

          該類用于管理WebSocketServer(其實主要是管理Session),如果不需要發送消息給特定用戶,那么無需創建該類,在WebSocketServer類中維護一個類變量即可。

          import lombok.extern.slf4j.Slf4j;
           
          import javax.websocket.Session;
          import java.util.concurrent.ConcurrentHashMap;
          import java.util.concurrent.CopyOnWriteArraySet;
           
          @Slf4j
          public class WebSocketManager {
           
              private final static CopyOnWriteArraySet<WebSocketServer> webSocketServerSet = new CopyOnWriteArraySet<>();
           
              private final static ConcurrentHashMap<String, WebSocketServer> webSocketServerMap = new ConcurrentHashMap<>();
           
              public static void addWebSocketServer(WebSocketServer webSocketServer){
                  if (webSocketServer != null){
                      webSocketServerSet.add(webSocketServer);
                      webSocketServerMap.put(webSocketServer.getSessionId(), webSocketServer);
                  }
              }
           
              public static void removeWebSocketServer(WebSocketServer webSocketServer){
                  webSocketServerSet.remove(webSocketServer);
                  webSocketServerMap.remove(webSocketServer.getSessionId());
              }
           
              /**
               * 通過SessionId發送消息給特定用戶
               * @param
               * @param msg
               */
              public static void sentToUser(String sessionId, String msg){
                  Session session = webSocketServerMap.get(sessionId).getSession();
                  sentToUser(session, msg);
              }
           
              /**
               * 通過Session發送消息給特定用戶
               * @param session
               * @param msg
               */
              public static void sentToUser(Session session, String msg){
                  if (session == null){
                      log.error("不存在該Session,無法發送消息");
                      return;
                  }
                  session.getAsyncRemote().sendText(msg);
              }
           
              /**
               * 發送消息給所有用戶
               * @param msg
               */
              public static void sentToAllUser(String msg){
                  for (WebSocketServer webSocketServer : webSocketServerSet) {
                      sentToUser(webSocketServer.getSession(), msg);
                  }
                  log.info("向所有用戶發送WebSocket消息完畢,消息:{}", msg);
              }
          }

          (5)前端代碼

          <!DOCTYPE html>
          <html>
          <head>
              <meta charset="utf-8">
              <title>websocket通訊</title>
          </head>
          <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
          <script>
              let socket;
              function openSocket() {
           
                  const socketUrl = "ws://localhost:9091/WebSocket/";
                  console.log(socketUrl);
                  if(socket!=null){
                      socket.close();
                      socket=null;
                  }
                  socket = new WebSocket(socketUrl);
                  //打開事件
                  socket.onopen = function() {
                      console.log("websocket已打開");
                  };
                  //獲得消息事件
                  socket.onmessage = function(msg) {
                      console.log(msg.data);
                      //發現消息進入,開始處理前端觸發邏輯
                  };
                  //關閉事件
                  socket.onclose = function() {
                      console.log("websocket已關閉");
                  };
                  //發生了錯誤事件
                  socket.onerror = function() {
                      console.log("websocket發生了錯誤");
                  }
              }
              function sendMessage() {
           
                  socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
                  console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
              }
          </script>
          <body>
          <p>【socket開啟者的ID信息】:<div><input id="userId" name="userId" type="text" value="10"></div>
          <p>【客戶端向服務器發送的內容】:<div><input id="toUserId" name="toUserId" type="text" value="20">
              <input id="contentText" name="contentText" type="text" value="hello websocket"></div>
          <p>【操作】:<div><a onclick="openSocket()">開啟socket</a></div>
          <p>【操作】:<div><a onclick="sendMessage()">發送消息</a></div>
          </body>
           
          </html>

          5 基于Bootstarp和AngularJS的現代Web應用

          現代的B/S系統軟件有下面幾個特色。

          1.單頁面應用 單頁面應用(single-page application,簡稱SPA)指的是一種類似于原生客戶端軟件的更流暢的用戶體驗的頁面。在單頁面的應用中,所有的資源(HTML、Javascript、CSS)都是按需動態加載到頁面上的,且不需要服務端控制頁面的轉向。

          2.響應式設計 響應式設計(Responsive web design,簡稱RWD)指的是不同的設備(電腦、平板、手機)訪問相同的頁面的時候,得到不同的頁面視圖,而得到的視圖是適應當前屏幕的。當然就算在電腦上,我們通過拖動瀏覽器窗口的大小, 也通用得到合適的視圖。

          3.數據導向 數據導向是對于頁面導向而言的,頁面上的數據獲得是通過消費后臺的REST服務來實現的,而不是通過服務器渲染的動態頁面(如JSP)來實現的,一般數據交換使用的格式是JSON。 本節將針對Bootstrap 和 AngularJS 進行快速入門式的引導,如需深入學習,請參考官網或相關專題書籍。

          5.1 Bootstrap

          1.什么是Bootstrap Bootstrap官方定義:Bootstrap是開發響應式和移動優先的Web應用的最流行的HTML、CSS、JavaScript框架。

          2.下載并引入Bootstrap 下載地址:http://getbootstrap.com/getting-started/, 如圖

          下載的壓縮包的目錄結構如圖

          css
          fonts
          js

          最簡單的Bootstrap頁面模板如下:

          <!DOCTYPE html>
          <html lang="zh-cn">
          <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width,initial-scale=1">
          <!-- 上面3個meta標簽必須是head 的頭三個標簽,其余的head內標簽在此3個之后 -->
          <title>Bootstrap基本模板</title>
          
          <!-- Bootstrap的CSS -->
          <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
          
          <!-- HTML5 shim and Respond.js 用來讓IE 8 支持 HTML 5 元素和媒體查詢 -->
          	<!-- [if lt IE 9]>
          		<script src="js/html5shiv.min.js"></script>
          		<script src="js/respond.min.js"></script>
          	<[endif]-->
          </head>
          <body>
          	<h1>你好,Bootstrap</h1>
          	
          	<!-- Jquery是Bootstrap腳本插件必需的 -->
          	<script src=js/jquery.min.js></script>
          	<!-- 包含所有編譯的插件 -->
          	<script src="bootstrap/js/bootstrap.min.js"></script>
          </body>
          </html>
          

          3.CSS支持 Bootstrap的CSS樣式為基礎的HTML元素提供了美觀的樣式,此外還提供了一個高級的網格系統用來做頁面布局。

          (1)布局網格 在Bootstrap里,行使用的樣式為row,列使用col-md-數字,此數字范圍為1~12,所有列加起來的和也是12,代碼如下:

          <div class="row">
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          	<div class="col-md-1">。col-md-1</div>
          </div>
          <div class="row">
          	<div class="col-md-8">.col-md-8</div>
          	<div class="col-md-4">.col-md-4</div>
          </div>
          <div>
          	<div class="col-md-4">.col-md-4</div>
          	<div class="col-md-4">.col-md-4</div>
          	<div class="col-md-4">.col-md-4</div>
          </div>
          <div>
          	<div class="col-md-6">.col-md-6</div>
          	<div class="col-md-6">.col-md-6</div>
          </div>

          (2)html元素

          Bootsrtap為html元素提供了大量的樣式,如表單元素、按鈕、圖標等。更多內容請查看:http://getbootstrap.com/css/。

          4.頁面組件支持 Bootstrap為我們提供了大量的頁面組件,包括字體圖標、下拉框、導航條、進度條、縮略圖等,更多請閱讀http://getboostrap.com/components/。

          5.javascript支持 Bootstrap為我們提供了大量的JavaScript插件,包含模式對話框、標簽頁、提示、警告等,更多內容請查看http://getbootstrap.com/javascript/。

          5.2 AngularJS

          1.什么是AngularJS AugularJS官方定義:AngularJS是HTML開發本應該的樣子,它是用來設計開發Web應用的。 AngularJS使用聲明式模板+數據綁定(類似于JSP、Thymeleaf)、MVW(Model-View——Whatever)、MVVM(Model-View-ViewModel)、MVC(Model-View-Controller)、依賴注入和測試,但是這一切的實現卻只借助純客戶端的JavaScript。 HTML一般是用來聲明靜態頁面的,但是通常情況下我們希望頁面是基于數據動態生成的,這也是我們很多服務端模板引擎出現的原因;而AngularJS可以只通過前端技術就能實現動態的頁面。

          2.下載并引入AngularJS AngularJS下載地址:https://code.angularjs.org/ 最簡單的AngularJS頁面

          <!DOCTYPE html>
          <html ng-app> <!-- ng-app所作用的范圍是AngularJS起效的范圍,本例是整個頁面有效。 -->
          <head>
          <sctipt src="js/angular.min.js"></sctipt>  <!-- 載入AngularJS的 腳本 -->
          </head>
          <body>
          <div>
          	<label>名字:</label>
          	<input type="text" ng-model="yourName" placeholder="輸入你的名字"> <!-- ng-model定義整個AngularJS的前端數據模型,模型的名稱為yourName,模型的值來自你輸入的值若輸入的值改變,則數據模型值也會變 -->
          	<hr>
          	<h1>你好{{yourName}}!</h1><!-- 使用{{模型名}}來讀取模型中的值。 -->
          </div>
          </body>
          </html>
          

          3.模塊、控制器和數據綁定

          我們對MVC的概念已經爛熟于心了,但是平時的MVC都是服務端的MVC,這里用AngularJS實現了純頁面端MVC,即實現了視圖模板、數據模型、代碼控制的分離。 再來看看數據綁定,數據綁定是將視圖和數據模型綁定在一起。如果視圖變了,則模型的值就變了;如果模型值變了,則視圖也會跟著改變。 AngularJS為了分離代碼達到復用的效果,提供了一個module(模塊)。定義一個模塊需使用下面的代碼。

          無依賴模塊:

          angular.module('firstModule',[]);

          有依賴模塊

          angular.module('firstModule',['moduleA','moduleB']);

          我們看到了V就是我們的頁面元素,M就是我們的ng-model,那C呢?我們可以通過下面的代碼來定義控制器,頁面使用ng-controller來和其關聯:

          augular.module('firstModule',[])
          	.controller('firstController',funtion(){
          	...
          	};
          );
          
          <div ng-controller="firstController">
          ...
          </div>
          

          4.Scope和Event

          (1)Scope Scope是AngularJS的內置對象,用$Scope來獲得。在Scope中定義的數據是數據模型,可以通過{{模型名}}在視圖上獲得。Scope主要是在編碼中需要對數據模型進行處理的時候使用,Scope的作用范圍與在頁面聲明的范圍一致(如在controller內使用,scope的作用范圍是頁面聲明ng-controller標簽元素的作用范圍)。

          定義:

          $scope.greeting='Hello'

          獲取

          {{greeting}}

          (2)Event

          因為Scope的作用范圍不同,所以不同的Scope之間若要交互的話需要通過事件(Event)來完成。 1)冒泡事件(Emit)冒泡事件負責從子Scope向上發送事件,示例如下。 子Scope發送:

          $scope.$emit('EVENT_NAME_EMIT','message');

          父Scope接受:

          $scope.$on(''EVENT_NAME_EMIT',function(event,data){
          	....
          })

          2)廣播事件(Broadcast)。廣播事件負責從父Scope向下發送事件,示例如下。 父Scope發送:

          $scope.$broadcast('EVENT_NAME_BROAD','message');
          

          子scope接受

          $scope.$on(''EVENT_NAME_BROAD',function(event,data){
          ...
          })

          5.多視圖和路由

          多視圖和路由是AngularJS實現單頁面應用的技術關鍵,AngularJS內置了一個$routeProvider對象來負責頁面加載和頁面路由轉向。 需要注意的是,1.2.0之后的AngularJS將路由功能移出,所以使用路由功能要另外引入angular-route.js 例如

          angular.module('firstModule').config(function($routeProvider){
          $routeProvider.when('/view1,{  //此處定義的是某個頁面的路由名稱
          	controller:'Controller1',   //此處定義的是當前頁面使用的控制器。
          	templateUrl:'view1.html',  //此處定義的要加載的真實頁面
          }).when('/view2',{
          	controller:'Controller2',
          	templateUrl:'view2.html',
          	});
          })

          在頁面上可以用下面代碼來使用我們定義的路由

          <ul>
          	<li><a href="#/view1">view1</a></li>
          	<li><a href="#/view2">view2</a></li>
          </ul>
          <ng-view></ng-view>  <!--此處為加載進來的頁面顯示的位置  -->
          

          依賴注入 依賴注入是AngularJS的一大酷炫功能。可以實現對代碼的解耦,在代碼里可以注入AngularJS的對象或者我們自定義的對象。下面示例是在控制器中注入$scope,注意使用依賴注入的代碼格式。

          angular.module('firstModule')
          	.controller("diController",['$scope',
          		function($scope){
          				...
          			}]);

          7.Service和Factory

          AngularJS為我們內置了一些服務,如$location、$time、$rootScope 。很多時候我們需要自己定制一些服務,AngularJS為我們提供了Service和Factory。 Service和Factory的區別是:使用Service的話,AngularJS會使用new來初始化對象;而使用Factory會直接獲得對象。 (1)Service

          定義:

          angular.module('firstModule').service('helloService',function(){
          	this.sayHello=function(name){
          		alert('Hello '+name);
          	}
          });

          注入調用:

          angular.module('firstModule'
          	.controller("diController",['$scope','helloService',
          		function($scope,helloService){
          			helloService.sayHello('lmz');
          	}]);

          (2)Factory

          定義:

          angular.module('firstModule').service('helloFactory',function(){
          	return{
          	sayHello:function(name){
          		alert('Hello ' + name);
          		}
          	}
          });

          注入調用:

          angular.module('firstModule')
          	.controller("diController",['$scope', 'helloFactory',
          		function($scope , helloFactory) {
          		 	helloFactory.sayHelle('lmz');
          		 }]);

          8.http操作

          AngularJS內置了$http對象用來進行Ajax的操作:

          $http.get(url)
          $http.post(url,data)
          $http.put(url,data)
          $http.delete(url)
          $http.head(url)

          9.自定義指令

          AngularJS內置了大量的指令(directive),如ng-repeat、ng-show、ng-model等。即使用一個簡短的指令可實現一個前端組件。 比方說,有一個日期的js/jQuery插件,使用AngularJS封裝后,在頁面上調用此插件可以通過指令來實現,例如:

          元素指令:<date-picker></date-picker>
          屬性指令:<input type="text" date-picker/>
          樣式指令:<input type="text" class="date-picker"/>
          注釋指令:<!--directive:date-picker -->
          

          定義指令:

          angular.module('myApp',[]).directive('helloWorld',function(){
          return {
          	restrict:'AE',  //支持使用屬性、元素
          	replace:true,
          	template:'<h3>Hello,World!</h3>
          };
          });

          調用指令,元素標簽:

          <hello-world/>
          
          <hello:world/>

          或者屬性方式

          <div hello-world />

          5.3 實戰

          在前面兩節我們快速介紹了Bootstrap和AngularJS,本節我人將它們和Spring Boot串起來做個例子。 在例子中,我們使用Bootstrap制作導航使用AngularJS實現導航切換頁面的路由功能,并演示AngularJS通過$http服務和Spring Boot提供的REST服務,最后演示用指令封裝jQuery UI的日期選擇器。

          1.新建Spring Boot項目

          初始化一個Spring Boot項目,依賴只需選擇Web 。

          準備Bootstrap、AngularJS、jQuery、jQueryUI相關的資源到 src/main/resources/static 下,結構如圖



          另外要說明的是,本例的頁面都是靜態頁面,所以全部放置在/static目錄下。

          2.制作導航

          頁面位置:src/main/resources/static/action.html:

          <!DOCTYPE html>
          <html lang="zh-cn" ng-app="actionApp">
          <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width,initial-scale=1">
          <title>實戰</title>
          
          <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
          <link href="jqueryui/jquery-ui.min.css" rel="sylesheet">
          <style type="text/css">
          
          .content{
          	padding:100px 15px;
          	text-align: center;
          }
          </style>
          
          <!--[if lt IE 9]>
          	<script src="js/html5shiv.min.js"></script>
          	<script src="js/respond.min.js"></scripte>
          	<![endif]-->
          </head>
          <body>
          <!-- 使用Bootstrap定義的導航,并配合AngularJS的路由,通過路由名稱#/oper和#/directive切換視圖 -->
          	<nav class="navbar navbar-inverse navbar-fixed-top">
          		<div class="container">
          			<div id="navbar" class="collapse navbar-collapse">
          				<ul class=nav navbar-nav>
          					<li><a href="#/oper">后臺交互</a>
          					<li><a href="#/directive">自定義指令</a></li>
          				</ul>
          			</div>
          		</div>
          	</nav>
          	
          	<!-- 通過<ng-view></ng-view>展示載入的頁面 -->
          	<div class="content">
          		<ng-view></ng-view>
          	</div>
          	
          	<!-- 加載本例所需的腳本,其中jquery-ui.min.js的腳本是為我們定制指令所用;app.js定義AngularJS的模塊和路由;directives.js為自定義的指令;controllers.js是控制器定義之處 -->
          	<script src="js/jquery.min.js"></script>
          	<script src="jqueryui/jquery-ui.min.js"></script>
          	<script src="bootstrap/js/bootstrap.min.js"></script>
          	<script src="js/angular.min.js"></script>
          	<script src="js/angular-route.min.js"></script>
          	<script src="js-action/app.js"></script>
          	<script src="js-action/directives.js"></script>
          	<script src="js-action/controllers.js"></script>
          </body>
          </html>

          3.模塊和路由定義

          頁面位置: src/main/resources/static/js-action/app.js:

          var actionApp = angular.module('actionApp',['ngRoute']);  //定義模塊actionApp,并依賴于路由模塊ngRout。
          
          actionApp.config(['$routeProvider'] , function($routeProvider){  //配置路由,并注入$routeProvider來配置
          	$routeProvider.when('/oper',{        //  /oper為路由名稱
          		controller:'View1Controller',     //controller定義的是路由的控制器名稱
          		templateUrl:'views/view1.html',    //templateUrl定義的是視圖的真正地址
          	}).when('/directive',{
          		controller:'View2Controller',
          		templateUrl:'views/view.html',
          	});
          });

          控制器定義 腳本位置: src/main/resources/static/js-action/controllers.js

          //定義控制器View1Controller,并注入$rootScope、$scope和$http。
          actionApp.controller('View1Controller',['$rootScope','$scope','$http',
          function($rootScope,$scope,$http){
          	//使用$scope.$on監聽$viewContentLoaded事件,可以在頁面內容加載完成后進行一些操作。
          	$scope.$on('$viewContentLoaded',function(){
          		console.log('頁面加載完成');
          	});
          	//這段代碼是核心 代碼,請結合下面的View1的界面一起理解
          	$scope.search=function(){  //在scope內定義一個方法search,在頁面上通過ng-click調用。
          		personName = $scope.personName;        //通過$scope.personName獲取頁面定義的ng-model = "personName" 的值。
          		$http.get('search',{                 //使用$http.get向服務器地址search發送get請求。
          			  		params:{personName:personName}   //使用params增加請求參數
          		}).success(function(data){                   //用success方法作為請求成功后的回調。
          			$scope.person=data;                     //將服務端返回的數據data通過$scope.person賦給模型person,這樣頁面視圖上可以通過{{person.name}}、{{person.age}}、{{person.address}}來調用,且模型person值改變后,視圖是自動更新的
          		});
          	};
          }]);
          
          actionApp.controller('View2Controller',['$rootScope','$scope',function($rootScope,$scope){
          	$scope.$on('$viewContentLoaded',function(){
          		console.log('頁面加載完成');
          	});
          }]);

          5.View1的界面(演示與服務端交互) 頁面位置 src/main/resources/static/views/view1.html

          <div class="row">
          	<label for="attr" class="col-md-2 control-label">名稱</label>
          	<div class="col-md-2">
          		<!-- 定義數據模型 ng-model="personName" -->
          		<input type="text" class="form-control" ng-model="personName">
          	</div>
          	<div class="col-md-1">
          	<!-- 通過ng-click="search()"調用控制器中定義的方法 -->
          	<button class="btn btn-primary" ng-click="search()">查詢</button>
          	</div>
          </div>
          
          <div class="row">
          	<div class="col-md-4">
          		<ul class="list-group">
          			<li class="list-group-item">名字:{{person.name}}
          			<li class="list-group-item">年齡:{{person.age}}
          			<li class="list-group-item">地址:{{person.address}}
          		</ul>
          	</div>
          </div>

          6.服務端代碼

          傳值對象Javabean:

          public class Person {
          	private String name;
          	private Integer age;
          	private String address;
          	
          	public Person() {
          		super();
          	}
          	
          	public Person(String name,Integer age,String address) {
          		super();
          		this.name=name;
          		this.age=age;
          		this.address=address;
          	}
          
          	public String getName() {
          		return name;
          	}
          
          	public void setName(String name) {
          		this.name = name;
          	}
          
          	public Integer getAge() {
          		return age;
          	}
          
          	public void setAge(Integer age) {
          		this.age = age;
          	}
          
          	public String getAddress() {
          		return address;
          	}
          
          	public void setAddress(String address) {
          		this.address = address;
          	}
          	
          	
          
          }

          控制器:

          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.autoconfigure.SpringBootApplication;
          import org.springframework.http.MediaType;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;
          
          @RestController
          @SpringBootApplication
          public class Ch77Application {
          	
          	@RequestMapping(value="/search",produces= {MediaType.APPLICATION_JSON_VALUE})
          	public Person search(String personName) {
          		return new Person(personName,32,"shenzhen");
          	}
          
          	public static void main(String[] args) {
          		SpringApplication.run(Ch77Application.class, args);
          	}
          
          }

          7.自定義指令

          腳本位置: src/main/resources/static/js-action/directives.js:

          actionApp.directive('datePicker',function(){  //定義一個指令名為datePicker。
          	return{
          		restrict:'AC',   //限制為屬性指令和樣式指令。
          		link:function(scope,elem,attrs){   //使用link方法來定義指令,在Link方法內可使用當前scope、當前元素及元素屬性。
          			elem.datepicher();				//初始化jqueryui的datePicker(jquery的寫法是$('#id').datePicker()).
          		}
          	};
          });

          通過上面的代碼我們就定制了一個封裝jqueryui的datePicker的指令,本例只是為了演示的目的,主流的腳本框架已經被很多人封裝過了,有興趣的讀者可以訪問http://ngmodules.org/網站,這個網站包含了大量的AngularJS的第三方模塊、插件和指令。

          8.View2的頁面(演示自定義指令)

          頁面地址: src/main/resources/static/views/view2.html:

          <div class="row">
              <label for="arrt" class="col-md-2 control-label">屬性形式</label>
              <div class="col-md-2">
                  <!-- 使用屬性形式調用指令 -->
                  <input type="text" class="form-control" date-picker>
              </div>
          </div>
          
          <div class="row">
              <label for="style" class="col-md-2 control-label">樣式形式</label>
              <div class="col-md-2">
                  <!-- 使用樣式形式調用指令 -->
                  <input type="text" class="form-control date-picker"
              </div>
          </div>

          9.運行

          菜單及路由切換如圖



          與后臺交互如圖

          自定義指定如圖

          TML5大前端是由新的標記引進的新元素形式和為現有元素新增的某些屬性,與新的JavaScript APIs的結合體。那么HTML5新增加了哪些新標簽與JavaScript API結合體以及具體作用有哪些呢?以下是最常用的幾種:

          1、Canvas API是一個具有完整功能的JavaScript API并伴隨產生了新HTML5元素。通過Canvas API,利用它和WebGL在瀏覽器中創建一個2 D或3 D繪圖場景;

          2、Contacts API主要應用在移動設備上,為瀏覽器提供對用戶通用通訊錄的訪問。它在瀏覽器內建立一個本地存儲庫,來存儲聯系人信息。Contacts API將允許您有本地存儲庫,網站可以通過本地存儲庫訪問存儲的聯系人信息。現在的主流瀏覽器都支持Contacts API;

          3、通過File API 瀏覽器可以直接訪問用戶計算機的沙箱區域,將數據存儲到文件系統;

          4、在HTML5中Forms API得到了發展,內置了驗證功能;

          5、允許瀏覽器請求用戶的位置信息,一旦獲權,瀏覽器通過許多不同的方法來確定計算機或設備的實際位置,它將會有一個比例尺來確認精確的地點位置。通過該API能獲取經緯度等數據,非常適合應用程序定位;

          6、Media Capture的功能是將本地設備通過JavaScript將與瀏覽器相連接;

          7、Messaging API被用來與其他API一起使用;

          8、選擇(Selection)API的就像jQuery庫一樣,運用非常廣泛;

          9、 Server-Sent Events API:一個網頁獲取新的數據通常需要發送一個請求到服務器,也就是向服務器請求的頁面。使用Server-Sent Events API,服務器可以在任何時刻向Web頁面推送數據和信息,這些被推送進來的信息可以在這個頁面上作為事件/數據來處理;

          10、 Web Notifications API即Web消息提醒,它可以使頁面發出通知,通知將被顯示在頁面之外的系統層面上(通常使用操作系統的標準通知機制,但是在不同的平臺和瀏覽器上的表現會有差異);

          11、Web Sockets API:Web Sockets是一種基ws協議的技術,它使得建立全雙工連接成為可能。Websocket常見于瀏覽器中,但是這個協議不受使用平臺的限制,允許收發信息到服務器端。

          以上是HTML5大前端中新加入的一些比較常用的功能API,如果想要系統的了解以及學習HTML5的新功能,可以選擇千鋒重慶校區的HTML5大前端課程。其課程將一線互聯網企業前沿技術遷移課堂,讓學員通過深度學習,切實掌握實戰技術,助力學員開啟成功職場生涯。


          主站蜘蛛池模板: AV鲁丝一区鲁丝二区鲁丝三区| 国产精品一区二区久久精品涩爱| 国产免费一区二区三区VR| 秋霞无码一区二区| 亚洲高清一区二区三区| 亚洲熟女乱综合一区二区| 中文字幕一区在线观看| 无码一区二区三区在线| 国产情侣一区二区三区| AA区一区二区三无码精片 | 久久精品免费一区二区喷潮| 精品一区二区三区3d动漫| 麻豆一区二区免费播放网站| 久久99国产精一区二区三区| 国产在线步兵一区二区三区| 91在线一区二区| 无码人妻精品一区二区三区66 | 精品视频一区二区| 无码少妇A片一区二区三区| 无码国产精品一区二区免费16| 中文字幕精品亚洲无线码一区应用 | 熟妇人妻AV无码一区二区三区| 国产一区二区精品在线观看| 蜜芽亚洲av无码一区二区三区| 色窝窝无码一区二区三区| 一区二区在线电影| 无码av人妻一区二区三区四区| 亚洲香蕉久久一区二区三区四区| 亚洲国产精品无码久久一区二区| 国产精品亚洲一区二区三区在线| AV无码精品一区二区三区宅噜噜| 又硬又粗又大一区二区三区视频| 无码人妻久久一区二区三区蜜桃| 国产日韩精品一区二区在线观看播放 | 色婷婷一区二区三区四区成人网| 蜜臀Av午夜一区二区三区| 在线精品亚洲一区二区| 国产日韩高清一区二区三区| 任你躁国语自产一区在| 福利片福利一区二区三区| 日韩电影一区二区|