1. 程式人生 > >SpringMVC——數據轉換 & 數據格式化 & 數據校驗

SpringMVC——數據轉換 & 數據格式化 & 數據校驗

gpo new open util tro -m 註解 構造 param

一、數據綁定流程

  • 1. Spring MVC 主框架將 ServletRequest 對象及目標方 法的入參實例傳遞給 WebDataBinderFactory 實例,以創 建 DataBinder 實例對象
  • 2. DataBinder 調用裝配在 Spring MVC 上下文中的 ConversionService 組件進行數據類型轉換、數據格式 化工作。將 Servlet 中的請求信息填充到入參對象中
  • 3. 調用 Validator 組件對已經綁定了請求消息的入參對象 進行數據合法性校驗,並最終生成數據綁定結果 BindingData 對象
  • 4. Spring MVC 抽取 BindingResult 中的入參對象和校驗 錯誤對象,將它們賦給處理方法的響應入參

Spring MVC 通過反射機制對目標處理方法進行解析,將請 求消息綁定到處理方法的入參中。數據綁定的核心部件是 DataBinder,運行機制如下:

技術分享圖片

源碼分析

  • 在JavaBean對象的屬性setter方法處打斷點調試
  • 在調試頁面進入org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throws
Exception { String name = ModelFactory.getNameForParameter(parameter); Object attribute = mavContainer.containsAttribute(name)?mavContainer.getModel().get(name):this.createAttribute(name, parameter, binderFactory, request); //創建binderd對象 WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
if(binder.getTarget() != null) { //數據的綁定 this.bindRequestParameters(binder, request); //完成數據的校驗 this.validateIfApplicable(binder, parameter); if(binder.getBindingResult().hasErrors()
      && this.isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } Map bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return binder.getTarget(); }
  • 查看Binder對象的屬性

技術分享圖片

  • 可以看到binder包含了ConversionService和validators屬性,它們分別處理類型轉換和數據校驗

二、數據轉換

  • Spring MVC 上下文中內建了很多轉換器,可完成大多數 Java 類型的轉換工作。
  • ConversionService converters =

技術分享圖片

自定義類型轉換器

ConversionService 是 Spring 類型轉換體系的核心接口。

  • 可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定義一個 ConversionService。Spring 將自動識別出 IOC 容器中的 ConversionService,並在 Bean 屬性配置及 Spring MVC 處理方法入參綁定等場合使用它進行數據的轉換
  • 可通過 ConversionServiceFactoryBean 的 converters 屬性 註冊自定義的類型轉換器

三、數據格式化

  1. 在表單添加birthday(生日)輸入框,同時在Javabean中天機brith屬性,屬性的類型為Java.util.Date
  2. 提交表單時,頁面報400錯誤,數據無法提交到目標方法
  3. 原因:輸入框的birthday沒有進行格式化

解決方法:

在Javabean對象的birth屬性上加註解

 @DateTimeFormat(pattern = "yy-mm-dd")
 private Date birth;

①、日期格式化

@DateTimeFormat 註解可對 java.util.Date、java.util.Calendar、java.long.Long 時間 類型進行標註:

  • pattern 屬性:類型為字符串。指定解析/格式化字段數據的模式, 如:”yyyy-MM-dd hh:mm:ss”
  • iso 屬性:類型為 DateTimeFormat.ISO。指定解析/格式化字段數據 的ISO模式,包括四種:ISO.NONE(不使用) -- 默 認、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、 ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
  • style 屬性:字符串類型。通過樣式指定日期時間的格式,由兩位字 符組成,第一位表示日期的格式,第二位表示時間的格式:S:短日 期/時間格式、M:中日期/時間格式、L:長日期/時間格式、F:完整 日期/時間格式、-:忽略日期或時間格式

②、數值格式化

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

  • style:類型為 NumberFormat.Style。用於指定樣式類 型,包括三種:Style.NUMBER(正常數字類型)、 Style.CURRENCY(貨幣類型)、 Style.PERCENT( 百分數類型)
  • pattern:類型為 String,自定義樣式, 如patter="#,###";

③、源碼分析

  • Spring MVC 上下文中內建了很多格式化處理器,可完成大多數 Java數據類型的格式化。
  • ConversionService converters =

技術分享圖片

  • 對屬性對象的輸入/輸出進行格式化,從其本質上講依然 屬於 “類型轉換” 的範疇。
  • Spring 在格式化模塊中定義了一個實現 ConversionService 接口的 FormattingConversionService 實現類,該實現類擴展 了 GenericConversionService,因此它既具有類型轉換的功能,又具有格式化的功能
  • FormattingConversionService 擁有一個 FormattingConversionServiceFactroyBean 工廠類, 後者用於在 Spring 上下文中構造前者

FormattingConversionServiceFactroyBean 內部已經註冊了 :

  • NumberFormatAnnotationFormatterFactroy:支持對數字類型的屬性 使用 @NumberFormat 註解
  • DateTimeFormatAnnotationFormatterFactroy:支持對日期類型 的屬性使用 @DateTimeFormat 註解
  • 裝配了 FormattingConversionServiceFactroyBean 後,就可 以在 Spring MVC 入參綁定及模型數據輸出時使用註解了。
  • 默認創建的 ConversionService 實例即為 FormattingConversionServiceFactroyBean

④、自定義數據類型格式化&數據轉換

  <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>    
    
    <!-- 配置 ConversionService -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="自定義類型格式化&轉換實現類"/>
            </set>
        </property>    
    </bean>

四、數據校驗

  JSR 303 是 Java 為 Bean 數據合法性校驗提供的標準框架, 它已經包含在 JavaEE 6.0 中 .JSR 303 通過在 Bean 屬性上標註類似於 @NotNull、@Max 等標準的註解指定校驗規則,並通過標準的驗證接口對 Bean 進行驗證

Hibernate Validator 擴展註解:

  • Hibernate Validator 是 JSR 303 的一個實現,除支持 所有標準的校驗註解外,它還支持以下的擴展註解

校驗流程

①. 使用 JSR 303 驗證標準
②. 加入 hibernate validator 驗證框架的 jar 包

hibernate-validator-5.0.0.CR2.jar
hibernate-validator-annotation-processor-5.0.0.CR2.jar
classmate-0.8.0.jar
jboss-logging-3.1.1.GA.jar
validation-api-1.1.0.CR1.jar

③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
④. 需要在 bean 的屬性上添加對應的註解

技術分享圖片
package com.nchu.mybatis.bean;

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

import java.util.Date;

/**
 * Created by yangshijing on 2017/12/4 0004.
 */
public class Employee {
    private Integer id;
    private String lastName;
    @Email
    private String email;
    private String gender;
    private Integer deptId;
    @DateTimeFormat(pattern = "yy-mm-dd")
    private Date birth;
    public Employee() {
    }

    public Employee(String email, String gender, Integer id, String lastName,Integer deptId) {
        this.email = email;
        this.gender = gender;
        this.id = id;
        this.lastName = lastName;
        this.deptId = deptId;
    }

    public Date getBirth() {
        return birth;
    }

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

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getEmail() {
        return email;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    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;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName=‘" + lastName + ‘\‘‘ +
                ", email=‘" + email + ‘\‘‘ +
                ", gender=‘" + gender + ‘\‘‘ +
                ",birth="+ birth +
                ‘}‘;
    }
}
View Code

⑤. 在目標方法 bean 類型的前面添加 @Valid 註解

  /**
     *添加employee接口
     * @param employee
     * @return
     */
    @RequestMapping(value = "/emp" ,method= RequestMethod.POST)
    public String save(@Valid Employee employee, Map<String,Object> map){
        try{
            employeeService.saveEmp(employee);
        }catch (Exception e){
            e.printStackTrace();
        }
       return "redirect:/employee/getemps";
    }

⑥、表單email項未輸入email格式時,無法訪問到目標方法,並在控制臺打印出錯誤信息

SpringMVC——數據轉換 & 數據格式化 & 數據校驗