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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章