整合 Spring MVC 與 jQuery 以進行驗證規則

工程 | Michael Isvy | 2012 年 8 月 29 日 | ...

我很高興在 Zeroturnaround 最近的一份調查中看到,Spring MVC 被票選為 Java 最受歡迎的 Web 框架。

這個框架非常彈性,而且有很多種使用方式。如同所有具有多種選項的彈性框架一樣,討論常見實務非常重要。

我為這篇部落格文章建立的專案使用了許多 Spring MVC 應用程式中常見的功能。你會發現類似這樣的東西

在控制器中,你會找到典型的 Spring MVC 功能,用於對應請求、透過註解提取請求資料、資料繫結、檔案上傳…等。

另一方面,在 JSP 內部,大多數 HTML 都是以原生方式撰寫(而不是由 Spring MVC 標籤產生)。此外,Spring MVC 標籤庫不會產生任何 Javascript 程式碼。

我們首先將討論如何整合 Spring MVC 與 jQuery 和 Bean Validation。然後,我們將看看如何讓這些 JSP 程式碼更簡潔。

Bean Validation?

JSR 303 Bean Validation 提供了一種全面的方式來宣告驗證規則。以下是一個範例

public class DiningForm {
  @Pattern(regexp="\\d{16}")

  private String creditCardNumber;

  @Size(1)
  private String merchantNumber;

  @Min(0)
  private double monetaryAmount;

  @NotNull
  private Date date;

  ...

}

當呼叫驗證時,將根據上述註解驗證 DiningForm 的實例。

從 Spring 3.0 開始,Spring MVC 與 Bean Validation 整合以進行驗證規則(這不是使用 Spring @MVC 進行驗證的唯一方法,但顯然它正成為最常見的方法)。

在控制器方法中,我們可以如下使用 @Valid


@RequestMapping(value="/update", method=RequestMethod.POST)
  public String update(@Valid DiningForm diningForm, BindingResult result) {

    if (result.hasErrors()) {
      return “rewards/edit”;
    }

    // continue on success...

  }
}

在 JSP 層級,可以使用 <form:errors /> 顯示錯誤訊息。


<form:form modelAttribute="diningForm">
  <form:input path="firstName"/>
  <form:errors path="firstName"/>
  …
</form:form>

上面的程式碼非常簡單且運作良好。但它不會產生任何 Javascript。因此,它不允許局部渲染或客戶端驗證。讓我們看看如何改進它!

新增 Javascript 以進行局部渲染

讓我們考慮當「名字」為空時會發生什麼事。

在先前的範例中,每次提交表單時都會重新整理整個頁面。以下是 HTML 回應的摘錄

我們的目標是最小化回應大小。我們應該能夠有這樣的響應(使用 json 語法)


{"status":"FAIL","result":[{"fieldName":"firstName","message":"firstName  may not be empty"}]}

首先,我們將使用 jQuery 表單提交來驗證表單。當表單被視為有效時,將使用常規 HTML 表單提交觸發表單提交(透過這種方式,我們將能夠重新導向到不同的頁面)。

讓我們首先建立一個簡單的 ValidationResponse 類別,如下所示


public class ValidationResponse {
 private String status;
 private List errorMessageList;

 public String getStatus() {
   return status;
 }
 public void setStatus(String status) {
   this.status = status;
 }
 public List getErrorMessageList() {
   return this.errorMessageList;
 }
 public void setErrorMessageList(List errorMessageList) {
   this.errorMessageList = errorMessageList;
 }
}

在控制器類別中,我們可以新增一個動作方法


@RequestMapping(value="/user.json")
public @ResponseBody ValidationResponse processForm (Model model, @Valid User user, BindingResult result ) {
 ValidationResponse res = new ValidationResponse();
 if(!result.hasErrors()){
   res.setStatus("SUCCESS");
 }
 // …
 return res;
}

感謝 @ResponseBody 註解,傳回的物件將被轉換為 JSON,如下圖所示

在 JSP 內部,錯誤訊息會被解析並在適當的時候顯示。您可以瀏覽 Javascript 程式碼 以取得更多詳細資訊。

根據 漸進增強 最佳實務,所有 Javascript 程式碼都已放置在 HTML 表單之外。萬一在客戶端的瀏覽器上停用 Javascript,表單會退回完整頁面重新整理。

現在我們已經讓局部重新整理適用於驗證規則,但仍有 2 個點需要改進

  • 這個頁面看起來不夠酷!
  • 這個 hello-world 風格的頁面已經有 100 行了。應該有一些方法可以使其更簡潔。

讓我們使用 Bootstrap 使其美觀

即使這與 Spring MVC 沒有直接關係,我仍然難以呈現一個 UI 設計如此糟糕的範例應用程式。萬一您還沒聽說過 twitter Bootstrap,它正逐漸成為事實上的 CSS 框架。許多開發人員喜歡它,因為它允許以少量 effort 為網站做出可接受的設計。在複製 Bootstrap CSS 和圖片後,我只需要使用 Bootstrap CSS 類別(請參閱 JSP 原始碼 以取得更多詳細資訊)。我的表單現在看起來像這樣:

使用自訂標籤以避免「JSP 湯麵」綜合症

這才是事情變得真正有趣的地方:即使我們已經有一些可以運作的程式碼,但它仍然很難閱讀。我們將 HTML、Javascript、CSS 和 JSP 運算式語言混合在一起。如果我的 JSP 程式碼看起來像這樣,可讀性會更高


<html:form modelAttribute="user"  id="add-user-form" formUrl="/userAjaxCustomTag.htm">
 <html:inputField name="firstName" label="Enter your first name:" />
 <html:inputField name="lastName" label="Enter your last name:" />
 <div>
   <button type="submit">Save changes</button>
   <button type="reset">Cancel</button>
 </div>
</html:form>

自訂標籤是 Java EE 的一部分,並且在 Apache Tomcat 上也能良好運作。建立自訂標籤出乎意料地容易。讓我們以表單輸入欄位為例。我們目前使用這種語法(8 行)


<div id="firstName">
 <label>Enter your first name:</label>
 <div>
   <form:input path="firstName" />
   <span>
     <form:errors path="firstName" />
   </span>
 </div>
</div>

我們的目標是改用這種語法(1 行)


<html:inputField name="firstName" label="Enter your first name:" />

在 WEB-INF 資料夾中,我可以建立一個新的標籤檔案,如下所示

其內容如下


<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="label" required="true" rtexprvalue="true" %>
<div id="${name}">
 <label>${label}</label>
<div>
  <form:input path="${name}"/>
  <span><form:errors path="${name}"/></span>
</div>

回到 userForm.jsp,我只需要宣告標籤資料夾


<%@ taglib prefix="html" tagdir="/WEB-INF/tags/html" %>

然後我可以如下使用這個新建立的標籤


<html:inputField name="firstName" label="Enter your first name:" />

自訂標籤已良好整合到 Eclipse/STS 中,我甚至可以使用程式碼自動完成功能:

以類似的方式,我也可以將 JavaScript 程式碼外部化到標籤中,這樣我只需要一行程式碼即可呼叫


<ajax:formPartialRefresh validateUrl="/userAjaxBootstrap.json" formName="add-user-form"/>

結論

我們已經討論了在表單驗證中使用 Spring MVC 進行局部渲染。在短短幾分鐘內,我們已將 JSP 湯麵轉變成更簡潔且更容易理解的東西。

歡迎您查看 github 上對應的範例應用程式

致謝:我要感謝我的朋友 Nicholas Ding,他與我一起為這篇部落格文章建立程式碼範例。

取得 Spring 電子報

隨時關注 Spring 電子報

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案,只需一個簡單的訂閱。

了解更多

即將到來的活動

查看 Spring 社群中所有即將到來的活動。

查看全部