Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 欧美精品久久,日韩中文字幕一在线,日韩欧美三级在线观看

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          關(guān)于 HTML5 你需要了解的基礎(chǔ)知識

          TML5 是第五個且是當(dāng)前的 HTML 版本,它是用于在萬維網(wǎng)上構(gòu)建和呈現(xiàn)內(nèi)容的標(biāo)記語言。本文將幫助讀者了解它。 -- Palak Shah

          本文導(dǎo)航
          • -新標(biāo)簽和元素 …… 08%

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

          • -地理位置 …… 16%

          • -網(wǎng)絡(luò)存儲 …… 33%

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

          • -視頻 …… 50%

          • -音頻 …… 61%

          • -畫布(Canvas) …… 71%

          • -HTML5 工具 …… 78%

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

          作者: Palak Shah

          譯者: geekpi

          HTML5 是第五個且是當(dāng)前的 HTML 版本,它是用于在萬維網(wǎng)上構(gòu)建和呈現(xiàn)內(nèi)容的標(biāo)記語言。本文將幫助讀者了解它。

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

          HTML5 的新功能是:

          • 新標(biāo)簽,如 <header> 和 <section>

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

          • 本地存儲

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

          • 新媒體功能

          • 地理位置

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

          新標(biāo)簽和元素

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

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

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

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

          圖 1:語義化元素

          圖 2:表單元素

          圖 3:圖形元素

          圖 4:媒體元素

          HTML5 的高級功能

          地理位置

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

          地理位置的一些用途是:

          • 公共交通網(wǎng)站

          • 出租車及其他運輸網(wǎng)站

          • 電子商務(wù)網(wǎng)站計算運費

          • 旅行社網(wǎng)站

          • 房地產(chǎn)網(wǎng)站

          • 在附近播放的電影的電影院網(wǎng)站

          • 在線游戲

          • 網(wǎng)站首頁提供本地標(biāo)題和天氣

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

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

          • 全球定位系統(tǒng)(GPS)是最準(zhǔn)確的

          • 網(wǎng)絡(luò)信號 - IP地址、RFID、Wi-Fi 和藍(lán)牙 MAC地址

          • GSM/CDMA 蜂窩 ID

          • 用戶輸入

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

          if (navigator.geolocation) {

          // do stuff

          }

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

          語法是:

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

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

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

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

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

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

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

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

          圖5:位置對象屬性

          網(wǎng)絡(luò)存儲

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

          與 Cookie 相比,Web 存儲的優(yōu)點是:

          • 更安全

          • 更快

          • 存儲更多的數(shù)據(jù)

          • 存儲的數(shù)據(jù)不會隨每個服務(wù)器請求一起發(fā)送。只有在被要求時才包括在內(nèi)。這是 HTML5 Web 存儲超過 Cookie 的一大優(yōu)勢。

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

          1. 本地 - 存儲沒有到期日期的數(shù)據(jù)。

          2. 會話 - 僅存儲一個會話的數(shù)據(jù)。

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

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

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

          • 存儲一個值:

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

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

          • 得到一個值:

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

          • alert(localStorage["key1"]);

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

          • 刪除所有值:

          • localStorage.clear();

          應(yīng)用緩存(AppCache)

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

          應(yīng)用緩存的優(yōu)點是:

          • 網(wǎng)頁瀏覽可以脫機

          • 頁面加載速度更快

          • 服務(wù)器負(fù)載更小

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

          <html manifest="test.appcache">

          ...

          </html>

          它應(yīng)該在你要緩存的所有頁面上。

          緩存的應(yīng)用程序頁面將一直保留,除非:

          1. 用戶清除它們

          2. manifest 被修改

          3. 緩存更新

          視頻

          在 HTML5 發(fā)布之前,沒有統(tǒng)一的標(biāo)準(zhǔn)來顯示網(wǎng)頁上的視頻。大多數(shù)視頻都是通過 Flash 等不同的插件顯示的。但 HTML5 規(guī)定了使用 video 元素在網(wǎng)頁上顯示視頻的標(biāo)準(zhǔn)方式。

          目前,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 發(fā)布之前,在網(wǎng)頁上播放音頻沒有統(tǒng)一的標(biāo)準(zhǔn)。大多數(shù)音頻也通過 Flash 等不同的插件播放。但 HTML5 規(guī)定了通過使用音頻元素在網(wǎng)頁上播放音頻的標(biāo)準(zhǔn)方式。音頻元素用于播放聲音文件和音頻流。

          目前,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)

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

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

          畫布元素不具有繪制元素的功能。我們可以通過使用 JavaScript 來實現(xiàn)繪制。所有繪畫應(yīng)在 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 工具

          為了有效操作,所有熟練的或業(yè)余的 Web 開發(fā)人員/設(shè)計人員都應(yīng)該使用 HTML5 工具,當(dāng)需要設(shè)置工作流/網(wǎng)站或執(zhí)行重復(fù)任務(wù)時,這些工具非常有幫助。它們提高了網(wǎng)頁設(shè)計的可用性。

          以下是一些幫助創(chuàng)建很棒的網(wǎng)站的必要工具。

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

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

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

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

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

          • Adobe Edge Animate: 這是必須處理交互式 HTML 動畫的 HTML5 開發(fā)人員的有用工具。它用于數(shù)字出版、網(wǎng)絡(luò)和廣告領(lǐng)域。此工具允許用戶創(chuàng)建無瑕疵的動畫,可以跨多個設(shè)備運行。

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

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

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


          Palak Shah

          作者是高級軟件工程師。她喜歡探索新技術(shù),學(xué)習(xí)創(chuàng)新概念。她也喜歡哲學(xué)。你可以通過 palak311@gmail.com[1] 聯(lián)系她。


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

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

          本文由 LCTT 原創(chuàng)編譯,Linux中國 榮譽推出

          點擊“了解更多”可訪問文內(nèi)鏈接

          SpringBoot的Web開發(fā)支持

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

          1.1 ServerPropertiesAutoConfiguration和ServerProperties

          這兩個類用于配置服務(wù)器的相關(guān)屬性,比如監(jiān)聽端口、上下文路徑等。

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

          package org.springframework.boot.autoconfigure.web

          它定義了bean serverProperties,對應(yīng)實現(xiàn)類ServerProperties,這是負(fù)責(zé)加載服務(wù)器配置參數(shù)的工具類。

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

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

          org.springframework.boot.autoconfigure.web

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

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

          1.2 HttpEncodingAutoConfiguration和HttpEncodingProperties

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

          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 會根據(jù)項目中的依賴自動配置這個類的實例。
          • @EnableConfigurationProperties(ServerProperties.class) :啟用 ServerProperties 類的配置屬性,這樣在配置文件中就可以使用 server.servlet.encoding 屬性來配置字符編碼。
          • @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) :該配置類只有在基于 servlet 的 web 應(yīng)用程序中才會被實例化。
          • @ConditionalOnClass(CharacterEncodingFilter.class) :只有在項目中存在 CharacterEncodingFilter 類時才會生效。
          • @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) :只有在配置文件中 server.servlet.encoding 屬性的值為 "enabled" 時才會生效;當(dāng)然如果配置文件中沒有這個屬性,也默認(rèn)會生效。
          • @Bean :用于聲明一個方法創(chuàng)建的對象是一個 Spring 管理的 Bean。Spring 容器會自動管理這個 Bean 的生命周期,包括依賴注入、初始化和銷毀等。
          • @ConditionalOnMissingBean :只有在當(dāng)前 Spring 容器中不存在指定類型的 Bean 時,才會執(zhí)行被注解的方法。這樣可以用于確保在需要的時候才創(chuàng)建某個 Bean,避免重復(fù)創(chuàng)建。

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

          有關(guān)屬性注入來看看ServerProperties 類相關(guān)的部分源碼 和 對應(yīng)的配置參數(shù):

          @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 {
              // 默認(rèn)的HTTP編碼,用于Servlet應(yīng)用程序。
              public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
          
              // HTTP請求和響應(yīng)的字符集。如果未顯式設(shè)置,將添加到"Content-Type"頭中
              private Charset charset = DEFAULT_CHARSET;
          
              // 是否強制在HTTP請求和響應(yīng)上使用配置的字符集的標(biāo)志
              private Boolean force;
          
              // 是否強制在HTTP請求上使用配置的字符集的標(biāo)志。當(dāng)"force"未指定時,默認(rèn)為true。
              private Boolean forceRequest;
          
              // 是否強制在HTTP響應(yīng)上使用配置的字符集的標(biāo)志。
              private Boolean forceResponse;
          
              // 將區(qū)域設(shè)置映射到字符集以進(jìn)行響應(yīng)編碼的映射。
              private Map<Locale, Charset> mapping;
              // 。。。
          }
          

          當(dāng)然在 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 這兩個配置項實際上具有相同的功能,它們都決定是否強制對客戶端請求進(jìn)行字符編碼。當(dāng)這些配置項設(shè)置為 true時,服務(wù)器將要求客戶端發(fā)送的請求內(nèi)容使用指定的字符集進(jìn)行編碼。 另外,從 Spring Boot 2.3.5 版本開始,server.servlet.encoding.enabled 配置項已被棄用。因此,推薦的做法是直接設(shè)置 server.servlet.encoding.charset 來指定字符集,然后通過設(shè)置server.servlet.encoding.force=true 來開啟對請求/響應(yīng)的編碼集強制控制。

          1.3 MultipartAutoConfiguration和MultipartProperties

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

          MultipartAutoConfiguration和MultipartProperties源碼如下:

          @Configuration(proxyBeanMethods = false)
          //類路徑下存在類Servlet, StandardServletMultipartResolver, MultipartConfigElement
          @ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
          //文件上傳開關(guān),默認(rèn)開啟
          @ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
          //servlet web應(yīng)用環(huán)境
          @ConditionalOnWebApplication(type = Type.SERVLET)
          //文件上傳配置信息MultipartProperties
          @EnableConfigurationProperties(MultipartProperties.class)
          public class MultipartAutoConfiguration {
          
              private final MultipartProperties multipartProperties;
          
              public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
                  this.multipartProperties = multipartProperties;
              }
              //不存在MultipartConfigElement、CommonsMultipartResolver時創(chuàng)建MultipartConfigElement 
              @Bean
              @ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class })
              public MultipartConfigElement multipartConfigElement() {
                  return this.multipartProperties.createMultipartConfig();
              }
              
              //不存在時創(chuàng)建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.
               */
               //文件上傳開關(guān)
              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
               */
               //根據(jù)默認(rèn)或自定義配置項創(chuàng)建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轉(zhuǎn)換器,方便在Web應(yīng)用中處理JSON數(shù)據(jù)。

          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
               *      - 為條件注解,當(dāng)添加了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的消息轉(zhuǎn)換工具類
                   * @ConditionalOnMissingBean
                   *   - 表示如果我們沒有配置這個Bean,就自動創(chuàng)建一個默認(rèn)的,當(dāng)我們配置了就使用我們自定義的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類

          自己創(chuàng)建一個Bean,取代JacksonHttpMessageConvertersConfiguration中項目自帶的。

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

          @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,內(nèi)容如下:

          @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的相關(guān)屬性,比如視圖解析器、攔截器等。

          WebMvcAutoConfiguration源碼:

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

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

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

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

          2 Thymeleaf模版引擎

          2.1 Thymeleaf基礎(chǔ)知識

          Thymeleaf是適用于Web和獨立環(huán)境的現(xiàn)代服務(wù)器端Java引擎模板

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

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

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

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

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

          Springboot官方大力推薦和支持,Springboot官方做了很多默認(rèn)配置,開發(fā)者只需編寫對應(yīng)html即可,大大減輕了上手難度和配置復(fù)雜度。

          2.2 引入 Thymeleaf 依賴

          (1)pml引用

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

          (2)配置文件

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

          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>  
              <!-- 頁面內(nèi)容 -->  
          </body>  
          </html>
          
          <html xmlns:th="http://www.thymeleaf.org">

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

          2.3 常用配置

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

          Springboot官方提供的配置內(nèi)容有以下:

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

          2.4 常用語法

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

          • th屬性
          • 標(biāo)準(zhǔn)表達(dá)式語法

          2.4.1 th屬性



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

          2.4.2 標(biāo)準(zhǔn)表達(dá)式語法

          Thymeleaf 模板引擎支持多種表達(dá)式:

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

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

          2.4.2.1 變量表達(dá)式

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

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

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

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

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

          ${#內(nèi)置的基本對象}:獲取內(nèi)置的基本對象并使用

          • ctx :上下文對象
          • vars :上下文變量
          • locale:上下文的語言環(huán)境
          • request:HttpServletRequest 對象(僅在 Web 應(yīng)用中可用)
          • response:HttpServletResponse 對象(僅在 Web 應(yīng)用中可用)
          • session:HttpSession 對象(僅在 Web 應(yīng)用中可用)
          • servletContext:ServletContext 對象(僅在 Web 應(yīng)用中可用)
          //獲取Session域?qū)ο笾写鎯Φ腖ist集合對象
          //方式一:
          ${#session.getAttribute('books')
          //方式二:
          ${session.books}

          ${#內(nèi)置的工具對象}:獲取內(nèi)置的工具對象并使用

          • strings:字符串工具對象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等
          • numbers:數(shù)字工具對象,常用的方法有:formatDecimal 等
          • bools:布爾工具對象,常用的方法有:isTrue 和 isFalse 等
          • arrays:數(shù)組工具對象,常用的方法有: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 等
          //使用內(nèi)置工具對象 strings 的 equals 方法,來判斷字符串與對象的某個屬性是否相等
          ${#strings.equals('張三',name)}

          2.4.2.2 選擇表達(dá)式

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

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

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

          2.4.2.3 URL表達(dá)式

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

          鏈接表達(dá)式的形式結(jié)構(gòu)如下:

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

          2.4.2.4 鏈接表達(dá)式

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

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

          <!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的鏈接表達(dá)式和URL表達(dá)式創(chuàng)建了一些鏈接。

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

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

          4.2.2.5 國際化表達(dá)式

          國際表達(dá)式使用的基本步驟:

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

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

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

          4.2.2.6 片段引用表達(dá)式

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

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

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

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

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

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

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

          <div th:fragment="fragmentName">
              <!-- 片段內(nèi)容 -->
          </div>

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

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

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

          3 Web相關(guān)配置

          3.1 SpringBoot提供的自動配置

          3.1.1 自動配置的ViewResolver

          (1)ContentNegotiatingViewResolver

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

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

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

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

          ContentNegotiatingViewResolver

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

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

          要想返回JSON數(shù)據(jù)所代表的MappingJacksonJsonView ,要么在請求頭中設(shè)置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框架提供的一個視圖解析器,它根據(jù)視圖名稱直接查找Spring容器中的同名Bean作為視圖對象。這種方式的好處在于簡單直觀,當(dāng)視圖名稱與Bean名稱一一對應(yīng)時,可以快速地解析出視圖對象。

          2)BeanNameViewResolver工作原理

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

          3)BeanNameViewResolver的適用場景

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

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

          4)總結(jié)

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

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

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

          (3)InteranlResourceViewResolver

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

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

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

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

          3.1.2 自動配置的靜態(tài)資源

          一般客戶端發(fā)送請求到web服務(wù)器,web服務(wù)器從內(nèi)存在取到相應(yīng)的文件,返回給客戶端,客戶端解析并渲染顯示出來。

          例如:css,js等文件。

          (1)使用webjar實現(xiàn)

          SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 這個配置類里面,默認(rèn)為我們提供了靜態(tài)資源處理。

          我們進(jìn)入WebMvcAutoConfigurationAdapter源碼里面進(jìn)行查看,發(fā)現(xiàn)有這么一個方法: addResourceHandlers 添加資源處理;

          @Override
          public void addResourceHandlers(ResourceHandlerRegistry registry) {
                  if (!this.resourceProperties.isAddMappings()) {
          // 已禁用默認(rèn)資源處理
                  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));
                  }
          // 靜態(tài)資源配置
                  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/ 找對應(yīng)的資源; 什么是webjars 呢?

          Webjars本質(zhì)就是以jar包的方式引入我們的靜態(tài)資源 。

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

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

          WebJars是將這些通用的Web前端資源打包成Java的Jar包,然后借助Maven工具對其管理,保證這些Web資源版本唯一性,升級也比較容易。關(guān)于webjars資源,有一個專門的網(wǎng)站https://www.webjars.org/,我們可以到這個網(wǎng)站上找到自己需要的資源,在自己的工程中添加入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內(nèi)訪問靜態(tài)資源可以使用如下方式:

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

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

          ResourceProperties類部分源碼

          @ConfigurationProperties(
            prefix = "spring.resources",
            ignoreUnknownFields = false
          )
          public class ResourceProperties {
            //springboot默認(rèn)的加載路徑
            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;
          

          映射規(guī)則總結(jié)

          在springboot靜態(tài)資源加載規(guī)則中,除了”標(biāo)準(zhǔn)“靜態(tài)資源位置之外,還有一個較為特殊的WebJars “標(biāo)準(zhǔn)”靜態(tài)資源映射規(guī)則。 所有的“/**”的請求,如果沒有對應(yīng)的處理,那么就去默認(rèn)映射的靜態(tài)資源目錄下去找,如下所示:

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

          (3)SpringBoot配置靜態(tài)資源

          1)通過配置文件配置

          配置節(jié)點:spring.web.resources.static-locations

          值為要配置的靜態(tài)資源存放目錄

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

          以上配置中,設(shè)置靜態(tài)資源目錄為src/main/resources/test/目錄。

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

          2) 通過config類配置

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

          重寫WebMvcConfigurationSupport類的addResourceHandlers方法。

          通過參數(shù)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訪問文件內(nèi)容

          區(qū)別:

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

          共同點:

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

          3.1.3 自動配置的Formatter和Conventer

          只要我們定義了Converter,GenericConverter和Formatter接口的實現(xiàn)類的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 靜態(tài)首頁的支持

          將靜態(tài)首頁index.html文件放置在如下目錄:

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

          3.2 接管SpringBoot的Web配置

          • 可以通過一個配置類(注解有@Configuration的類)加上@EnableWebMvc注解來實現(xiàn)自己控制的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,F(xiàn)ilter,Listener

          當(dāng)使用嵌入式Servlet容器(Tomcat,Jetty等)時,通過將Servlet,F(xiàn)ilter,Listener生命為Spring Bean來達(dá)到注冊的效果,或者注冊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 項目中,可以內(nèi)置 TomcatJettyUndertowNetty 等服務(wù)器容器。當(dāng)我們添加了 spring-boot-starter-web 依賴后,默認(rèn)會使用 Tomcat 作為 Web 容器。

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

          @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做一些基礎(chǔ)性的設(shè)置,查看下面的配置類可以知道,這些屬性存在默認(rèn)值;

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

          4.2.2 常用配置

          #端口號,默認(rèn)8080
          server.port = 80
           
          #服務(wù)器綁定的網(wǎng)絡(luò)地址,默認(rèn)0.0.0.0,允許通過所有IPv4地址進(jìn)行連接
          server.address = yourIp
           
          #標(biāo)準(zhǔn)錯誤網(wǎng)頁,Whitelabel。它默認(rèn)啟用,可以關(guān)閉
          server.error.whitelabel.enabled = false
           
          #Whitelabel默認(rèn)路徑是/error,可以通過設(shè)置server.error.path參數(shù)來自定義它
          server.error.path = /user-error
           
          #設(shè)置屬性,以確定顯示有關(guān)錯誤的信息。可以包含錯誤消息和堆棧跟蹤
          server.error.include-exception= true
          server.error.include-stacktrace= always
           
          #工作線程的最大數(shù)量
          server.tomcat.max-threads= 200
           
          #設(shè)置服務(wù)器連接超時時間
          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協(xié)議
          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
           
          #定義標(biāo)識密鑰庫中密鑰的別名
          server.ssl.key-alias=tomcat
           
          #啟用訪問日志
          server.tomcat.accesslog.enabled = true
           
          #配置參數(shù),如附加到日志文件的目錄名,前綴,后綴和日期格式
          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依賴?yán)锱懦齌omcat。這可以通過<exclusions>標(biāo)簽實現(xiàn)。

          <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>

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

          # 端口配置
          server.port=8081
          
          # 啟動線程數(shù)
          server.jetty.acceptors=2
          
          # Selector線程數(shù)
          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
          
          # 請求和響應(yīng)緩沖區(qū)大小
          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:
            # 服務(wù)器的HTTP端口,默認(rèn)為80
            port: 80
            servlet:
              # 應(yīng)用的訪問路徑
              context-path: /
            # undertow 配置
            undertow:
              # HTTP post內(nèi)容的最大大小。當(dāng)值為-1時,默認(rèn)值為大小是無限的
              max-http-post-size: -1
              # 以下的配置會影響buffer,這些buffer會用于服務(wù)器連接的IO操作,有點類似netty的池化內(nèi)存管理
              # 每塊buffer的空間大小,越小的空間被利用越充分
              buffer-size: 512
              # 是否分配的直接內(nèi)存
              direct-buffers: true
              threads:
                # 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會負(fù)責(zé)多個連接, 默認(rèn)設(shè)置每個CPU核心一個線程
                io: 8
                # 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類似servlet請求阻塞操作, undertow會從這個線程池中取得線程,它的值設(shè)置取決于系統(tǒng)的負(fù)載
                worker: 256

          4.4 SSL配置

          通過HTTP協(xié)議傳輸數(shù)據(jù),并不會對數(shù)據(jù)進(jìn)行加密,所以存在著一定的風(fēng)險,容易被抓包破解數(shù)據(jù),而且現(xiàn)在各種瀏覽器對使用HTTP協(xié)議的網(wǎng)站也會提示不安全。

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

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

          TLS與SSL在傳輸層與應(yīng)用層之間對網(wǎng)絡(luò)連接進(jìn)行加密。

          SSL協(xié)議位于TCP/IP協(xié)議與各種應(yīng)用層協(xié)議之間,為數(shù)據(jù)通訊提供安全支持。

          SSL協(xié)議可分為兩層:

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

          服務(wù)器認(rèn)證階段:

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

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

          3)客戶根據(jù)收到的服務(wù)器響應(yīng)信息,產(chǎn)生一個主密鑰,并用服務(wù)器的公開密鑰加密后傳給服務(wù)器;

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

          用戶認(rèn)證階段:

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

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

          • 機密性:SSL協(xié)議使用密鑰加密通信數(shù)據(jù)。
          • 可靠性:服務(wù)器和客戶都會被認(rèn)證,客戶的認(rèn)證是可選的。
          • 完整性:SSL協(xié)議會對傳送的數(shù)據(jù)進(jìn)行完整性檢查。

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

          4.4.1 配置證書

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

          依次填入以下內(nèi)容:

          mcat.key
          輸入密鑰庫口令:
          再次輸入新口令:
          您的名字與姓氏是什么?
            [Unknown]:  localhost
          您的組織單位名稱是什么?
            [Unknown]:  localhost
          您的組織名稱是什么?
            [Unknown]:  xxx Co,.Ltd
          您所在的城市或區(qū)域名稱是什么?
            [Unknown]:  KunShan
          您所在的省/市/自治區(qū)名稱是什么?
            [Unknown]:  SuZhou
          該單位的雙字母國家/地區(qū)代碼是什么?
            [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轉(zhuǎn)向https

          當(dāng)用戶使用http訪問的時候,將http協(xié)議重定向到https端口

          (1)修改配置文件

          custom:  # 自定義http啟動端口
            http-port: 8089
          配置
          server:
            port: 8090 #端口配置  
            ssl: #ssl配置
              enabled: true  # 默認(rèn)為true
              #key-alias: alias-key # 別名(可以不進(jìn)行配置)
              # 保存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請求全部轉(zhuǎn)發(fā)到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請求轉(zhuǎn)換為https請求
                  TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
                      @Override
                      protected void postProcessContext(Context context) {
                          SecurityConstraint constraint = new SecurityConstraint();
                          // 默認(rèn)為NONE
                          constraint.setUserConstraint("CONFIDENTIAL");
                          SecurityCollection collection = new SecurityCollection();
                          // 所有的東西都https
                          collection.addPattern("/*");
                          constraint.addCollection(collection);
                          context.addConstraint(constraint);
                      }
                  };
                  tomcat.addAdditionalTomcatConnectors(httpConnector());
                  return tomcat;
              }
          
              /**
               * 強制將所有的http請求轉(zhuǎn)發(fā)到https
               * @return httpConnector
               */
              @Bean
              public Connector httpConnector() {
                  Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
                  connector.setScheme("http");
                  // connector監(jiān)聽的http端口號
                  connector.setPort(httpPort);
                  connector.setSecure(false);
                  // 監(jiān)聽到http的端口號后轉(zhuǎn)向到的https的端口號
                  connector.setRedirectPort(port);
                  return connector;
              }
          }
          

          4.5 Favicon配置

          4.5.1 默認(rèn)的Favicon

          Spring Boot提供了一個默認(rèn)的Favicon,每次訪問應(yīng)用的時候都能看到,如圖所示。



          4.5.2 關(guān)閉Favicon

          我們可以在application.properties中設(shè)置關(guān)閉Favicon,默認(rèn)為開啟。

          spring.mvc.favicon.enabled=false

          4.5.3 設(shè)置自己的Favicon

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

          注意:配置文件不要配置spring.mvc.static-path-pattern參數(shù),否則不能看到Favicon圖標(biāo)

          4.6 WebSocket

          4.6.1 什么是WebSocket?

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

          WebSocket 的一些關(guān)鍵特點包括:

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

          4.6.2 代碼實戰(zhàn)

          (1)SpringBoot導(dǎo)入依賴

          在pom.xml中導(dǎo)入以下依賴,版本由SpringBoot管理

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

          (2)創(chuàng)建配置類

          創(chuàng)建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)創(chuàng)建WebSocketServer類

          創(chuàng)建WebSocketServer類,并將其注入到Bean容器中

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

          該類一般擁有以下功能:

          1. WebSocket 端點注冊: WebSocket 服務(wù)器需要注冊一個或多個 WebSocket 端點(Endpoints)。每個端點對應(yīng)一種處理邏輯,可以處理客戶端發(fā)送過來的消息,以及向客戶端發(fā)送消息。這些端點通過注解或配置來定義。
          2. 建立和維護(hù)連接: WebSocket 服務(wù)器負(fù)責(zé)監(jiān)聽客戶端的連接請求,一旦有客戶端連接,服務(wù)器會創(chuàng)建一個 WebSocket 會話(Session)來管理這個連接。服務(wù)器需要能夠維護(hù)這些連接,包括打開、關(guān)閉、保持心跳等操作。
          3. 消息處理: 一旦客戶端連接成功,WebSocket 服務(wù)器需要處理客戶端發(fā)送過來的消息。這可以在 WebSocket 端點中的方法上定義處理邏輯。服務(wù)器可以根據(jù)不同的業(yè)務(wù)需求處理不同類型的消息。
          4. 處理異常: 與任何網(wǎng)絡(luò)通信一樣,WebSocket 連接可能會面臨各種異常情況,如斷開連接、網(wǎng)絡(luò)問題等。WebSocket 服務(wù)器需要能夠處理這些異常情況,進(jìn)行適當(dāng)?shù)那謇砗吞幚怼?/span>

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

          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連接關(guān)閉");
              }
           
              @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發(fā)生錯誤", session.getId(), error);
              }
           
              public Session getSession() {
                  return session;
              }
           
              public String getSessionId() {
                  return session.getId();
              }
          }

          (4)創(chuàng)建WebSocketServer管理類

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

          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發(fā)送消息給特定用戶
               * @param
               * @param msg
               */
              public static void sentToUser(String sessionId, String msg){
                  Session session = webSocketServerMap.get(sessionId).getSession();
                  sentToUser(session, msg);
              }
           
              /**
               * 通過Session發(fā)送消息給特定用戶
               * @param session
               * @param msg
               */
              public static void sentToUser(Session session, String msg){
                  if (session == null){
                      log.error("不存在該Session,無法發(fā)送消息");
                      return;
                  }
                  session.getAsyncRemote().sendText(msg);
              }
           
              /**
               * 發(fā)送消息給所有用戶
               * @param msg
               */
              public static void sentToAllUser(String msg){
                  for (WebSocketServer webSocketServer : webSocketServerSet) {
                      sentToUser(webSocketServer.getSession(), msg);
                  }
                  log.info("向所有用戶發(fā)送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);
                      //發(fā)現(xiàn)消息進(jìn)入,開始處理前端觸發(fā)邏輯
                  };
                  //關(guān)閉事件
                  socket.onclose = function() {
                      console.log("websocket已關(guān)閉");
                  };
                  //發(fā)生了錯誤事件
                  socket.onerror = function() {
                      console.log("websocket發(fā)生了錯誤");
                  }
              }
              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>【客戶端向服務(wù)器發(fā)送的內(nèi)容】:<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()">發(fā)送消息</a></div>
          </body>
           
          </html>

          5 基于Bootstarp和AngularJS的現(xiàn)代Web應(yīng)用

          現(xiàn)代的B/S系統(tǒng)軟件有下面幾個特色。

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

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

          3.數(shù)據(jù)導(dǎo)向 數(shù)據(jù)導(dǎo)向是對于頁面導(dǎo)向而言的,頁面上的數(shù)據(jù)獲得是通過消費后臺的REST服務(wù)來實現(xiàn)的,而不是通過服務(wù)器渲染的動態(tài)頁面(如JSP)來實現(xiàn)的,一般數(shù)據(jù)交換使用的格式是JSON。 本節(jié)將針對Bootstrap 和 AngularJS 進(jìn)行快速入門式的引導(dǎo),如需深入學(xué)習(xí),請參考官網(wǎng)或相關(guān)專題書籍。

          5.1 Bootstrap

          1.什么是Bootstrap Bootstrap官方定義:Bootstrap是開發(fā)響應(yīng)式和移動優(yōu)先的Web應(yīng)用的最流行的HTML、CSS、JavaScript框架。

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

          下載的壓縮包的目錄結(jié)構(gòu)如圖

          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標(biāo)簽必須是head 的頭三個標(biāo)簽,其余的head內(nèi)標(biāo)簽在此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樣式為基礎(chǔ)的HTML元素提供了美觀的樣式,此外還提供了一個高級的網(wǎng)格系統(tǒng)用來做頁面布局。

          (1)布局網(wǎng)格 在Bootstrap里,行使用的樣式為row,列使用col-md-數(shù)字,此數(shù)字范圍為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元素提供了大量的樣式,如表單元素、按鈕、圖標(biāo)等。更多內(nèi)容請查看:http://getbootstrap.com/css/。

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

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

          5.2 AngularJS

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

          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的前端數(shù)據(jù)模型,模型的名稱為yourName,模型的值來自你輸入的值若輸入的值改變,則數(shù)據(jù)模型值也會變 -->
          	<hr>
          	<h1>你好{{yourName}}!</h1><!-- 使用{{模型名}}來讀取模型中的值。 -->
          </div>
          </body>
          </html>
          

          3.模塊、控制器和數(shù)據(jù)綁定

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

          無依賴模塊:

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

          有依賴模塊

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

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

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

          4.Scope和Event

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

          定義:

          $scope.greeting='Hello'

          獲取

          {{greeting}}

          (2)Event

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

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

          父Scope接受:

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

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

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

          子scope接受

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

          5.多視圖和路由

          多視圖和路由是AngularJS實現(xiàn)單頁面應(yīng)用的技術(shù)關(guān)鍵,AngularJS內(nèi)置了一個$routeProvider對象來負(fù)責(zé)頁面加載和頁面路由轉(zhuǎn)向。 需要注意的是,1.2.0之后的AngularJS將路由功能移出,所以使用路由功能要另外引入angular-route.js 例如

          angular.module('firstModule').config(function($routeProvider){
          $routeProvider.when('/view1,{  //此處定義的是某個頁面的路由名稱
          	controller:'Controller1',   //此處定義的是當(dāng)前頁面使用的控制器。
          	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>  <!--此處為加載進(jìn)來的頁面顯示的位置  -->
          

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

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

          7.Service和Factory

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

          定義:

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

          注入調(diào)用:

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

          注入調(diào)用:

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

          8.http操作

          AngularJS內(nèi)置了$http對象用來進(jìn)行Ajax的操作:

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

          9.自定義指令

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

          元素指令:<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>
          };
          });

          調(diào)用指令,元素標(biāo)簽:

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

          或者屬性方式

          <div hello-world />

          5.3 實戰(zhàn)

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

          1.新建Spring Boot項目

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

          準(zhǔn)備Bootstrap、AngularJS、jQuery、jQueryUI相關(guān)的資源到 src/main/resources/static 下,結(jié)構(gòu)如圖



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

          2.制作導(dǎo)航

          頁面位置: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>實戰(zhàn)</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定義的導(dǎo)航,并配合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監(jiān)聽$viewContentLoaded事件,可以在頁面內(nèi)容加載完成后進(jìn)行一些操作。
          	$scope.$on('$viewContentLoaded',function(){
          		console.log('頁面加載完成');
          	});
          	//這段代碼是核心 代碼,請結(jié)合下面的View1的界面一起理解
          	$scope.search=function(){  //在scope內(nèi)定義一個方法search,在頁面上通過ng-click調(diào)用。
          		personName = $scope.personName;        //通過$scope.personName獲取頁面定義的ng-model = "personName" 的值。
          		$http.get('search',{                 //使用$http.get向服務(wù)器地址search發(fā)送get請求。
          			  		params:{personName:personName}   //使用params增加請求參數(shù)
          		}).success(function(data){                   //用success方法作為請求成功后的回調(diào)。
          			$scope.person=data;                     //將服務(wù)端返回的數(shù)據(jù)data通過$scope.person賦給模型person,這樣頁面視圖上可以通過{{person.name}}、{{person.age}}、{{person.address}}來調(diào)用,且模型person值改變后,視圖是自動更新的
          		});
          	};
          }]);
          
          actionApp.controller('View2Controller',['$rootScope','$scope',function($rootScope,$scope){
          	$scope.$on('$viewContentLoaded',function(){
          		console.log('頁面加載完成');
          	});
          }]);

          5.View1的界面(演示與服務(wù)端交互) 頁面位置 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">
          		<!-- 定義數(shù)據(jù)模型 ng-model="personName" -->
          		<input type="text" class="form-control" ng-model="personName">
          	</div>
          	<div class="col-md-1">
          	<!-- 通過ng-click="search()"調(diào)用控制器中定義的方法 -->
          	<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.服務(wù)端代碼

          傳值對象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方法內(nèi)可使用當(dāng)前scope、當(dāng)前元素及元素屬性。
          			elem.datepicher();				//初始化jqueryui的datePicker(jquery的寫法是$('#id').datePicker()).
          		}
          	};
          });

          通過上面的代碼我們就定制了一個封裝jqueryui的datePicker的指令,本例只是為了演示的目的,主流的腳本框架已經(jīng)被很多人封裝過了,有興趣的讀者可以訪問http://ngmodules.org/網(wǎng)站,這個網(wǎng)站包含了大量的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">
                  <!-- 使用屬性形式調(diào)用指令 -->
                  <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">
                  <!-- 使用樣式形式調(diào)用指令 -->
                  <input type="text" class="form-control date-picker"
              </div>
          </div>

          9.運行

          菜單及路由切換如圖



          與后臺交互如圖

          自定義指定如圖

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

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

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

          3、通過File API 瀏覽器可以直接訪問用戶計算機的沙箱區(qū)域,將數(shù)據(jù)存儲到文件系統(tǒng);

          4、在HTML5中Forms API得到了發(fā)展,內(nèi)置了驗證功能;

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

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

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

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

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

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

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

          以上是HTML5大前端中新加入的一些比較常用的功能API,如果想要系統(tǒng)的了解以及學(xué)習(xí)HTML5的新功能,可以選擇千鋒重慶校區(qū)的HTML5大前端課程。其課程將一線互聯(lián)網(wǎng)企業(yè)前沿技術(shù)遷移課堂,讓學(xué)員通過深度學(xué)習(xí),切實掌握實戰(zhàn)技術(shù),助力學(xué)員開啟成功職場生涯。


          主站蜘蛛池模板: 性色AV一区二区三区天美传媒| 一区 二区 三区 中文字幕| 精品一区二区三区视频| 国产免费一区二区三区在线观看| 手机福利视频一区二区| 国产在线精品一区二区三区不卡 | 麻豆一区二区三区蜜桃免费| 老熟妇仑乱一区二区视頻| 国模无码人体一区二区| 色狠狠一区二区三区香蕉蜜桃| 精品日产一区二区三区手机| 无码少妇一区二区| 一区高清大胆人体| 国产精品视频一区二区三区四| 视频一区二区三区人妻系列| 国产日韩精品一区二区在线观看| 成人国产精品一区二区网站公司| 亚洲色婷婷一区二区三区| 久久久久国产一区二区| 亚洲日韩精品无码一区二区三区| 无码精品蜜桃一区二区三区WW| 在线视频亚洲一区| 无码一区二区三区中文字幕| 精品亚洲av无码一区二区柚蜜| 亲子乱av一区区三区40岁| 亚洲AV一区二区三区四区| 国产精品资源一区二区| 日本人的色道www免费一区| 性色AV一区二区三区无码| 日韩精品一区二区三区在线观看l 日韩精品一区二区三区毛片 | 国产精品区一区二区三在线播放 | 国产精品日本一区二区不卡视频| 无人码一区二区三区视频| 久久精品亚洲一区二区| 无码一区18禁3D| 在线电影一区二区| 性色AV 一区二区三区| 日本大香伊一区二区三区| 亚洲AV午夜福利精品一区二区| 夜色福利一区二区三区| 国产日本亚洲一区二区三区|