全球10萬+開發者使用的《Spring實戰》第5版出版啦!

《Spring實戰》第5版本書是一本經典而實用的暢銷Spring學習指南。這本書就相當於是關於Spring的新華字典,第5版涵蓋了Spring 5.0和Spring Boot 2.0里程碑式的更新。全書分為5個部分,共19章。第1部分(第1~5章)涵蓋了構建Spring應用的基礎話題。第2部分(第6~9章)討論如何將Spring應用與其他應用進行集成。第3部分(第10~12章)探討Spring對反應式編程提供的全新支持。第4部分(第13~15章)拆分單體應用模型,介紹Spring Cloud和微服務開發。第5部分(第16~19章)討論如何為應用投入生產環境做準備以及如何進行部署。


全球10萬+開發者使用的《Spring實戰》第5版出版啦!

Spring 5更新了哪些內容?

Spring 5的主要功能是對反應式編程的支持,包括Spring WebFlux。這是一個全新的反應式Web框架,借鑑了Spring MVC的編程模型,允許開發人員創建伸縮性更好且耗用更少線程的Web應用程序。至於Spring應用的後端,最新版本的Spring Data支持創建反應式、非阻塞的數據repository。所有這些都構建在Reactor項目之上,Reactor是一個用於處理反應式類型的Java庫。

除了Spring 5新的反應式編程特性之外,Spring Boot 2提供了比以前更多的自動配置支持,以及一個完全重新設計的Actuator,用於探查和操作正在運行的應用。

更重要的是,當開發人員希望將單體應用拆分為分散的微服務時,Spring Cloud提供了一些工具,使配置和發現微服務變得容易,並增強了微服務的功能,使它們更能抵禦失敗。

針對學習者的建議

如果你是經驗豐富的老手,《Spring實戰(第5版)》可以作為指南,指導你去學習Spring提供的新功能;如果你是Spring新手,那麼現在是行動起來的最佳時機,本書的前幾章會讓你快速上手!


《Spring實戰》(第5版)學習路線圖

本書分成了5個部分,共計19章。

第1部分涵蓋構建Spring應用的基礎話題。

  • 第1章介紹Spring和Spring Boot以及如何初始化Spring項目。在本章中,我們邁出構建Spring應用的第一步,在本書後續各章中,我們會對這個應用進行擴展。
  • 第2章討論如何使用Spring MVC構建應用的Web層。在本章中,我們將會構建處理Web請求的控制器以及在瀏覽器中渲染信息的視圖。
  • 第3章會深入探討Spring應用的後端,在這裡數據會持久化到關係型數據庫中。
  • 在第4章中,我們會使用Spring Security認證用戶並防止未認證的用戶訪問應用。
  • 第5章介紹如何使用Spring Boot的配置屬性功能來配置Spring應用。我們還會學習如何使用profile選擇性地應用配置。

第2部分討論如何將Spring應用與其他應用進行集成。

  • 第6章延續第2章對Spring MVC的討論,我們將會學習如何在Spring中編寫REST API。
  • 第7章討論和第6章相對立的主題,展現Spring應用如何消費REST API。
  • 第8章會討論如何使用異步通信技術讓Spring應用發送和接收消息,這裡會用到Java Message Service、RabbitMQ或Kafka。
  • 第9章討論如何使用Spring Integration進行聲明式的應用集成。

第3部分探討Spring對反應式編程提供的全新支持。

  • 第10章介紹Reactor項目。這是一個反應式編程庫,支撐了Spring 5的反應式特性。
  • 第11章重新探討REST API開發,介紹全新的Web框架Spring WebFlux。該框架借用了很多Spring MVC的理念,但是為Web開發提供了新的反應式模型。
  • 第12章將會看一下如何使用Spring Data編寫反應式數據持久化,我們將會讀取和寫入Cassandra與Mongo數據庫。

第4部分將會拆分單體應用模型,介紹Spring Cloud和微服務開發。

  • 第13章會深入介紹服務發現,組合使用Spring和Netflix的註冊中心實現Spring微服務的註冊和發現。
  • 第14章將展現如何在配置服務器中實現中心化的應用配置,從而實現跨微服務共享配置。
  • 第15章會介紹Hystrix的斷路器模式。它能夠讓微服務在面臨失敗時更有彈性。

在第5部分中,我們將會討論如何做好將應用投入生產環境的準備,並看一下如何進行部署。

  • 第16章會介紹Spring Boot Actuator。它是Spring Boot的一個擴展,通過REST端點的形式暴露Spring應用內部的運行狀況。
  • 第17章將會介紹如何使用Spring Boot Admin。它是構建在Actuator之上的一個用戶友好的基於瀏覽器的管理應用。
  • 第18章將會討論如何將Spring bean暴露為JMX MBean以及如何消費它們。
  • 在第19章中,我們會看到如何將Spring應用部署到各種生產環境中。

通常來講,剛剛接觸Spring的開發人員應該從第1章開始,並按順序閱讀每一章;經驗豐富的Spring開發人員可能更願意在任何感興趣的時候參與進來。即便如此,每一章都是建立在前一章的基礎上的,所以如果從中間開始閱讀,那麼可能會漏掉一些上下文信息。


樣章試讀:第2章 開發Web應用

本章內容:

在瀏覽器中展現模型數據

處理和校驗表單輸入

選擇視圖模板庫

第一印象是非常重要的:Curb Appeal能夠在購房者真正進門之前就將房子賣掉;如果一輛車噴成了櫻桃色,那麼它的油漆會比它的引擎更引人注目;文學作品中充滿了一見鍾情的故事。內在固然非常重要,但是外在的,也就是第一眼看到的東西同樣非常重要。

我們使用Spring所構建的應用會完成各種各樣的事情,包括處理數據、從數據庫中讀取信息以及與其他應用進行交互。但是,用戶對應用程序的第一印象來源於用戶界面。在很多應用中,UI是以瀏覽器中的Web應用的形式來展現的。

在第1章中,我們創建了第一個Spring MVC控制器來展現應用的主頁。但是,Spring MVC能做很多的事情,並不侷限於展現靜態內容。在本章中,我們將會開發Taco Cloud的第一個主要功能:設計定製taco的能力。在這個過程中,我們將會深入研究Spring MVC並會看到如何展現模型數據和處理表單輸入。

2.1 展現信息

從根本上來講,Taco Cloud是一個可以在線訂購taco的地方。但是,除此之外,Taco Cloud允許客戶展現其創意,能夠讓他們通過豐富的配料(ingredient)設計自己的taco。

因此,Taco Cloud需要有一個頁面為taco藝術家展現都可以選擇哪些配料。可選的配料可能隨時會發生變化,所以不能將它們硬編碼到HTML頁面中。我們應該從數據庫中獲取可用的配料並將其傳遞給頁面,進而展現給客戶。

在Spring Web應用中,獲取和處理數據是控制器的任務,而將數據渲染到HTML中並在瀏覽器中展現則是視圖的任務。為了支撐taco的創建頁面,我們需要構建如下組件。

  • 用來定義taco配料屬性的領域類。
  • 用來獲取配料信息並將其傳遞至視圖的Spring MVC控制器類。
  • 用來在用戶的瀏覽器中渲染配料列表的視圖模板。

這些組件之間的關係如圖2.1所示。

全球10萬+開發者使用的《Spring實戰》第5版出版啦!

圖2.1 典型的Spring MVC請求流

因為本章主要關注Spring的Web框架,所以我們會將數據庫相關的內容放到第3章中進行講解。現在的控制器只負責向視圖提供配料。在第3章中,我們會重新改造這個控制器,讓它能夠與repository協作,從數據庫中獲取配料數據。

在編寫控制器和視圖之前,我們首先確定一下用來表示配料的領域類型,它會為我們開發Web組件奠定基礎。

2.1.1 構建領域類

應用的領域指的是它所要解決的主題範圍:也就是會影響到對應用理解的理念和概念[1]。在Tao Cloud應用中,領域對象包括taco設計、組成這些設計的配料、顧客以及顧客所下的訂單。作為開始,我們首先關注taco的配料。

在我們的領域中,taco配料是非常簡單的對象。每種配料都有一個名稱和類型,以便於對其進行可視化的分類(蛋白質、奶酪、醬汁等)。每種配料還有一個ID,這樣的話對它的引用就能非常容易和明確。如下的Ingredient類定義了我們所需的領域對象。

程序清單2.1 定義taco配料

<code>package tacos;

import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class Ingredient {

private final String id;
private final String name;
private final Type type;

public static enum Type {
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
}

}/<code>

我們可以看到,這是一個非常普通的Java領域類,它定義了描述配料所需的3個屬性。在程序清單2.1中,Ingredient類最不尋常的一點是它似乎缺少了常見的getter和setter方法,以及equals()、hashCode()、toString()等方法。

在程序清單中沒有這些方法,部分原因是節省空間,另外還因為我們使用了名為Lombok的庫(這是一個非常棒的庫,它能夠在運行時動態生成這些方法)。實際上,類級別的@Data註解就是由Lombok提供的,它會告訴Lombok生成所有缺失的方法,同時還會生成所有以final屬性作為參數的構造器。通過使用Lombok,能夠讓Ingredient的代碼簡潔明瞭。

Lombok並不是Spring庫,但是它非常有用,我發現如果沒有它,開發工作將很難開展。當我需要在書中將代碼示例編寫得短小簡潔時,它簡直成了我的救星。

要使用Lombok,首先要將其作為依賴添加到項目中。如果你使用Spring Tool Suite,那麼只需要用右鍵點擊pom.xml,並從Spring上下文菜單選項中選擇“Edit Starters”。在第1章中看到的選擇依賴的對話框將會再次出現(見圖1.4),這樣的話我們就有機會添加依賴或修改已選擇的依賴了。找到Lombok選項,並確保它處於已選中的狀態,然後點擊“OK”,Spring Tool Suite會自動將其添加到構建規範中。

另外,你也可以在pom.xml中通過如下條目進行手動添加:

<code><dependency>
<groupid>org.projectlombok/<groupid>
<artifactid>lombok/<artifactid>
<optional>true/<optional>
/<dependency>/<code>

這個依賴將會在開發階段為你提供Lombok註解(例如@Data),並且會在運行時進行自動化的方法生成。但是,我們還需要將Lombok作為擴展添加到IDE上,否則IDE將會報錯,提示缺少方法和final屬性沒有賦值。參見Lombok項目頁面,以查閱如何在你所選擇的IDE上安裝Lombok。

我相信你會發現Lombok非常有用,但你也要知道,它是可選的。在開發Spring應用的時候,它並不是必備的,所以如果你不想使用它的話,完全可以手動編寫這些缺失的方法。當你完成之後,我們將會在應用中添加一些控制器,讓它們來處理Web請求。

2.1.2 創建控制器類

在Spring MVC框架中,控制器是重要的參與者。它們的主要職責是處理HTTP請求,要麼將請求傳遞給視圖以便於渲染HTML(瀏覽器展現),要麼直接將數據寫入響應體(RESTful)。在本章中,我們將會關注使用視圖來為Web瀏覽器生成內容的控制器。在第6章中,我們將會看到如何以REST API的形式編寫控制器來處理請求。

對於Taco Cloud應用來說,我們需要一個簡單的控制器,它要完成如下功能。

  • 處理路徑為“/design”的HTTP GET請求。
  • 構建配料的列表。
  • 處理請求,並將配料數據傳遞給要渲染為HTML的視圖模板,發送給發起請求的Web瀏覽器。

程序清單2.2中的DesignTacoController類解決了這些需求。

程序清單2.2 初始的Spring控制器類

<code>package tacos.web;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.validation.Valid;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;
import tacos.Taco;
import tacos.Ingredient;
import tacos.Ingredient.Type;

@Slf4j
@Controller
@RequestMapping("/design")
public class DesignTacoController {

@GetMapping
public String showDesignForm(Model model) {
List<ingredient> ingredients = Arrays.asList(
new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
new Ingredient("COTO", "Corn Tortilla", Type.WRAP),
new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
new Ingredient("CARN", "Carnitas", Type.PROTEIN),
new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES),
new Ingredient("LETC", "Lettuce", Type.VEGGIES),
new Ingredient("CHED", "Cheddar", Type.CHEESE),
new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),
new Ingredient("SLSA", "Salsa", Type.SAUCE),
new Ingredient("SRCR", "Sour Cream", Type.SAUCE)
);

Type[] types = Ingredient.Type.values();
for (Type type : types) {
model.addAttribute(type.toString().toLowerCase(),
filterByType(ingredients, type));
}

model.addAttribute("design", new Taco());

return "design";
}

}/<ingredient>/<code>

對於DesignTacoController,我們先要注意在類級別所應用的註解。首先是@Slf4j,這是Lombok所提供的註解,在運行時,它會在這個類中自動生成一個SLF4J(Simple Logging Facade for Java)Logger。這個簡單的註解和在類中通過如下代碼顯式聲明的效果是一樣的:

<code>private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(DesignTacoController.class);/<code>

隨後,我們將會用到這個Logger。

DesignTacoController用到的下一個註解是@Controller。這個註解會將這個類識別為控制器,並且將其作為組件掃描的候選者,所以Spring會發現它並自動創建一個DesignTacoController實例,並將該實例作為Spring應用上下文中的bean。

DesignTacoController還帶有@RequestMapping註解。當@RequestMapping註解用到類級別的時候,它能夠指定該控制器所處理的請求類型。在本例中,它規定DesignTacoController將會處理路徑以“/design”開頭的請求。

處理GET請求

修飾showDesignForm()方法的@GetMapping註解對類級別的@RequestMapping進行了細化。@GetMapping結合類級別的@RequestMapping,指明當接收到對“/design”的HTTP GET請求時,將會調用showDesignForm()來處理請求。

@GetMapping是一個相對較新的註解,是在Spring 4.3引入的。在Spring 4.3之前,你可能需要使用方法級別的@RequestMapping註解作為替代:

<code>@RequestMapping(method=RequestMethod.GET)/<code>

顯然,@GetMapping更加簡潔,並且指明瞭它的目標HTTP方法。@GetMapping只是諸多請求映射註解中的一個。表2.1列出了Spring MVC中所有可用的請求映射註解。

全球10萬+開發者使用的《Spring實戰》第5版出版啦!

讓正確的事情變得更容易

在為控制器方法聲明請求映射時,越具體越好。這意味著至少要聲明路徑(或者從類級別的@RequestMapping繼承一個路徑)以及它所處理的HTTP方法。

但是更長的@RequestMapping(method=RequestMethod.GET)註解很容易讓開發人員採取懶惰的方式,也就是忽略掉method屬性。幸虧有了Spring 4.3的新註解,正確的事情變得更容易了,我們的輸入變得更少了。

新的請求映射註解具有和@RequestMapping完全相同的屬性,所以我們可以在使用@RequestMapping的任何地方使用它們。

通常,我喜歡只在類級別上使用@RequestMapping,以便於指定基本路徑。在每個處理器方法上,我會使用更具體的@GetMapping、@PostMapping等註解。

現在,我們已經知道showDesignForm()方法會處理請求,接下來我們看一下方法體,看它都做了些什麼工作。這個方法構建了一個Ingredient對象的列表。現在,這個列表是硬編碼的。當我們學習第3章的時候,會從數據庫中獲取可用taco配料並將其放到列表中。

配料列表準備就緒之後,showDesignForm()方法接下來的幾行代碼會根據配料類型過濾列表。配料類型的列表會作為屬性添加到Model對象上,這個對象是以參數的形式傳遞給showDesignForm()方法的。Model對象負責在控制器和展現數據的視圖之間傳遞數據。實際上,放到Model屬性中的數據將會複製到Servlet Response的屬性中,這樣視圖就能在這裡找到它們了。showDesignForm()方法最後返回“design”,這是視圖的邏輯名稱,會用來將模型渲染到視圖上。

我們的DesignTacoController已經具備雛形了。如果你現在運行應用並在瀏覽器上訪問“/design”路徑,DesignTacoController的showDesignForm()將會被調用,它會從repository中獲取數據並放到模型中,然後將請求傳遞給視圖。但是,我們現在還沒有定義視圖,請求將會遇到很糟糕的問題,也就是HTTP 404(Not Found)。為了解決這個問題,我們將注意力切換到視圖上,在這裡數據將會使用HTML進行裝飾,以便於在用戶的Web瀏覽器中進行展現。

2.1.3 設計視圖

在控制器完成它的工作之後,現在就該視圖登場了。Spring提供了多種定義視圖的方式,包括JavaServer Pages(JSP)、Thymeleaf、FreeMarker、Mustache和基於Groovy的模板。就現在來講,我們會使用Thymeleaf,這也是我們在第1章開啟這個項目時的選擇。我們會在第2.5節考慮其他的可選方案。

為了使用Thymeleaf,我們需要添加另外一個依賴到項目構建中。如下的<dependency>條目使用了Spring Boot的Thymeleaf starter,從而能夠讓Thymeleaf 渲染我們將要創建的視圖:/<dependency>

<code><dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-thymeleaf/<artifactid>
/<dependency>/<code>

在運行時,Spring Boot的自動配置功能會發現Thymeleaf在類路徑中,因此會為Spring MVC創建支撐Thymeleaf視圖的bean。

像Thymeleaf這樣的視圖庫在設計時是與特定的Web框架解耦的。這樣的話,它們無法感知Spring的模型抽象,因此無法與控制器放到Model中的數據協同工作。但是,它們可以與Servlet的request屬性協作。所以,在Spring將請求轉移到視圖之前,它會把模型數據複製到request屬性中,Thymeleaf和其他的視圖模板方案就能訪問到它們了。

Thymeleaf模板就是增加一些額外元素屬性的HTML,這些屬性能夠指導模板如何渲染request數據。舉例來說,如果有一個請求屬性的key為“message”,我們想要使用Thymeleaf將其渲染到一個HTML

標籤中,那麼在Thymeleaf模板中我們可以這樣寫:

<code>

placeholder message

/<code>

當模板渲染成HTML的時候,

元素體將會被替換為Servlet request中key為“message”的屬性值。“th:text”是Thymeleaf命名空間中的屬性,它會執行這個替換過程。${}會告訴它要使用某個請求屬性(在本例中,也就是“message”)中的值。

Thymeleaf還提供了一個屬性“th:each”,它會迭代一個元素集合,為集合中的每個條目渲染HTML。在我們設計視圖展現模型中的配料列表時,這就非常便利了。舉例來說,如果只想渲染“wrap”配料的列表,我們可以使用如下的HTML片段:

<code>

Designate your wrap:




INGREDIENT

/<code>

在這裡,我們在

標籤中使用th:each屬性,這樣的話就能針對wrap request屬性所對應集合中的每個元素重複渲染
了。在每次迭代的時候,配料元素都會綁定到一個名為ingredient的Thymeleaf變量上。

元素中,有一個複選框元素,還有一個為複選框提供標籤的元素。複選框使用Thymeleaf的th:value來為渲染出的元素設置value屬性,這裡會將其設置為所找到的ingredient的id屬性。元素使用th:text將“INGREDIENT”佔位符文本替換為ingredient的name屬性。

當用實際的模型數據進行渲染的時候,其中一個

迭代的渲染結果可能會如下所示:
<code>


Flour Tortilla

/<code>

最終,上述的Thymeleaf片段會成為一大段HTML表單的一部分,我們taco藝術家用戶會通過這個表單來提交其美味的作品。完整的Thymeleaf模板會包括所有的配料類型,表單如下所示:

程序清單2.3 設計taco的完整頁面

<code> 

xmlns:th="http://www.thymeleaf.org">

<title>Taco Cloud/<title>
<link>



Design your taco!






/<code>

可以看到,我們會為各種類型的配料重複定義

片段。另外,我們還包含了一個Submit按鈕,以及用戶用來定義其作品名稱的輸入域。

值得注意的是,完整的模板包含了一個Taco Cloud的logo圖片以及對樣式表的<link>引用[2]。在這兩個場景中,都使用了Thymeleaf的@{}操作符,用來生成一個相對上下文的路徑,以便於引用我們需要的靜態製件(artifact)。正如我們在第1章中所學到的,在Spring Boot應用中,靜態內容要放到根路徑的“/static”目錄下。

我們的控制器和視圖已經完成了,現在我們可以將應用啟動起來,看一下我們的勞動成果。運行Spring Boot應用有很多種方式。在第1章中,我為你首先展示瞭如何將應用構建成一個可執行的JAR文件,然後通過java –jar命令來運行這個JAR。我還展示瞭如何直接通過mvn spring-boot:run構建命令來運行應用。

不管你採用哪種方式來啟動Taco Cloud應用,在啟動之後都可以通過http://localhost: 8080/design來進行訪問。你將會看到類似於圖2.2的一個頁面。

全球10萬+開發者使用的《Spring實戰》第5版出版啦!

圖2.2 渲染之後的taco設計頁面

這看上去非常不錯!訪問你站點的taco藝術家可以看到一個表單,這個表單中包含了各種taco配料,他們可以使用這些配料創建自己的傑作。但是當他們點擊Submit Your Taco按鈕的時候會發生什麼呢?

我們的DesignTacoController還沒有為接收創建taco的請求做好準備。如果提交設計表單,用戶就會遇到一個錯誤。(具體來講,將會是一個HTTP 405錯誤:Request Method “POST” Not Supported。)接下來,我們通過編寫一些處理表單提交的控制器代碼來修正這個錯誤。

"


分享到:


相關文章: