将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;
 }
}

在控制器类中,我们可以添加一个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 社区所有即将举行的活动。

查看所有