Spring MVC 入门(九)Spring MVC 数据校验

9.1 数据校验

    应用通过输入页面收集的数据是非常复杂的,不仅会包含正常用户的误输入,还可能包含恶意用户的恶意输入。异常的输入,轻则会导致系统非正常中断,重则会导致系统崩溃。应用程序必须能正常处理表现层接收的各种数据,通常的做法是遇到异常输入时应用程序直接返回,提示用户必须重新输入,也就是将哪些异常输入过滤掉。这种对异常输入的过滤,就是输入校验,也称为“数据校验”。一个健壮的应用系统必须将这些非法输入阻止在应用外,防止这些非法输入进入系统,这样才能保证系统不受影响。
    输入校验分为客户端校验服务器端校验,客户端校验主要是过滤非正常用户的误操作,通常通过 JavaScript 代码完成;服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现。
    客户端校验的主要作用是防止用户的误输入,这仅能对输入进行初步过滤;对于恶意用户的恶意行为,客户端校验无能为力。因此,客户端校验绝不可替代服务器校验。当然客户端校验也绝不可少,因为 Web 应用的大部分用户是正常用户,他们的输入可能包含了大量的误输入,客户端校验能把这些误输入阻止在客户端,从而降低了服务器的负载
    Spring MVC 提供了强大的数据校验功能,其中有两种方法可以验证输入:一种是利用 Spring 自带的 Validation 校验框架;另一种是利用 JSR 303Java 验证规范)实现校验功能。

9.1.1 Spring 的 Validation 校验框架

    Spring 拥有自己独立的数据校验框架。Spring 在进行数据绑定时,可同时调用校验框架来完成数据校验工作。
    Spring 的校验框架在 org.springframework.validation 包中,其中重要的接口和类如下:

  • Validation。最重要的接口。
  • Errors。Spring 用来存放错误信息的接口。
  • ValidationUtils。Spring 提供的一个关于校验的工具类。
  • LocalValidationFactoryBean。位于 org.springframework.validation.beanvalidation 包中,该类既实现了 Spring 的 Validation 接口,也实现了 JSR 303 的 Validation 接口。只要在 Spring 容器定义一个 LocalValidationFactorybean,即可将其注入到需要数据校验的 Bean 中。定义一个 LocalValidationFactoryBean 的 Bean 非常简单:
<bean id="validator" 
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

    <mvc:annotation-driven/> 会默认装配好一个 LocalValidationFactoryBean,所以在实际开发中不需要手动配置 LocalValidationFactoryBean。需要注意的是:Spring 本身没有提供 JSR 303 的实现,如果要使用 JSR 303 完成验证,则必须将 JSR 303 的实现(注入 Hibernate Validator)jar 文件加入到应用程序的类路径下,这样 Spring 会自动加载并装配好 JSR 303 的实现。

示例:Spring 的 Validation 校验

  1. 新建 loginForm.jsp,页面使用 <form:errors> 标签显示属性的错误信息。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试 Validation 接口验证</title>
</head>
<body>
	<jsp:useBean id="user" class="domain.User" scope="request"/>
    <form:form modelAttribute="user" method="post" action="login">
        <table>
            <tr>
                <td><label>登录名:</label></td>
                <td><form:input path="loginname"/></td>
                <!--  显示 loginname 属性的错误信息  -->
                <td><form:errors path="loginname" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td><label>密码:</label></td>
                <td><form:input path="password"/></td>
                <!--  显示 password 属性的错误信息  -->
                <td><form:errors path="password" cssStyle="color:red"/> </td>
            </tr>
            <tr>
                <td><input type="submit" value="提交"></td>
            </tr>
        </table>
    </form:form>
</body>
</html>
  1. 新建 User 类负责接收页面输入信息。
package domain;

import java.io.Serializable;

public class User implements Serializable {
    private String loginname;
    private String password;

    public String getLoginname() {
        return loginname;
    }

    public void setLoginname(String loginname) {
        this.loginname = loginname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "loginname='" + loginname + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
  1. 新建 UserValidator 类。
package validator;

import domain.User;
import org.springframework.stereotype.Repository;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

// 实现 Spring 的 Validator 接口
@Repository("userValidator")
public class UserValidator implements Validator {
    // 从该校验器能够对 clazz 类型的对象进行校验。
    @Override
    public boolean supports(Class<?> aClass) {
        // User 指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
        return User.class.isAssignableFrom(aClass);
    }
    // 对目标类 target 进行校验,并将校验错误记录在 errors 当中。
    @Override
    public void validate(Object target, Errors errors) {
        /*
        *  使用 ValidationUtils 中的一个静态方法rejectIfEmpty() 来对 loginname 属性进行数据校验,
        *  假若 'loginname' 属性是 null 或者空字符串的话,就拒绝验证通过。
        */
        ValidationUtils.rejectIfEmpty(errors,"loginname",null,"登录名不能为空!");
        ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空!");
        User user = (User)target;
        if (user.getLoginname().length() > 10){
            // 使用 Errors 的 rejectValue 方法验证
            errors.rejectValue("loginname",null,"用户名不能超过十个字符!");
        }
        if (user.getPassword() != null
        && !user.getPassword().equals("")
        && user.getPassword().length() < 6){
            errors.rejectValue("password",null,"密码不能小于6位!");
        }
    }
}

    UserValidator 实现了 Spring 的 Validator 接口,其可以对 User 对象进行数据校验,并分别使用 ValidationUtils 的 rejectIfEmpty 方法和 Errors 的 rejectValue 方法对 User 进行了数据校验。@Repository(“userValidator”)注解将该对象注释为 Spring 容器中的一个 Bean,名字为 “userValidator”。

  1. 新建 UserController 类控制页面跳转。
package controller;

import domain.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import validator.UserValidator;

@Controller
public class UserController {
    private final static Log logger = LogFactory.getLog(UserController.class);
    @RequestMapping(value = "/{formName}")
    public String loginForm(@PathVariable String formName){
        // 动态跳转页面
        return formName;
    }
    // 注入 UserValidator 对象
    @Autowired
    @Qualifier(value = "userValidator")
    private UserValidator userValidator;
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(
            @ModelAttribute User user,
            Model model,
            Errors errors
    ){
        logger.info(user);
        model.addAttribute("user",user);
        // 调用 userValidator 的验证方法
        userValidator.validate(user,errors);
        // 如果验证不通过跳转到 loginForm 视图
        if (errors.hasErrors()){
            return "loginForm";
        }
        return "success";
    }
}

    login 方法将对传进来的参数进行校验,注意方法的最后一个参数 errors,该参数是一个 Spring 校验框架的 Errors 对象。在该方法中调用了之前写的 userValidator 类进行数据校验,如果校验失败,则跳转到“loginForm”视图。

  1. 新建 success.jsp 页面。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功</title>
</head>
<body>
    <form:form modelAttribute="user" method="post" action="">
        <table>
            <tr>
                <td><label>用户名:</label></td>
                <td><form:input path="loginname"/></td>
            </tr>
            <tr>
                <td><label>密码:</label></td>
                <td><form:input path="password"/></td>
            </tr>
        </table>
    </form:form>
</body>
</html>
  1. 修改 Spring MVC 控制文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:component-scan base-package="controller"/>
    <!--  装配自定义的类型转换器  -->
    <mvc:annotation-driven/>
    <!--  使用默认的 Servlet 来响应静态文件  -->
    <mvc:default-servlet-handler/>
    <!--  视图解析器  -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--    前缀    -->
        <property name="prefix">
            <value>/WEB-INF/content/</value>
        </property>
        <!--    后缀    -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>
  1. 修改 Spring 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="validator"/>
</beans>
  1. 修改 web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 部署 ValidatorTest 应用,在浏览器中输入如下 URL 测试应用:
http://localhost:8080/ValidatorTest/loginForm

    不输入登录名和密码直接提交,结果如下所示:
在这里插入图片描述
    输入不合法的登录名和密码,提交后结果如下所示:
在这里插入图片描述
    可以看到,校验框架校验后返回了错误信息并将其显示在页面上。
    由于早期 Spring 就被设计了 Validation 框架,所以之前的很多应用都使用 Validation 框架进行校验。由于 Validation 框架通过硬编码完成数据校验,在实际开发中会显得比较麻烦,因此现代开发更加推荐使用 JSR 303 完成数据校验

    注: 起初运行程序时,程序报错为:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute

    翻译为:

java.lang.IllegalStateException:BindingResult和bean名“user”的纯目标对象都不可用作请求属性

    分析后发现,报错位置应在<form:form modelAttribute="user" method="post" action="login">,在 loginForm.jsp 页面调用 user 时 user 并未被实例化,因此,页面无法调用。

    解决办法:
    在 loginForm.jsp 页面中加入如下代码:

<jsp:useBean id="user" class="domain.User" scope="request"/>

9.1.2 JSR 303 校验

    JSR 303 是 Java 为 Bean 数据合法性校验所提供的一个标准规范,叫做 Bean Validation。官方参考实现是 Hibernate Validator。
    Bean Validation 为 JavaBean 验证定义了相应的元数据类型和 API。在应用程序中,通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标注的验证接口对 Bean 进行验证。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
    JSR 303 是一个规范,它的核心接口是 javax.validation.Validator,该接口根据目标对象中所标注的校验注解进行数据校验,并得到校验结果。JSR 303 目前有两个实现,一个是 Hibernate Validator,另一个是 Apache bval。
    JSR 303 中定义了一套可标注在成员变量、属性方法上的校验注解。

注解 功能 范例
@Null 验证对象是否为 null。 @Null
String desc;
@NotNull 验证对象是否不为 null,无法检查长度为 0 的字符串,用于验证基本数据类型。 @NotNull
String name;
@AssertTrue 验证 Boolean 对象是否为 true。 @AssertTrue
boolean isEmpty;
@Max(value) 验证 Number 和 String 对象是否小于等于指定的值。 @Max(18)
int age;
@Min(value) 验证 Number 和 String 对象是否大于等于指定的值。 @Min(10)
int age;
@DecimalMax(value) 被标注的值必须不大于约束中指定的最大值。这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示,小数存在精度。 @DecimalMax(1.1)
BigDecimal price;
@DecimalMin(value) 被标注的值必须不小于约束中指定的最小值。这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示,小数存在精度。 @DecimalMin(0.5)
BigDecimal Price;
@Digits(integer,fraction) 验证字符串是否是符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度。 @Digits(integer=5,fraction=2)
BigDecimal price;
@Size(min,max) 验证对象(Array、Collection、Map、String)长度是否在给定的范围之内。 @Size(min=15,max=60)
int age;
@Past 验证 Date 和 Callendar 对象是否在当前时间之前。 @Past
Date birthDate;
@Future 验证 Date 和 Callendar 对象是否在当前时间之后。 @Future
Date ShippingDate;
@Pattern 验证 String 对象是否符合正则表达式的规则。 @Pattern(regexp="[1][3,8][3,6,9][0-9]{8}")
String phone;

    Hibernate Validator 是 JSR 303 的一个参考实现,除了支持所有标准的校验注解之外,它还扩展了如下注解:

注解 功能 范例
@NotBlank 检查约束字符串是不是 Null,被 Trim 的长度是否大于 0。只对字符串,且会去掉前后空格。 @NotBlank
String name;
@URL 验证是否是合法的 url。 @URL
String url;
@Email 验证是否是合法的邮件地址。 @Email
String email;
@CreditCardNumber 验证是否是合法的信用卡号码。 @CreditCardNumber
String creditCard;
@Length(min,max) 验证字符串的长度必须在指定的范围内。 @Length(min=6,max=8)
String password;
@NotEmpty 检查元素是否为 NULL 或者 EMPTY。用于 Array、Collection、Map、String。 @NotEmpty
String name;
@Range(min,max,message) 验证属性值必须在合适的范围内。 @Range(min=18,max=60,message=“学生的年龄必须在 18 岁到 60 岁之间”)
int age;

示例:测试 JSR 303 校验

    本例使用的是 Hibernate Validator 的实现,创建 JSR303Test 工程后,将 hibernate-validator-5.2.4.Final.jar、hibernate-validator-annotation-processor-5.2.4.Final.jar、hibernate-validator-cdi-5.2.4.Final.jar、validation-api-1.1.0.Final.jar、classmate-1.1.0.jar 和 jboss-logging-3.2.1.Final.jar 加入项目当中。

  1. 新建 registerForm.jsp 注册页面,用于提交用户注册信息,注册信息包括用户名、密码、邮箱、电话等。之后将在后台使用 JSR 303 进行验证。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试 JSR 303</title>
</head>
<body>
    <h3>注册页面</h3>
    <form:form modelAttribute="user" method="post" action="login">
        <table>
            <tr>
                <td>登录名:</td>
                <td><form:input path="loginname"/></td>
                <td><form:errors path="loginname" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><form:input path="password"/></td>
                <td><form:errors path="password" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>用户名:</td>
                <td><form:input path="username"/></td>
                <td><form:errors path="username" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>年龄:</td>
                <td><form:input path="age"/></td>
                <td><form:errors path="age" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>邮箱:</td>
                <td><form:input path="email"/></td>
                <td><form:errors path="email" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>生日:</td>
                <td><form:input path="birthday"/></td>
                <td><form:errors path="birthday" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td>电话:</td>
                <td><form:input path="phone"/></td>
                <td><form:errors path="phone" cssStyle="color:red"/></td>
            </tr>
            <tr>
                <td><input type="submit" value="提交"/></td>
            </tr>
        </table>
    </form:form>
</body>
</html>

  1. 新建 User 类用于接收用户输入信息,User 类使用了 Hibernate Validator 的注解对前台提交的数据进行验证。
package domain;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    @NotBlank(message="登录名不能为空")
    private String loginname;
    @NotBlank(message = "密码不能为空")
    @Length(min = 6,max = 8,message = "密码长度必须在 6 位到 8 位之间")
    private String password;
    @NotBlank(message = "用户名不能为空")
    private String username;
    @NotBlank(message = "年龄不能为空")
    @Range(min = 15,max = 60,message = "年龄必须在15岁到60岁之间")
    private Integer age;
    @Email(message = "必须是合法的邮箱地址")
    private String email;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Past(message = "生日必须是一个过去的日期")
    private Date birthday;
    @Pattern(regexp = "[1][3,8][3,6,9][0-9]{8}",message = "无效的电话号码")
    private String phone;

    public String getLoginname() {
        return loginname;
    }

    public void setLoginname(String loginname) {
        this.loginname = loginname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}
  1. 新建 UserController 类控制页面跳转。UserController中使用 @Valid 注解对提交的数据进行校验,后面跟着 Errors 对象保存校验信息。如果 errors 中有错误信息,则返回 registerForm.jsp 页面,验证通过则跳转到 success.jsp 页面。
package controller;

import domain.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.validation.Valid;

@Controller
public class UserController {
    private final static Log logger = LogFactory.getLog(UserController.class);
    @RequestMapping(value = "/{formName}")
    public String loginForm(@PathVariable String formName, Model model){
        User user = new User();
        model.addAttribute("user",user);
        // 动态跳转页面。
        return formName;
    }

    // 数据校验使用 @Valid,后面跟着 Errors 对象保存校验信息。
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(
            @Valid @ModelAttribute User user,
            Errors errors,
            Model model){
        logger.info(user);
        if (errors.hasErrors()){
            return "registerForm";
        }
        model.addAttribute("user",user);
        return "success";
    }
}
  1. 新建 success.jsp 页面,用于显示数据校验通过的结果。
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>测试 JSR 303</title>
</head>
<body>
    <h3>测试 JSR 303</h3>
    登录名:${requestScope.user.loginname}<br>
    密码:${requestScope.user.password}<br>
    用户名:${requestScope.user.username}<br>
    年龄:${requestScope.user.age}<br>
    邮箱:${requestScope.user.email}<br>
    生日:<fmt:formatDate value="${requestScope.user.birthday}" pattern="yyyy-MM-dd"/><br>
    电话:${requestScope.user.phone}<br>
</body>
</html>
  1. 修改 Spring MVC 配置文件。由于<mvc:annotation-driven/>会默认装配好一个 LocalValidatorFactoryBean,因此 Spring MVC 配置文件不需增加额外的配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:component-scan base-package="controller"/>
    <!--  装配自定义的类型转换器  -->
    <mvc:annotation-driven/>
    <!--  使用默认的 Servlet 来响应静态文件  -->
    <mvc:default-servlet-handler/>
    <!--  视图解析器  -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--    前缀    -->
        <property name="prefix">
            <value>/WEB-INF/content/</value>
        </property>
        <!--    后缀    -->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>
  1. 修改 web.xml 文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 部署 JSR303Test 应用,在浏览器中输入如下 URL:
http://localhost:8080/JSR303Test/registerForm

        结果如下图所示:
在这里插入图片描述
        输入错误信息,直接单击提交,后台验证不通过,如下图所示:
在这里插入图片描述
在这里插入图片描述
        输入符合校验规则的注册信息,通过验证后会跳转到 success 页面。如下图所示:
在这里插入图片描述
    以上使用注解的 message 属性输出错误信息,而在实际项目中,我们希望错误信息更加人性化、更具可读性,同时还希望显示国际化的错误信息。
    Spring MVC 支持国际化显示数据校验的错误信息。每个属性在数据绑定和数据校验发生错误时,都会生成一个对应的 FieldError 对象,FieldError 对象实现了 org.springframework.context.MessageSourceResolvable 接口,顾名思义,MessageSourceResolvable 是可用国际化资源进行解析的对象。MessageSourceResolvable 接口有如下3个方法:

  • Object[] getArguments()。返回一组参数对象。
  • String[] getCodes()。返回一组消息代码,每一个代码对应一个属性资源,可以使用 getArguments() 返回的参数对资源属性进行参数替换。
  • String getDefaultMessage()。默认的消息,如果没有装配相应的国际化资源,那么显示的所有错误信息都是默认的。

    当一个属性校验失败后,校验框架会为该属性生成4个消息代码,这些代码以校验注解类名为前缀,结合类名、属性名以及属性类型名生成多个对应的消息代码。
    当使用 Spring MVC 标签显示错误信息时,Spring MVC 会查看 Web 上下文是否装配了对应的国际化消息,如果没有,则显示默认的错误信息,否则使用国际化消息对错误代码进行显示。
    知道错误对象的错误码是对应国际化消息的键名称后,定义两个国际化资源文件,在国际化资源文件中为错误代码定义相应的本地化消息内容。
    文件名为:message_en_US.properties

NotBlank.user.loginname= 登录名不能为空
NotBlank.user.password= 密码不能为空
Length.user.password= 密码长度必须在6位到8位之间
NotBlank.user.username= 用户名不能为空
Range.user.age= 年龄必须在15岁到60岁之间
Email.user.email= 必须是合法的邮箱地址
Past.user.birthday= 生日必须是一个过去的日期
Pattern.user.phone= 无效的电话号码

    文件名为:message_zh_CN.properties

NotBlank.user.loginname = Loginname is not null
NotBlank.user.password = Password is not null
Length.user.password = Password length must be between 6 and 8
NotBlank.user.username = Username is not null
Range.user.age = Age must be between the ages of 15 to 60
Email.user.email = Must be a legitimate email address
Past.user.birthday = Birthday must be a date in the past
Pattern.user.phone = Invalid phone number

    接下来在 Spring MVC 配置文件中增加国际化配置。
在这里插入图片描述
在这里插入图片描述
    通过该选项创建属性文件。然后在 Spring MVC 配置文件中增加国际化配置。

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <!--  国际化资源文件  -->
        <property name="basename" value="message"/>
    </bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章