HTMX是否有潛力成為實現以Java為中心的Ajax(Asynchronous JavaScript and XML,非同步JavaScript和XML)開發模式的關鍵元件。
- Ajax是一種在不重新載入整個頁面的情況下,能夠與伺服器交換資料並更新部分網頁的技術。
- HTMX可能成為將Java後端與前端動態互動功能緊密結合的工具。
讓我們透過基於 HTMX、Spring Boot 和 Thymeleaf 的示例應用程式來一探究竟。
什麼是HTMX?
HTMX是一種較新的技術,它採用普通的 HTML,並賦予其 Ajax 和 DOM 交換等額外功能。它被列入我個人的好主意列表中,因為它消除了典型 Web 應用程式中的整個複雜性。HTMX 透過在 JSON 和 HTML 之間來回轉換來工作。可以將其視為一種宣告式 Ajax。
Java、Spring 和 Thymeleaf
而 Java 則是另一個選擇:它是最成熟且最具創新性的伺服器端平臺之一。Spring 是新增一系列基於 Java 的功能的簡單選擇,包括用於處理端點和路由的 精心設計的Spring Boot Web 專案。
Thymeleaf是一款完整的伺服器端模板引擎,也是 Spring Boot Web 的預設引擎。與 HTMX 結合使用時,您可以構建全棧 Web 應用,而無需使用大量 JavaScript。
案例
我們將構建標準的 Todo 應用:我們列出現有的待辦事項,並允許建立新的待辦事項、刪除待辦事項以及更改其完成狀態。
概述
完成的 Todo 應用程式在磁碟上的樣子如下:
$ tree |
因此,除了典型的 Gradle 內容外,應用程式還有兩個主要部分包含在 /src 目錄中:/main 目錄包含 Java 程式碼,而 /resources 則包含屬性檔案以及 CSS 和 Thymeleaf 模板的兩個子目錄。
您可以在 GitHub repo 程式碼庫中找到該專案的原始碼。要執行它,請訪問根目錄並鍵入 $ gradle bootRun。然後就可以在 localhost:8080 上使用該應用程式了。
如果想從頭開始啟動應用程式,可以從以下步驟開始:$ spring init --dependencies=web,thymeleaf spring-htmx。這將把 Thymeleaf 和 Spring Boot 安裝到 Gradle 專案中。
該應用程式是由 DemoApplication.java 執行的普通 Spring Boot 應用程式。
Java Spring HTMX 模型類
讓我們首先看看我們的模型類:com/example/iwjavaspringhtmx/TodoItem.java。這是代表待辦事項的伺服器端模型類。它看起來如下:
public class TodoItem { |
這是一個帶有 getter 和 setter 的簡單模型類。沒什麼特別的,但這正是我們想要的。
Java Spring HTMX 控制器類
在伺服器上,控制器是老闆。它接受請求、編排邏輯並制定響應。在我們的例子中,我們需要四個端點,用於列出專案、更改其完成狀態、新增專案和刪除專案。這是控制器類:
@Controller |
您會注意到,我剛剛建立了一個靜態變數List來儲存記憶體中的專案。在現實生活中,我們會使用外部資料儲存。
首先,端點使用 @GetMapping、@PostMapping 和 @DeleteMapping 進行註解。這就是將 Spring Web 路徑對映到處理程式的方法。每個註解對應其 HTTP 方法(GET、POST、DELETE)。
Spring Boot 還可以使用引數註解 @PathParameter 從路徑中輕鬆獲取引數。因此,對於 /todos/{id}/delete 路徑,@PathVariable Integer id 將包含路徑 {id} 部分的值。
在 createTodo() 方法中,註釋為 @ModelAttribute TodoItem newTodo 的引數將自動接收 POST 主體並將其值應用於 newTodo 物件。(這是一種將表單提交轉化為 Java 物件的快速而簡單的方法)。
接下來,我們使用專案 ID 來操作專案列表:這是標準的 REST API 方法。
傳送響應有兩種方式。如果方法上有 @ResponseBody 註解(比如 deleteTodo()),那麼返回的內容將逐字傳送。否則,返回字串將被解釋為 Thymeleaf 模板路徑(稍後您將看到)。
Model 模型引數比較特殊。它用於為移交給 Thymeleaf 的作用域新增屬性。我們可以把下面的專案方法理解為給定一個指向根/路徑的 GET 請求,將 items 變數新增到作用域中,命名為 "itemList",然後使用 "index "模板渲染響應。
@GetMapping(<font>"/") |
在 HTMX 處理從前端傳送的 AJAX 請求時,HTMX 元件將使用響應來更新使用者介面。我們很快就能在實踐中很好地瞭解這一點。
Thymeleaf 模板
現在讓我們來看看 Thymeleaf 的索引模板。它位於 /resources/templates/index.html 檔案中。Spring Boot 使用約定將 items() 方法返回的 "index "字串對映到該檔案。下面是我們的 index.html 模板:
<!DOCTYPE html> |
Thymeleaf 的基本思想是在 HTML 結構中使用 Java 變數。(這相當於使用 Pug 這樣的模板系統)。
Thymeleaf 使用以 th: 為字首的 HTML 屬性或元素來表示其工作位置。請記住,當我們在控制器中對映根/路徑時,我們在作用域中新增了 itemList 變數。在這裡,我們在帶有 th:each 屬性的 th:block 中使用該變數。th:each 屬性是 Thymeleaf 中的迭代器機制。我們用它來訪問 itemList 中的元素,並將每個元素作為名為 item 的變數公開:item : ${itemList}。
在 itemList 的每次迭代中,我們都將渲染工作交給另一個模板。這種模板重用是避免程式碼重複的關鍵。
行:
<th:block th:replace=<font>"~{'todo.html'}"th:args="${item}"></th:block> |
告訴 Thymeleaf 渲染 todo.html 模板,並將專案作為引數。
接下來我們將瞭解 todo 模板,但首先要注意的是,我們在控制器中的 completeTodo 和 createTodo 中都使用了相同的模板,以提供在 Ajax 請求期間傳送回 HTMX 的標記。換句話說,我們將 todo.html 用作初始列表渲染的一部分,並在 Ajax 請求期間向使用者介面傳送更新。重複使用 Thymeleaf 模板可以使我們保持 DRY。
待辦事項模板
這是 todo.html:
<li> |
您可以看到,我們提供了一個 list-item 元素,並使用一個變數 item 來填充值。在這裡,我們將使用 HTMX 和 Thymeleaf 進行一些有趣的工作。
首先,我們使用 th:checked 將 item.isComplete 的選中狀態應用於核取方塊輸入。
點選核取方塊時,我們會使用 HTMX 向後端發出 Ajax 請求:
- hx-trigger="click" 告知 HTMX 在點選時啟動 Ajax。
- hx-target="closest li "告訴 HTMX 將 Ajax 請求的響應放在哪裡。在我們的例子中,我們要替換最近的 list-item 元素。(請記住,我們的刪除端點會返回該專案的整個列表專案標記)。
- hx-swap="outerHTML "告訴 HTMX 如何替換新內容,在本例中就是替換整個元素。
- th:hx-post="|/todos/${item.id}/complete|"告訴 HTMX,這是一個活動的 Ajax 元素,會向指定的 URL(我們的 completeTodo 端點)發出 POST 請求。
將 Thymeleaf 與 HTMX 結合使用時需要注意的一點是,您最終會使用複雜的屬性字首,就像您在 th:hx-post 中看到的那樣。從本質上講,Thymeleaf 首先在伺服器上執行(th: 字首)並填充 ${item.id} 插值,然後 hx-post 在客戶端上正常工作。
接下來,對於 span,我們只需顯示 item.description 中的文字。(請注意,Thymelef 的表示式語言允許我們訪問欄位而無需使用 get 字首)。同樣值得注意的是,我們如何在 span 元素中應用已完成的樣式類。下面是我們的 CSS 將用於為已完成的專案新增刪除線裝飾:
th:classappend=<font>"${item.isCompleted ? 'complete' : ''}" |
使用 Thymeleaf 屬性,可以根據 item.isComplete 等布林條件有條件地應用類。
我們的刪除按鈕與完整核取方塊的工作原理類似。我們使用 Thymeleaf 提供的 item.id 向 URL 傳送 Ajax 請求,當響應返回時,我們更新列表項。請記住,我們從 deleteTodo() 發回的是空字串。因此,其效果是從 DOM 中移除列表項。
CSS 樣式表
CSS 樣式表位於 src/main/resources/static/style.css,沒什麼特別的。唯一有趣的是處理跨頁上的span樣式:
span { |
結論
將 HTMX、Java、Spring 和 Thymeleaf 結合在一起,可以用最少的模板程式碼構建相當複雜的互動。我們可以在不編寫 JavaScript 的情況下實現大量典型的互動。
乍一看,Java-HTMX 協議棧似乎終於兌現了以 Java 為中心的 Ajax 的承諾;就像 Google Web Toolkit 曾經設定的目標一樣。
但事實並非如此。
HTMX 試圖將Web應用程式重新定位到 REST 的真正本質,而這個協議棧為我們指明瞭方向。
HTMX 與伺服器端無關,因此我們可以毫無困難地將其與 Java 後端整合。