SpringMVC學習筆記 | 數(shù)據(jù)轉(zhuǎn)換、數(shù)據(jù)格式化、數(shù)據(jù)校驗

數(shù)據(jù)綁定

數(shù)據(jù)綁定流程

  • SpringMVC主框架將ServletRequest對象及目標方法的入?yún)嵗齻鬟f給WebDataBinderFactory實例,以創(chuàng)建DataBinder實例對象。
  • DataBinder調(diào)用裝配在SpringMVC上下文中的ConversionService組件進行數(shù)據(jù)類型轉(zhuǎn)換、數(shù)據(jù)格式化工作,將Servlet中的請求信息填充到入?yún)ο笾小?/li>
  • 調(diào)用Validator組件對已經(jīng)綁定了請求消息的入?yún)ο筮M行數(shù)據(jù)合法性校驗,并最終生成數(shù)據(jù)綁定結果BindingData對象。
  • SpringMVC抽取BindingResult中的入?yún)ο蠛托r炲e誤對象,將他們賦給處理方法的響應入?yún)ⅰ?/li>

類型轉(zhuǎn)換

自定義類型轉(zhuǎn)換器

ConversionService是Spring類型轉(zhuǎn)換體系的核心接口,可以利用ConversionServiceFactoryBean在Spring的IOC容器中定義一個ConversionService。Spring將自動識別出IOC容器中的ConversionService,并在bean屬性配置及SpringMVC處理方法入?yún)⒔壎ǖ葓龊鲜褂盟M行數(shù)據(jù)的轉(zhuǎn)換。
可以通過ConversionServiceFactoryBeanconverters屬性注冊自定義的類型轉(zhuǎn)換器。

<bean id="conversionService" 
        class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <ref bean="employeeConverter"/>
        </set>
    </property>
</bean>

Spring支持的轉(zhuǎn)換器

Spring定義了3種類型的轉(zhuǎn)換器接口,實現(xiàn)任意一個轉(zhuǎn)換器接口都可以作為自定義轉(zhuǎn)換器注冊到ConversionServiceFactroyBean

  • Converter<S,T>:將S類型對象轉(zhuǎn)為T類型對象。
  • ConverterFactory:將相同系列多個“同質(zhì)”Converter封裝在一起,如果希望將一種類型的對象轉(zhuǎn)換為另一種類型及其子類的對象(例如將String轉(zhuǎn)換為Number及Number子類(Integer、Long、Double等)對象)可使用該轉(zhuǎn)換器工廠類。
  • GenericConverter:會根據(jù)源類對象及目標類對象所在的宿主類中的上下文信息進行類型轉(zhuǎn)換。

在配置文件中使用<mvc:annotation-driven conversion-service="xxxxx"/>會將自定義的ConversionService注冊到SpringMVC的上下文中。,其中xxxxx是自定義的類型轉(zhuǎn)換器名,例如:

<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 配置ConversionService-->
<bean id="conversionService" 
          class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
         <set>
             <ref bean="employeeConverter"/>
         </set>
    </property>
</bean>

我們來自定義一個類型轉(zhuǎn)換器,我們希望輸入一個字符串(lastname-email-gender-department.id),然后提交后能轉(zhuǎn)換為一個Employee對象。

  • 首先建立我們的兩個實體類及對應的dao類
package com.cerr.springmvc.crud.entities;

public class Employee {
    private Integer id;
    private String lastname;
    private String email;
    private Integer gender;
    private Department department;

    public Employee(){}

    public Employee(Integer id, String lastname, String email, Integer gender, Department department) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.department = department;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastname='" + lastname + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                ", department=" + department +
                '}';
    }
}
package com.cerr.springmvc.crud.entities;

public class Department {
    private Integer id;
    private String departmentName;

    public Department() {}

    public Department(Integer id, String departmentName) {
        super();
        this.id = id;
        this.departmentName = departmentName;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getDepartmentName() {
        return departmentName;
    }
    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }
}
package com.cerr.springmvc.crud.dao;

import com.cerr.springmvc.crud.entities.Department;
import com.cerr.springmvc.crud.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Repository
public class EmployeeDao {

    private static Map <Integer, Employee > employees = null;

    @Autowired
    private DepartmentDao departmentDao;

    static{
        employees = new HashMap <Integer, Employee>();

        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));
    }

    private static Integer initId = 1006;

    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }

        employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
        employees.put(employee.getId(), employee);
    }

    public Collection <Employee> getAll(){
        return employees.values();
    }

    public Employee get(Integer id){
        return employees.get(id);
    }

    public void delete(Integer id){
        employees.remove(id);
    }
}
  • 建立我們自定義的轉(zhuǎn)換器類,需要實現(xiàn)Converter<S,T>接口
package com.cerr.springmvc.converters;

import com.cerr.springmvc.crud.entities.Department;
import com.cerr.springmvc.crud.entities.Employee;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

//該注釋讓該類能加載到IOC容器中
@Component
public class EmployeeConverter implements Converter<String, Employee > {

    /**
     * 這是轉(zhuǎn)換的方法,對傳入的字符串進行分割。
     * 然后填充Employee的參數(shù)來初始化一個Employee實例,然后返回
     * @param s
     * @return
     */
    @Override
    public Employee convert(String s) {
        if (s != null){
            String [] vals = s.split("-");
            if (vals != null && vals.length == 4){
                String lastName = vals[0];
                String email = vals[1];
                Integer gender = Integer.parseInt(vals[2]);
                Department department = new Department();
                department.setId(Integer.parseInt(vals[3]));
                Employee employee = new Employee(null,lastName,email,gender,department);
                System.out.println(employee);
                return employee;
            }
        }
        return null;
    }
}
  • 在配置文件中配置:
<?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 配置自動掃描的包-->
    <context:component-scan base-package="com.cerr.springmvc"/>

    <!-- 配置視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/webViews/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <mvc:default-servlet-handler/>
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!-- 配置ConversionService-->
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <!-- 
                因為我們自己寫的自定義轉(zhuǎn)換器類使用了Component進行標識,
                所以此處的bean名直接寫employeeConverter(類名第一個字母小寫)即可
                -->
                <ref bean="employeeConverter"/>
            </set>
        </property>
    </bean>
</beans>

測試:

package com.cerr.springmvc.test;

import com.cerr.springmvc.crud.dao.EmployeeDao;
import com.cerr.springmvc.crud.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class SpringMVCTest1 {
    @Autowired
    private EmployeeDao employeeDao;
    @RequestMapping(value = "/testConversionServiceConverer",method = RequestMethod.POST)
    public String testConverter(@RequestParam("employee") Employee employee){
        employeeDao.save(employee);
        System.out.println(employee);
        return "redirect:/emps";
    }
}

表單:

<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%--
  Created by IntelliJ IDEA.
  User: 白菜
  Date: 2019/11/13
  Time: 21:10
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/testConversionServiceConverer" method="POST">
        <!-- 格式:lastname-email-gender-department.id 例如:GG-gg@cerr.com-0-105 -->
        Employee : <input type="text" name="employee" />
        <input type="submit" value="submit" />
    </form>
</body>
</html>

輸入:GG-gg@cerr.com-0-105
結果:在控制臺成功打印出Employee(轉(zhuǎn)換成功)

關于mvc:annotation-driven

<mvc:annotation-driven/>會自動注冊RequestMappingHandlerMapping、RequestMappingHandlerAdapterExceptionHandlerExceptionResolver三個bean。
還將提供以下支持:

  • 支持使用ConversionService實例對表單參數(shù)進行類型轉(zhuǎn)換
  • 支持使用@NumberFormatannotation、@DateTimeFormat注解完成數(shù)據(jù)類型的格式化
  • 支持使用@Valid注解對JavaBean實例進行JSR 303驗證
  • 支持使用@RequestBody@ResponseBody注解

@InitBinder

@InitBinder標識的方法,可以對WebDataBinder對象進行初始化。WebDataBinder是DataBinder的子類,用于完成由表單字段到JavaBean屬性的綁定。
@InitBinder方法不能有返回值,必須聲明為void;@InitBinder方法的參數(shù)通常是WebDataBinder

例如我們這里定義一個initBinder方法,然后方法體里面的設置對于表單的lastname屬性不允許綁定到JavaBean順序。

@InitBinder
    public void initBinder(WebDataBinder binder){
        binder.setDisallowedFields("lastname");
    }

數(shù)據(jù)格式化

對屬性對象的輸入/輸出進行格式化,從其本質(zhì)上講依然屬于“類型轉(zhuǎn)換”的范疇。Spring在格式化模塊中定義了一個實現(xiàn)ConversionService接口的FarmattingConversionService實現(xiàn)類,該實現(xiàn)類擴展了GenericConversionService,因此它既具有類型轉(zhuǎn)換的功能,又具有格式化的功能。FormattingConversionService擁有一個FormattingConversionServiceFactoryBean工廠類,后者用于在Spring上下文中構造前者。

對于FormattingConversionServiceFactoryBean,內(nèi)部已經(jīng)注冊了:

  • NumberFormatAnnotationFormatterFactory:支持對數(shù)字類型屬性使用@NumberFormat注解
  • JodaDateTimeFormatAnnotationFormatterFactory:支持對日期類型的屬性使用@DataTimeFormat注解

如果裝配了FormattingConversionServiceFactoryBean,就可以在SpringMVC入?yún)⒔壎澳P蛿?shù)據(jù)輸出時使用注解驅(qū)動了,<mvc:annotation-driven />默認創(chuàng)建的ConversionService實例即為FormattingConversionServiceFactoryBean。

日期格式化

@DateTimeFOrmat注解可對java.util.Datejava.util.Calendar、java.long.Long時間類型進行標注,比較重要的屬性:

  • pattern屬性:類型為字符串,指定解析/格式化字段數(shù)據(jù)的模式,如:"yyyy-MM-dd hh:mm:ss"。
package com.cerr.springmvc.crud.entities;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import java.util.Date;

public class Employee {
    private Integer id;
    private String lastname;
    private String email;
    private Integer gender;
    private Department department;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
    private Float sarly;
    public Employee(){}

    public Employee(Integer id, String lastname, String email, Integer gender, Department department) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.department = department;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Float getSarly() {
        return sarly;
    }

    public void setSarly(Float sarly) {
        this.sarly = sarly;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastname='" + lastname + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                ", department=" + department +
                ", birth=" + birth +
                ", sarly=" + sarly +
                '}';
    }
}

在上面的例子中,我們注解的pattern為"yyyy-MM-dd",因此當我們輸入的日期為"yyyy-MM-dd"時都能給解析并轉(zhuǎn)換成Date。

數(shù)值格式化

@NumberFormat可對類似數(shù)字類型的屬性進行標注,它擁有兩個互斥的屬性:

  • style
    類型為Numberformat.Style。用于指定樣式類型,包括三種:Style.NUMBER(正常數(shù)字類型)、Style.CURRENCY(貨幣類型)、Style.PERCENT(百分數(shù)類型)。
  • pattern
    類型為String,自定義樣式,如pattern="#,###"。
package com.cerr.springmvc.crud.entities;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import java.util.Date;

public class Employee {
    private Integer id;
    private String lastname;
    private String email;
    private Integer gender;
    private Department department;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
    @NumberFormat(pattern = "#,###,###.#")
    private Float sarly;

    public Employee(){}

    public Employee(Integer id, String lastname, String email, Integer gender, Department department) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.department = department;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Float getSarly() {
        return sarly;
    }

    public void setSarly(Float sarly) {
        this.sarly = sarly;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastname='" + lastname + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                ", department=" + department +
                ", birth=" + birth +
                ", sarly=" + sarly +
                '}';
    }
}

上面的代碼標識了@NumberFormat(pattern = "#,###,###.#")后,例如輸入1,234,567.8,就能自動轉(zhuǎn)成數(shù)字。


數(shù)據(jù)校驗

JSR303

JSR 303是Java為Bean數(shù)據(jù)合法性校驗提供的標準框架,它已經(jīng)包含在JavaEE6.0中,JSR 303通過在Bean屬性上標注類似于@NotNull、@Max等標準的注解指定校驗規(guī)則,并通過標準的驗證接口對Bean進行驗證。

注解 功能說明
@Null 被注釋的元素必須為null
@NotNull 被注釋的元素必須不為null
@AssertTure 被注釋的元素必須為true
@AssertFalse 被注釋的元素必須為false
@Min(value) 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值
@Max(value) 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值
@DecimalMax(value) 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值
@Size(max,min) 被注釋的元素必須在指定的范圍內(nèi)
@Digits(integer,fraction) 被注釋的元素必須是一個數(shù)字,其值必須在可接受的范圍內(nèi)
@Past 被注釋的元素必須是一個過去的日期
@Future 被注釋的元素必須是一個將來的日期
@Pattern(value) 被注釋的元素必須符合指定的正則表達式

Hibernate Validator擴展注解

Hibernate Validator是JSR 303的一個參考實現(xiàn),除支持所有標準的校驗注解外,它還支持以下的擴展注解

注解 功能說明
@Email 被注釋的元素必須是電子郵箱地址
@Length 被注釋的字符串的大小必須在指定的范圍內(nèi)
@NotEmpty 被注釋的字符串必須非空
@Range 被注釋的元素必須在合適的范圍內(nèi)

SpringMVC數(shù)據(jù)校驗

Spring4.0擁有自己獨立的數(shù)據(jù)校驗框架,同時支持JSR 303標準的校驗框架。Spring在進行數(shù)據(jù)綁定時,可同時調(diào)用校驗框架完成數(shù)據(jù)校驗工作。在SpringMVC中,可直接通過注解驅(qū)動的方式進行數(shù)據(jù)校驗。

Spring的LocalValidatorFactoryBean既實現(xiàn)了Spring的Validator接口,也實現(xiàn)了JSR 303的Validator接口,只要在Spring容器中定義一個LocalValidatorFactoryBean,即可將其注入到需要數(shù)據(jù)校驗的Bean中。

Spring本身并沒有提供JSR 303的實現(xiàn),所以必須將JSR 303的jar包放到類路徑下。

<mvc:annotation-driven />會默認裝配好一個LocalValidatorFactroyBean,通過在處理方法的入?yún)⑸蠘俗?code>@valid注解即可讓SpringMVC在完成數(shù)據(jù)綁定后執(zhí)行數(shù)據(jù)校驗的工作。

在已經(jīng)標注了JSR 303注解的表單/命令對象前標注一個@Valid,SpringMVC框架在將請求參數(shù)綁定到該入?yún)ο蠛?,就會調(diào)用校驗框架根據(jù)注解聲明的校驗規(guī)則實施校驗。

SpringMVC是通過對處理方法簽約的規(guī)約來保存校驗結果的:前一個表單/命令對象的校驗結果保存到隨后的入?yún)⒅?,這個保存校驗結果的入?yún)⒈仨毷?code>BindingResult或Errors類型,這兩個類都位于org.springframework.validation包中。要注意的一點是:需要校驗的Bean對象和其綁定結果對象或錯誤對象是成對出現(xiàn)的,它們之間不允許聲明其他的入?yún)?/strong>
例如下面的代碼是錯誤的:

@RequestMapping(value = "/emp",method = RequestMethod.POST)
    public String save(@Valid Employee employee, Map<String,Object> map,BindingResult result){
       
        return "redirect:/emps";
    }

Employee和BindingResult兩個參數(shù)應該是在一起的,例如下面的才是正確的:

@RequestMapping(value = "/emp",method = RequestMethod.POST)
    public String save(@Valid Employee employee, BindingResult result,Map<String,Object> map){
        
        return "redirect:/emps";
    }

Errors接口提供了獲取錯誤信息的方法,如getErrorCount()getFieldErrors(String field)BindingResult擴展了Errors接口。

@RequestMapping(value = "/emp",method = RequestMethod.POST)
    public String save(@Valid Employee employee, BindingResult result,Map<String,Object> map){
        System.out.println("save:"+employee);
        /**
         * 如果轉(zhuǎn)換出錯
         */
        if (result.getErrorCount() > 0){
            System.out.println("出錯了:");
            for (FieldError error : result.getFieldErrors()){
                System.out.println(error.getField() + ":" + error.getDefaultMessage());
            }
            map.put("departments",departmentDao.getDepartments());
            
            //若驗證出錯,則轉(zhuǎn)向定制的頁面
            return "input";
        }
        employeeDao.save(employee);
        return "redirect:/emps";
    }

SpringMVC整合擴展的Hibernate Validator驗證框架數(shù)據(jù)校驗的步驟

  • 使用JSR 303驗證標準完成數(shù)據(jù)校驗。
  • 加入hibernate validator驗證框架的jar包。
  • 在SpringMVC配置文件中添加<mvc:annotation-dirven />
  • 需要在bean的屬性上添加對應的注解
  • 在目標方法bean類型的前面添加@Valid注解

首先在idea中加入jar包,并添加在Artifacts中


然后在配置文件中添加<mvc:annotation-dirven />,因為該配置在上面類型轉(zhuǎn)換時定義了一個自定義的類型轉(zhuǎn)換器,因此配置了FormattingConversionServiceFactoryBean,如果不需要使用自定義類型轉(zhuǎn)換器的話,這部分代碼可以去掉:

<?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 配置自動掃描的包-->
    <context:component-scan base-package="com.cerr.springmvc"/>
    <!-- 配置視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/webViews/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <mvc:default-servlet-handler/>
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!-- 配置ConversionService   org.springframework.context.support.ConversionServiceFactoryBean也可以-->
    <bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

        <property name="converters">
            <set>
                <ref bean="employeeConverter"/>
            </set>
        </property>
    </bean>
</beans>

對上面的Employee類,我們可以做一些驗證如下,添加@NotNull、@Email、@Past注解:

package com.cerr.springmvc.crud.entities;

import org.hibernate.validator.constraints.Email;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import java.util.Date;

public class Employee {
    private Integer id;

    @NotNull
    private String lastname;
    @Email
    private String email;

    private Integer gender;
    private Department department;

    @Past
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
    @NumberFormat(pattern = "#,###,###.#")
    private Float sarly;

    public Employee(){}

    public Employee(Integer id, String lastname, String email, Integer gender, Department department) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.department = department;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Float getSarly() {
        return sarly;
    }

    public void setSarly(Float sarly) {
        this.sarly = sarly;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }


    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastname='" + lastname + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                ", department=" + department +
                ", birth=" + birth +
                ", sarly=" + sarly +
                '}';
    }
}

并在處理的方法中的入?yún)⒅袑σr灥膶嶓w類標注@Valid,如果需要使用到BindingResult等類的話要注意要和@Valid標注的實體類成對存在:

@RequestMapping(value = "/emp",method = RequestMethod.POST)
    public String save(@Valid Employee employee, BindingResult result,Map<String,Object> map){
        System.out.println("save:"+employee);
        /**
         * 如果轉(zhuǎn)換出錯
         */
        if (result.getErrorCount() > 0){
            System.out.println("出錯了:");
            for (FieldError error : result.getFieldErrors()){
                System.out.println(error.getField() + ":" + error.getDefaultMessage());
            }
            map.put("departments",departmentDao.getDepartments());
            
            //若驗證出錯,則轉(zhuǎn)向定制的頁面
            return "input";
        }
        employeeDao.save(employee);
        return "redirect:/emps";
    }

如果輸入錯誤,則輸出結果如下:


在頁面上顯示錯誤

在JSP頁面上通過<form:errors path="屬性名" />顯示錯誤消息

<form:errors path="lastname"/><br>

如果要一次性顯示所有錯誤消息,可以將path寫為*,即:

<form:errors path="*"/><br>

提示消息的國際化

每個屬性在數(shù)據(jù)綁定和數(shù)據(jù)校驗發(fā)生錯誤時,都會生成一個對應的FieldError對象。當一個屬性校驗失敗后,校驗框架會為該屬性生成4個消息代碼,這些代碼以校驗注解類名為前綴,結合modleAttribute、屬性名及屬性類型名生成多個對應的消息代碼。
例如User類中的password屬性標注了一個@Pattern注解,當該屬性值不滿足@Pattern所定義的規(guī)則時,就會產(chǎn)生以下4個錯誤代碼:

  • Pattern.user.password
  • Pattern.password
  • Pattern.java.lang.String
  • Pattern

當使用SpringMVC標簽顯示錯誤消息時,SpringMVC會查看WEB上下文是否裝配了對應的國際化消息,如果沒有,則顯示默認的錯誤消息,否則使用國際化消息。

定制提示消息的話,我們要先定義一個國際化資源文件,例如i18n.properties文件,并且寫入需要定制化的消息:

NotNull.employee.lastname=lastname\u4e0d\u80fd\u4e3a\u7a7a
Email.employee.email=Email\u4e0d\u5408\u6cd5
Past.employee.birth=Birth\u4e0d\u80fd\u662f\u4e00\u4e2a\u5c06\u6765\u7684\u65f6\u95f4
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容