官术网_书友最值得收藏!

  • Spring實戰(第6版)
  • (美)克雷格·沃斯
  • 5187字
  • 2022-12-20 19:14:49

因為我們剛剛開始,所以首先為Taco Cloud應用做一些小的變更,但是這些變更會展現Spring的很多優點。在剛開始的時候,比較合適的做法是為Taco Cloud應用添加一個主頁。在添加主頁時,我們將會創建兩個代碼構件:

一個控制器類,用來處理主頁相關的請求;

一個視圖模板,用來定義主頁看起來是什么樣子。

測試是非常重要的,所以我們還會編寫一個簡單的測試類來測試主頁。但是,要事優先,我們需要先編寫控制器。

Spring自帶了一個強大的Web框架,名為Spring MVC。Spring MVC的核心是控制器(controller)的理念。控制器是處理請求并以某種方式進行信息響應的類。在面向瀏覽器的應用中,控制器會填充可選的數據模型并將請求傳遞給一個視圖,以便于生成返回給瀏覽器的HTML。

在第2章中,我們將會學習更多關于Spring MVC的知識。現在,我們會編寫一個簡單的控制器類以處理來自根路徑(如“/”)的請求,并將這些請求轉發至主頁視圖,在這個過程中不會填充任何的模型數據。程序清單1.4展示了這個簡單的控制器類。

程序清單1.4 主頁控制器

package tacos;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller  ?---控制器
public class HomeController {
  @GetMapping("/")  ?---處理對根路徑“/ ”的請求
  public String home() {
    return "home";  ?---返回視圖名
  }

}

可以看到,這個類帶有@Controller注解。就其本身而言,@Controller并沒有做太多的事情。它的主要目的是讓組件掃描將這個類識別為一個組件。因為HomeController帶有@Controller注解,所以Spring的組件掃描功能會自動發現它,并創建一個HomeController實例作為Spring應用上下文中的bean。

實際上,有一些其他的注解與@Controller有著類似的目的(包括@Component、@Service和@Repository)。你可以為HomeController添加上述的任意其他注解,其作用是完全相同的。但是,在這里選擇使用@Controller更能描述這個組件在應用中的角色。

home()是一個簡單的控制器方法。它帶有@GetMapping注解,表明如果針對“/”發送HTTP GET請求,那么將會由這個方法來處理請求。該方法所做的只是返回String類型的home值。

這個值將會解析為視圖的邏輯名。視圖如何實現取決于多個因素,但是Thymeleaf位于類路徑中,使得我們可以使用Thymeleaf來定義模板。

為何使用Thymeleaf?

你可能會想:為什么要選擇Thymeleaf作為模板引擎?為何不使用JSP?為何不使用FreeMarker?為何不選擇其他的幾個可選方案呢?

簡單來說,我必須要做出選擇,我喜歡Thymeleaf,相對于其他的方案,我會優先使用它。即便JSP是更加顯而易見的選擇,但是組合使用JSP和Spring Boot需要克服一些挑戰。我不想脫離第1章的內容定位,所以就此打住。在第2章中,我們會看到其他的模板方案,其中也包括JSP。

模板名稱是由邏輯視圖名派生而來的,再加上“/templates/”前綴和“.html”后綴。最終形成的模板路徑將是“/templates/home.html”。所以,我們需要將模板放到項目的“/src/main/resources/templates/home.html”中。現在,就讓我們來創建這個模板。

為了讓主頁盡可能簡單,主頁除了歡迎用戶訪問站點之外,不會做其他的任何事情。程序清單1.5展現了基本的Thymeleaf模板,定義了Taco Cloud的主頁。

程序清單1.5 Taco Cloud主頁模板

<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
      xmlns:th = "http://www.thymeleaf.org">
  <head>
    <title>Taco Cloud</title>
  </head>

  <body>
    <h1>Welcome to...</h1>
    <img th:src = "@{/images/TacoCloud.png}"/>
  </body>
</html>

這個模板并沒有太多需要討論的。唯一需要注意的是用于展現Taco Cloud Logo的<img>標簽。它使用了Thymeleaf的th:src屬性和@{...}表達式,以便于引用相對于上下文路徑的圖片。除此之外,這個主頁就是一個扮演“Hello World”角色的頁面。

我們再討論一下這個圖片。我將定義Taco Cloud Logo的工作留給你,但是你需要將它放到應用的正確位置。

圖片是使用相對于上下文的“/images/TacoCloud.png”路徑來引用的。回憶一下我們的項目結構,像圖片這樣的靜態資源位于“/src/main/resources/static”文件夾。這意味著,在項目中Taco Cloud Logo的圖片路徑必須為“/src/main/resources/static/images/ TacoCloud.png”。

現在,我們有了一個處理主頁請求的控制器和渲染主頁的模板,基本就可以啟動應用來看一下它的效果了。但是,在此之前,我們先看一下如何為控制器編寫測試。

在測試Web應用時,對HTML頁面的內容進行斷言是比較困難的。幸好,Spring對測試提供了強大的支持,這使得測試Web應用變得非常簡單。

對于主頁來說,我們所編寫的測試在復雜性上與主頁本身差不多。測試需要針對根路徑“/”發送一個HTTP GET請求并期望得到成功結果,其中視圖名稱為home并且結果內容包含“Welcome to...”。程序清單1.6就能夠完成該任務。

程序清單 1.6 針對主頁控制器的測試

package tacos;

import static org.hamcrest.Matchers.containsString;
import static
     org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static
     org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static
     org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static
     org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest(HomeController.class)  ?---針對HomeController的Web測試
public class HomeControllerTest {

  @Autowired
  private MockMvc mockMvc;  ?---注入MockMvc

  @Test
  public void testHomePage() throws Exception {
    mockMvc.perform(get("/"))  ?---發起對“/”的GET請求
      .andExpect(status().isOk())  ?---期望得到HTTP 200
      .andExpect(view().name("home"))  ?---期望得到home視圖
      .andExpect(content().string(  ?---期望包含“Welcome to...”
          containsString("Welcome to...")));
  }

}

對于這個測試,首先注意到的可能就是它使用了與TacoCloudApplicationTests類不同的注解。HomeControllerTest沒有使用@SpringBootTest標記,而是添加了@WebMvcTest注解。這是Spring Boot提供的一個特殊測試注解,讓這個測試在Spring MVC應用的上下文中執行。更具體來講,在本例中,它會將HomeController注冊到Spring MVC中,這樣一來,我們就可以向它發送請求了。

@WebMvcTest同樣會為測試Spring MVC應用提供了Spring環境的支持。盡管可以啟動一個服務器來進行測試,但是對于我們的場景來說,仿造一下Spring MVC的運行機制就可以。測試類被注入了一個MockMvc,能夠讓測試實現mockup。

通過testHomePage()方法,我們定義了針對主頁想要執行的測試。它首先使用MockMvc對象對“/”(根路徑)發起HTTP GET請求。對于這個請求,我們設置了如下的預期:

響應應該具備HTTP 200 (OK)狀態;

視圖的邏輯名稱應該是home;

渲染后的視圖應該包含文本“Welcome to....”。

我們可以在所選的IDE中運行測試,也可以使用如下的Maven命令:

$ mvnw test

如果在MockMvc對象發送請求之后,上述預期沒有全部滿足,那么這個測試會失敗。但是,我們的控制器和視圖模板在編寫時都滿足了這些預期,所以測試應該能夠通過,并且帶有成功的圖標——至少能夠看到一些綠色的背景,表明測試通過了。

控制器已經編寫好了,視圖模板也已經創建完畢,而且我們還通過了測試。看上去,我們已經成功實現了主頁。但是,盡管測試已經通過了,但是如果能夠在瀏覽器中看到結果,會更有成就感。畢竟,這才是Taco Cloud的客戶所能看到的效果。接下來,我們構建應用并運行它。

就像初始化Spring應用有多種方式一樣,運行Spring應用也有多種方式。你如果愿意,可以翻到本書附錄部分,了解運行Spring Boot應用的一些通用方式。

因為我們選擇了使用Spring Tool Suite來初始化和管理項目,所以可以借助名為Spring Boot Dashboard的便捷功能來幫助我們在IDE中運行應用。Spring Boot Dashboard的表現形式是一個Tab,通常會位于IDE窗口的左下角附近。圖1.7展現了一個帶有標注的Spring Boot Dashboard截屏。

1-7

圖1.7 Spring Boot Dashboard的重點功能

圖1.7包含了一些有用的細節,但是我不想花太多時間介紹Spring Boot Dashboard支持的所有功能。對我們來說,現在最重要的事情是需要知道如何使用它來運行Taco Cloud應用。確保taco-cloud應用程序在項目列表中能夠顯示(這是圖1.7中顯示的唯一應用),然后單擊啟動按鈕(最左邊的按鈕,也就是帶有綠色三角形和紅色正方形的按鈕)。應用程序應該就能立即啟動。

在應用啟動的過程中,你會在控制臺看到一些Spring ASCII碼,隨后會是描述應用啟動各個步驟的日志條目。在控制臺輸出的最后,你將會看到一條日志顯示Tomcat已經在port(s): 8080 (http)啟動,這意味著此時可以打開Web瀏覽器并導航至主頁,看到我們的勞動成果。

稍等一下!剛才說啟動Tomcat?我們是什么時候將應用部署到Tomcat Web服務器的呢?

Spring Boot應用的習慣做法是將所有它所需要的東西都放到一起,沒有必要將其部署到某種應用服務器中。在這個過程中,我們根本沒有將應用部署到Tomcat中——Tomcat是我們應用的一部分!(在1.3.6小節,我會詳細描述Tomcat是如何成為我們應用的一部分的。)

現在,應用已經啟動起來了,打開Web瀏覽器并訪問http://localhost:8080 (或者在Spring Boot Dashboard中點擊地球樣式的按鈕),你將會看到如圖1.8所示的界面。如果你設計了自己的Logo圖片,顯示效果可能會有所不同。但是,跟圖1.8相比,應該不會有太大的差異。

1-8

圖1.8 Taco Cloud主頁

看上去,似乎并不太美觀,但本書不是關于平面設計的,略顯簡陋的主頁外觀已經足夠了。

到現在為止,我一直沒有提及DevTools。在初始化項目的時候,我們將其作為一個依賴添加了進來。在最終生成的pom.xml文件中,它表現為一個依賴項。甚至Spring Boot Dashboard都顯示項目啟用了DevTools。那么,DevTools到底是什么,又能為我們做些什么呢?接下來,讓我們快速瀏覽一下DevTool最有用的一些特性。

顧名思義,DevTools為Spring開發人員提供了一些便利的開發期工具和特性,其中包括:

代碼變更后應用會自動重啟;

當面向瀏覽器的資源(如模板、JavaScript、樣式表)等發生變化時,會自動刷新瀏覽器;

自動禁用模板緩存;

如果使用H2數據庫,則內置了H2控制臺。

需要注意,DevTools并不是IDE插件,也不需要你使用特定的IDE。在Spring Tool Suite、IntelliJ IDEA和NetBeans中,它都能很好地運行。另外,因為它的用途僅僅是開發,所以它能夠很智能地在生產環境中把自己禁用掉。我們將會在第18章討論它是如何做到這一點的。現在,我們主要關注Spring Boot DevTools最有用的特性,那么先從應用的自動重啟開始吧。

應用自動重啟

如果將DevTools作為項目的一部分,那么你可以看到,當對項目中的Java代碼和屬性文件作出修改后,這些變更稍后就能發揮作用。DevTools會監控變更,在看到變化的時候自動重啟應用。

更準確地說,當DevTools啟用的時候,應用程序會加載到Java虛擬機(Java Virtual Machine,JVM)中的兩個獨立的類加載器中。其中一個類加載器會加載Java代碼、屬性文件,以及項目的“src/main/”路徑下幾乎所有的內容。這些條目很可能會經常發生變化。另外一個類加載器會加載依賴的庫,這些庫不太可能經常發生變化。

當探測到變更的時候,DevTools只會重新加載包含項目代碼的類加載器,并重啟Spring的應用上下文,在這個過程中,另外一個類加載器和JVM會原封不動。這個策略非常精細,但能減少應用啟動的時間。

這種策略的一個不足之處就是自動重啟無法反映依賴項的變化。這是因為包含依賴庫的類加載器不會自動重新加載。這意味著每當在構建規范中添加、變更或移除依賴的時候,為了讓變更生效,都要重新啟動應用。

瀏覽器自動刷新和禁用模板緩存

默認情況下,像Thymeleaf和FreeMarker這樣的模板方案在配置時,會緩存模板解析的結果,這樣一來,在為每個請求提供服務的時候,模板就不用重新解析了。在生產環境中,這是一種很好的方式,因為它會帶來一定的性能收益。

但是,在開發期,緩存模板就不太友好了。在應用運行的時候,如果緩存模板,刷新瀏覽器就無法看到模板變更的效果了。即便我們對模板做了修改,在應用重啟之前,緩存的模板依然會有效。

DevTools通過禁用所有模板緩存解決了這個問題。你可以對模板進行任意數量的修改,只需刷新一下瀏覽器就能看到結果。

如果你像我一樣,連瀏覽器的刷新按鈕都懶得點,希望在對代碼做出變更之后馬上就能在瀏覽器中看到結果,那么很幸運,DevTools有一些特殊的功能可以供我們使用。

DevTools會和你的應用程序一起,自動啟動一個LiveReload服務器。LiveReload服務器本身并沒有太大的用處。但是,當它與LiveReload瀏覽器插件結合起來的時候,就能夠在模板、圖片、樣式表、JavaScript等(實際上,幾乎涵蓋為瀏覽器提供服務的所有內容)發生變化的時候,自動刷新瀏覽器。

LiveReload有針對Google Chrome、Safari和Firefox的瀏覽器插件(這里要對Internet Explorer和Edge的支持者說聲抱歉)。請訪問LiveReload網站的Extensions頁面了解如何為你的瀏覽器安裝LiveReload。

內置的H2控制臺

雖然我們的項目還沒有使用數據庫,但是這種情況在第3章中就會發生變化。如果你使用H2數據庫進行開發,DevTools將會自動啟用H2控制臺,這樣一來,我們可以通過Web瀏覽器進行訪問。只需要讓瀏覽器訪問http://localhost:8080/h2-console,就能看到應用所使用的數據。

此時,我們已經編寫了一個非常簡單卻很完整的Spring應用。在本書接下來的章節中,我們將會不斷擴展它。但現在,要回過頭來看一下我們都完成了哪些工作、Spring發揮了什么作用。

回想一下我們是怎樣完成這一切的。簡短來說,在構建基于Spring的Taco Cloud應用的過程中,我們執行了如下步驟:

使用Spring Initializr創建初始的項目結構;

編寫控制器類處理針對主頁的請求;

定義了一個視圖模板來渲染主頁;

編寫了一個簡單的測試類來驗證工作符合預期。

這些步驟都非常簡單直接,對吧?除了初始化應用的第一個步驟之外,我們所做的每一個操作都專注于生成主頁的目標。

實際上,我們所編寫的每行代碼都致力于實現這個目標。除了Java import語句之外,我只能在控制器中找到兩行Spring相關的代碼,而在視圖模板中,一行Spring相關的代碼都沒有。盡管測試類的大部分內容都使用了Spring對測試的支持,但是它在測試的運行環境中,似乎沒有那么強的侵入性。

這是使用Spring進行開發的一個重要優勢。你可以只關注滿足應用需求的代碼,無須考慮如何滿足框架的需求。盡管我們偶爾還是需要編寫一些框架特定的代碼,但是它們通常只占整個代碼庫很小的一部分。正如我在前文所述,Spring(以及Spring Boot)可以視為感受不到框架的框架(frameworkless framework)。

但是,這一切到底是如何運行起來的呢?Spring在幕后做了些什么來保證應用的需求能夠得到滿足?要理解Spring到底做了些什么,我們首先來看一下構建規范。

在pom.xml文件中,我們聲明了對Web和Thymeleaf starter的依賴。這兩項依賴會傳遞引入大量其他的依賴,包括:

Spring的MVC框架;

嵌入式的Tomcat;

Thymeleaf和Thymeleaf布局方言。

它還引入了Spring Boot的自動配置庫。當應用啟動的時候,Spring Boot的自動配置將會探測到這些庫,并自動完成如下功能:

在Spring應用上下文中配置bean以啟用Spring MVC;

在Spring應用上下文中配置嵌入式的Tomcat服務器;

配置Thymeleaf視圖解析器以便于使用Thymeleaf模板渲染Spring MVC視圖。

簡言之,自動配置功能完成了所有的臟活累活,讓我們能夠集中精力編寫實現應用功能的代碼。如果你問我的觀點,我認為這是一個很好的安排!

我們的Spring之旅才剛剛開始。Taco Cloud應用程序只涉及了Spring所提供功能的一小部分。在開始下一步之前,我們先整體了解一下Spring,看看在我們的路途中都會有哪些地標。

主站蜘蛛池模板: 彭泽县| 铅山县| 萝北县| 泰和县| 柳林县| 云龙县| 吉水县| 平乐县| 雅江县| 朝阳市| 封丘县| 阿拉善右旗| 浪卡子县| 庆元县| 布拖县| 富蕴县| 宿州市| 新田县| 榆林市| 西乌| 阿拉善右旗| 阳西县| 通城县| 桃江县| 隆安县| 柞水县| 开江县| 龙江县| 称多县| 措勤县| 绵阳市| 夏津县| 吴桥县| 开远市| 平昌县| 含山县| 阿拉尔市| 孟津县| 铜鼓县| 定日县| 桦南县|