5.4.2 校验表单

如果用户在提交表单的时候,username 或 password 文本域为空的话,那么将会导致在新建 Spitter 对象中,username 或 password 是空的 String。至少这是一种怪异的行为。如果这种现象不处理的话,这将会出现安全问题,因为不管是谁只要提交一个空的表单就能登录应用。

同时,我们还应该阻止用户提交空的 firstName 和 / 或 lastName,使应用仅在一定程度上保持匿名性。有个好的办法就是限制这些输入域值的长度,保持它们的值在一个合理的长度范围,避免这些输入域的误用。

有种处理校验的方式非常初级,那就是在 processRegistration() 方法中添加代码来检查值的合法性,如果值不合法的话,就将注册表单重新显示给用户。这是一个很简短的方法,因此,添加一些额外的 if 语句也不是什么大问题,对吧?

与其让校验逻辑弄乱我们的处理器方法,还不如使用 Spring 对 Java 校验 API(Java Validation API,又称 JSR-303)的支持。从 Spring 3.0 开 始,在 Spring MVC 中提供了对 Java 校验 API 的支持。在 Spring MVC 中要使用 Java 校验 API 的话,并不需要什么额外的配置。只要保证在类路径下包含这个 Java API 的实现即可,比如 Hibernate Validator。

Java 校验 API 定义了多个注解,这些注解可以放到属性上,从而限制这些属性的值。所有的注解都位于 javax.validation.constraints 包中。表 5.1 列出了这些校验注解。

除了表 5.1中的注解,Java 校验 API 的实现可能还会提供额外的校验注解。同时,也可以定义自己的限制条件。但就我们来讲,将会关注于上表中的两个核心限制条件。

请考虑要添加到 Spitter 域上的限制条件,似乎需要使用 @NotNull 和 @Size 注解。我们所要做的事情就是将这些注解添加到 Spitter 的属性上。如下的程序清单展现了 Spitter 类,它的属性已经添加了校验注解。

package spittr;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Spitter {

  private Long id;
  
  @NotNull
  @Size(min=5, max=16)
  private String username;

  @NotNull
  @Size(min=5, max=25)
  private String password;
  
  @NotNull
  @Size(min=2, max=30)
  private String firstName;

  @NotNull
  @Size(min=2, max=30)
  private String lastName;
  
  ...
}

现在,Spitter 的所有属性都添加了 @NotNull 注解,以确保它们的值不为 null。类似地,属性上也添加了 @Size 注解以限制它们的长度在最大值和最小值之间。对 Spittr 应用来说,这意味着用户必须要填完注册表单,并且值的长度要在给定的范围内。

我们已经为 Spitter 添加了校验注解,接下来需要修改 processRegistration() 方法来应用校验功能。启用校验功能的 processRegistration() 如下所示:

程序清单 5.19 processRegistration():确保所提交的数据是合法的
@RequestMapping(value="/register", method=POST)
public String processRegistration(
    @Valid Spitter spitter, 
    Errors errors) {
  if (errors.hasErrors()) {
    return "registerForm";
  }
    
  spitterRepository.save(spitter);
  return "redirect:/spitter/" + spitter.getUsername();
}

与程序清单5.17 中最初的 processRegistration() 方法相比,这里有了很大的变化。Spitter 参数添加了 @Valid 注解,这会告知 Spring,需要确保这个对象满足校验限制。

在 Spitter 属性上添加校验限制并不能阻止表单提交。即便用户没有填写某个域或者某个域所给定的值超出了最大长度,processRegistration() 方法依然会被调用。这样,我们就需要处理校验的错误,就像在 processRegistration() 方法中所看到的那样。

如果有校验出现错误的话,那么这些错误可以通过 Errors 对象进行访问,现在这个对象已作为 processRegistration() 方法的参数。(很重要一点需要注意,Errors 参数要紧跟在带有 @Valid 注解的参数后面,@Valid 注解所标注的就是要检验的参数。)processRegistration() 方法所做的第一件事就是调用Errors.hasErrors() 来检查是否有错误。

如果有错误的话,Errors.hasErrors() 将会返回到registerForm,也就是注册表单的视图。这能够让用户的浏览器重新回到注册表单页面,所以他们能够修正错误,然后重新尝试提交。现在,会显示空的表单,但是在下一章中,我们将在表单中显示最初提交的值并将校验错误反馈给用户。

如果没有错误的话,Spitter 对象将会通过 Repository 进行保存,控制器会像之前那样重定向到基本信息页面。

Last updated