SpringMVC之WebDataBinder處理請求參數綁定(二)

在上一章節,SpringBoot2.x系列教程29--整合SpringMVC之@InitBinder處理請求參數的綁定(上)的內容中,我給大家講解了@InitBinder的原理及使用教程,本章節我繼續講解SpringMVC中的參數傳遞及數據綁定。

本章節主要是講解WebDataBinder的內容。

一. WebDataBinder簡介

從上面的代碼案例中,我們可以看到另一個類,那就是WebDataBinder!

1. WebDataBinder的由來

在servlet中,有一個方法:request.getParameter("paramName"),它會根據key返回一個String類型的數據。

但是如果我們這樣一個一個地去取出web中的請求參數,那就會很麻煩。我們知道Java中有對象的概念,那有沒有辦法將request中的請求參數自動封裝到一個Java對象中呢? 爲了解決這個問題,Spring中引入了WebDataBinder。

2. WebDataBinder類關係

3. WebDataBinder的作用

WebDataBinder的作用是從web request中把web請求裏的parameters綁定到對應的JavaBean上!

在Controller方法中的參數類型可以是基本類型,也可以是封裝後的普通Java類型。若這個普通的Java類型沒有聲明任何註解,則意味着它的每一個屬性都需要到Request中去查找對應的請求參數,而WebDataBinder則可以幫助我們實現從Request中取出請求參數並綁定到JavaBean中。

4. WebDataBinder工作機制

WebDataBinder是用來綁定請求參數到指定的屬性編輯器裏的。由於前臺傳到Controller裏的值是String類型,當往Java Bean裏設置這個值的時候,如果設置的這個屬性是個對象,Spring就會去找到對應的編輯器editor進行轉換,然後再設置進去!

Spring自己提供了大量的實現類,諸如CustomDateEditor,CustomBooleanEditor,CustomNumberEditor等,基本上夠我們開始使用。

但在平時使用SpringMVC時,可能會碰到Java Bean中有Date類型的參數,表單中傳來代表日期的字符串轉化爲日期類型,SpringMVC在默認時,是不支持這種類型轉換的。此時我們就需要手動設置時間格式並在WebDateBinder上註冊這個編輯器!

5. 示例代碼

@InitBinder  
public void bindingPreparation(WebDataBinder binder) {  
  DateFormat dateFormat1 = new SimpleDateFormat("dd-MM-yyyy");  
  CustomDateEditor orderDateEditor = new CustomDateEditor(dateFormat1, true);  
  DateFormat dateFormat2 = new SimpleDateFormat("MMM d, YYYY");  
  CustomDateEditor shipDateEditor = new CustomDateEditor(dateFormat2, true);  
  binder.registerCustomEditor(Date.class, "orderDate", orderDateEditor);  
  binder.registerCustomEditor(Date.class, "shipDate", shipDateEditor);  
}

二. WebDataBinder實現過程

WebDataBinder一般都要結合@InitBinder來一起使用。

1.創建web項目

我們在上一個項目的基礎之上直接編寫本案例。

項目結構:

2. 創建User類

我們在項目中創建domain包,在該包下創建一個User類。

package com.yyg.boot.domain;

import lombok.Data;

import java.util.Date;

/**
 * @Description Description
 * @Author 一一哥Sun
 * @Date Created in 2020/3/23
 */
@Data
public class User {

    private String name;

    private String password;

    private String email;

    private Date birthday;

}

3. Validator接口介紹

  • Validator 是一個有兩個方法的接口;
  • boolean supports(Class<?> clazz) : 檢驗參數是否驗證成功的實例類;
  • void validate(Object target, Errors errors) : 如果 supports() 方法返回真, target object 合法. Errors.rejectValue() 方法用一個字段名註冊錯誤信息。

4. 創建UserValidator驗證類

我們創建一個validator包,在該包下面創建一個UserValidator驗證類。

package com.yyg.boot.validator;

import com.yyg.boot.domain.User;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * @Description Description
 * @Author 一一哥Sun
 * @Date Created in 2020/3/23
 */
@Component
public class UserValidator implements Validator {

    /**
     * 檢驗參數是否驗證成功的實例類
     */
    @Override
    public boolean supports(Class<?> clazz) {
        //isAssignableFrom()方法是判斷是否爲某個類的父類,instanceof關鍵字是判斷是否某個類的子類。
        return User.class.isAssignableFrom(clazz);
    }

    /**
     * 如果 supports() 方法返回真, target object 合法. Errors.rejectValue() 方法會用一個字段名註冊錯誤信息;
     */
    @Override
    public void validate(Object target, Errors errors) {
        User user = (User)target;
        //配置字段驗證信息
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "","Username is empty");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "", "Password is empty");
        //用戶名長度不能小於5個字符
        if (user.getName().length()<5) {
            errors.rejectValue("name","", "Username length is less than 5");
        }
    }

}

5. 創建EmailValidator驗證類

我們創建一個validator包,在該包下面創建一個EmailValidator驗證類。

package com.yyg.boot.validator;

import com.yyg.boot.domain.User;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * @Description Description
 * @Author 一一哥Sun
 * @Date Created in 2020/3/23
 */
@Component
public class EmailValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        User user = (User)target;
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "","Email is empty");
        if (!user.getEmail().contains("@")) {
            errors.rejectValue("email","", "Email is not valid.");
        }
    }

}

6. 創建ValidatorController測試接口

我們創建一個web包,在該包下面創建一個ValidatorController類。

package com.yyg.boot.web;

import com.yyg.boot.domain.User;
import com.yyg.boot.validator.EmailValidator;
import com.yyg.boot.validator.UserValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Description Description
 * @Author 一一哥Sun
 * @Date Created in 2020/3/23
 */
@Controller
public class ValidatorController {

    @Autowired
    private UserValidator userValidator;

    @Autowired
    private EmailValidator emailValidator;

    /**
     * 接收參數,自定義編輯器
     */
    @InitBinder
    public void dataBinding(WebDataBinder binder) {
        binder.addValidators(userValidator, emailValidator);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        //setLenient用於設置Calendar是否寬鬆解析字符串,如果爲false,則嚴格解析;默認爲true,寬鬆解析
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, "birthday", new CustomDateEditor(dateFormat, true));
    }

    @ResponseBody
    @RequestMapping(value = "/user", method = RequestMethod.POST)
    public String createUser(@RequestBody @Valid User user, BindingResult result) {
        if (result.hasErrors()) {
            return result.getFieldError().getDefaultMessage();
        }
        System.out.println("Name:" + user.getName());
        System.out.println("Email:" + user.getEmail());
        System.out.println("Date of Birth:" + user.getBirthday());
        return "success";
    }

}

7. 啓動程序進行測試

我們在postman中,輸入地址: http://localhost:8080/user, 用post請求,傳遞json參數:

{
    "name":"一一哥",
    "password":"123",
    "email":"sss@33",
    "birthday": "2020-03-20"
}

此時可以看到返回的驗證數據:

當傳入的參數中,email不合格時,有如下返回值。

至此,我們第2篇數據綁定和自定義的屬性編輯器,以及自定義參數校驗器完成了!

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