Spring MVC支持与JSR 349Bean Validation  API 的集成。为了可以通过应用程序层来验证数据,他提供了大量功能。

下面所示的代码片段定义了User域类,其中应用了一些验证注解:

@Size 注解酱用户名的长度设置为3~20之间

@Email 注解根据e-email的正则表达式来验证输入

@CreditCardNumber 注解根据Lubn算法验证输入的数字

注意:

Luhn 算法是一个简单的模数-10(modulus-10)校验公式,可用来验证各种识别码

@Pattern 注解根据一个正则表达式验证密码,比如第一个字符必须是字母,必须包含至少4个字符,但不能超过15个字符

为了节约篇幅,代码中省略了Getter和Setter方法


public class User{
    @Size(min=3,max=20)
    String username;

    @Email
    String email;

    @CreditCardNumber
    String ccNumber;

    @Pattern(regexp="^[a-zA-Z]\\w{3,14}$")
    String password;

     //getters  &  setters
}

为了启用验证,需要相项目中添加Bean验证的实现。本列选择Hibernate Validator框架来提供验证功能。可以像下面的示例那样将该项目作为一个Maven依赖添加到当前项目中。此外,Hibernate Validator会将Bean Validation API作为一个船只依赖添加到项目中。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.1.Final</version>
</dependency>

因为已经定义了模型,所以可以编写新的包含该表单的JSP。所定义的表单分别针对User类的属性包含了4个输入元素,此外还包含4个errors标签,以便显示在每个输入字段可能发生的错误,通过使用请求映射/result,将表单提交到一个方法:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring MVC Form Validation</title>
<style type="text/css">
.formFieldError{
	background-color:#FFC;		
}
</style>
</head>
<body>
    <h2>User Registration Form</h2>
    <mvc:form modelAttribute="user" action="result.mvc">
    	<table>
    		<tr>
    			<td><mvc:label path="username">User Name</mvc:label></td>
    			<td><mvc:input path="username" cssErrorClass="formFieldError"/></td>
    			<td><mvc:errors path="username"/></td>
    		</tr>
    		<tr>	
    			<td><mvc:label path="email">E-Mail</mvc:label></td>
    			<td><mvc:input path="email" cssErrorClass="formFieldError"/></td>
    			<td><mvc:errors path="email"/></td>
    		</tr>
    		<tr>
    			<td><mvc:label path="ccNumber">Credit Card Number</mvc:label></td>
    			<td><mvc:input path="ccNumber" cssErrorClass="formFieldError"/></td>
    			<td><mvc:errors path="ccNumber"/></td>
    		</tr>
    		<tr>
    			<td><mvc:label path="password">Password</mvc:label></td>
    			<td><mvc:input path="password" cssErrorClass="formFieldError"/></td>
    			<td><mvc:errors path="password"/></td>
    		</tr>
    		<tr>
    			<td colspan="3">
    				<input type="submit" value="Submit"/>
    			</td>
    		</tr>
    	</table>
    </mvc:form>
</body>
</html>

对于每一个errors标签,都可以将其path特性设置为模型类的属性名称。但对于errors标签来说,path特性则不是必须设置的。但如果没有设置,则无法看到相关联输入字段的错误消息。如果想要在一个地方显示所有错误,可酱path值设置为*,并将errors标签放置在表单上。此外,本例还定义了一个样式表类formFieldError.并将每个输入字段的cssErrorClass特性设置为该类。通过使用该错误类,当对一个输入字段验证失败时,该字段的背景颜色将被设置为黄色。

用来处理表单提交的控制器方法如下所示:

@RequestMapping(value="/result")
	public ModelAndView processUser(@Valid User user,BindingResult result){
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("u",user);
		
		if(result.hasErrors()){
			modelAndView.setViewName("userForm");
		}
		else{
			modelAndView.setViewName("userResult");
		}
		return modelAndView;
	}

对用户输入的验证由在user方法参数上设置的@Valid注解触发,该注解被递归地应用到类的属性,如果没有设置该注解,就不会触发Bean验证。

processUser方法接收一个额外的参数result,该参数是一个BindingResult实例。通过使用该参数来检查在将请求映射到域类属性的过程中是否发生任何验证错误(使用result.hasErrors()方法)。然后根据条件设置视图,以便在输入页面向用户显示相关错误。

注意:

挡在模型特性上使用@Valid注解时,如果忽略了BindingResult类型的方法类型的方法参数,则可能在提交表单时遇到下面所示的问题:HTTP 400-The request sent by the client was syntactically incorrect. 所以请确保不要缺少BindingResult类型的方法参数。

如果所提交的表单带有空输入字段,将得到如图所示的输出。



带阴影的输入框样式来自cssErrorClass特性。图所示的错误消息是由框架默认设置的,如果要修改这些消息,可以通过使用注解设置新的消息,比如对于密码字段,可以设置以下消息:


通过使用该方法,可以让显示的消息比默认消息更加易于理解,但它仍然缺乏国际化,因为消息本身是硬编码实现的。

为了配置验证,首先需要相Web应用程序的上下文中添加LocalValidatorFactoryBean和ReloadableResourceBundleMessageSource Bean定义,此外,还需要在mvc明明空间的annotation-driven标签中定义验证程序:

<mvc:annotation-driven validator="validator"/>

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
   <property name="basename" value="classpath:messages"/>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
  <property name="validationMessageSource" ref="messageSource"/>
</bean>

此时,ReloadableResourceBundleMessageSource引用一个属性文件,该文件包含以键值对形式存在的消息。文件应该位于应用程序的类路径下,其基本名称为messages


如果你正在使用Maven作为开发工具,那么可在src/main/resources文件夹下创建该属性文件。根据区域设置不同,该文件可能有所不同,比如区域设置为U.S.,文件可能是message_en_US.properties,而区域设置为Turkish,则文件为message_tr_TR.properties,或者也可以直接将其定义为message.properties。

接下来,可以在注解中未消息定义键


如果使用该方法,则需要将一个消息键添加到每个注解(将其用大括号括起来)。另一种选择是根据注解,模型特性以及所使用的路径名称定义键值。此时,键的注解为AnnotationName.ModeAttributeName.PathName。让我们来看一个示例,比如,对于一个使用@Pattern注解标识的password字段,在属性文件中定义的键值应该是Pattern.user.password.相比于前一种方法,该方法是非强制性的,因为在代码中没有硬编码信息。