将 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 验证以进行验证规则(这不是使用 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 以进行部分渲染

让我们考虑一下当“first name”为空时会发生什么。

在之前的示例中,每次提交表单时都会刷新整个页面。这是 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;
 }
}

在控制器类中,我们可以添加一个 action 方法


@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 框架。许多开发人员喜欢它,因为它允许以很少的努力为网站做一个可以接受的设计。在复制 Bootstrap CSS 和图像后,我只需要使用 Boostrap 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 社区中所有即将举行的活动。

查看全部