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,则表单将回退到全页刷新。

现在我们已经为验证规则实现了部分刷新,但还有两点需要改进

  • 这个页面看起来不好看!
  • 这个简单的页面已经有 100 行代码了。应该有一些方法可以使它更短。

让我们用 Bootstrap 美化它

尽管这与 Spring MVC 没有直接关系,但我很难用如此糟糕的 UI 设计来演示一个示例应用程序。如果你还没有听说过,twitter Bootstrap 正在成为事实上的 CSS 框架。许多开发人员喜欢它,因为它可以轻松地为网站创建可接受的设计。复制 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 社区中所有即将举行的活动。

查看全部