菜鳥的Hibernate Validator實戰教程

說明

更新時間:2020/5/28 12:11,更新了list分組校驗以及常用註解
更新時間:2020/5/27 23:23,更新了Hibernate Validator基本使用

本文主要記錄本人在學習Hibernate Validator時的一些知識點,以便日後查看,本文會持續更新,不斷地擴充

本文僅爲記錄學習軌跡,如有侵權,聯繫刪除

一、Hibernate Validator簡介

Hibernate Validator的出現是爲了解決平時的項目開發中的數據正確性的校驗問題,在平時開發中,爲了確保數據的正確性,經常需要做數據的校驗,傳統的數據校驗會顯得代碼冗長,而且不美觀,而且如果項目較大的話,會出現很多重複代碼。爲了解決這個問題,Java中提供了Bean Validation的標準,該標準規定了校驗的具體內容,通過簡單的註解就能完成必要的校驗邏輯了,相對來說就方便了很多,而該規範其實只是規範,並沒有具體的實現,Hibernate提供了具體的實現,也即Hibernate Validator,這個也是目前使用得比較多的驗證器了。

二、快速入門

入門案例
實體類

package com.zsc.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Father {
    @Null(message = "主鍵不可以有值")
    private Integer id;

    @NotBlank(message = "名字不能爲空")
    private String name;

    @NotNull(message = "年齡不能爲空")
    private Integer age;
}

Controller

package com.zsc.controller;
import com.zsc.po.Father;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;

@Controller
public class FatherController {

    @RequestMapping("/father")
    public void father(@RequestBody @Valid Father father, BindingResult result){

        //處理業務邏輯
        if(result.hasErrors()){
            for (ObjectError error : result.getAllErrors()) {
                System.out.println(error.getDefaultMessage());
            }
        }
    }
}

用Postman發起請求
在這裏插入圖片描述
控制檯輸出
在這裏插入圖片描述
可以看到後臺確實有進行驗證,同時也捕捉到了相應的異常,所以控制檯會報錯,然而將這些異常直接返回給前端是不行的,而且這裏控制檯還報錯了就更別說了,所以,下面會對這些數據驗證後產生的異常進行處理。

三、全局異常處理

在進行數據驗證後,產生的異常需要經過處理後才能返回給前端
首先需要一個類(ResultVo),記錄後端處理後的結果返回

package com.zsc.vo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.zsc.enums.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)//不爲空的項纔會加入序列化,表現爲返回的信息中只返回不爲null參數
public class ResultVo {
    /**
     * 後端是否處理成功
     */
    private boolean success;
    /**
     * 返回狀態碼
     */
    private String code;
    /**
     * 返回的處理後的信息
     */
    private String msg;
    /**
     * 給前端的返回值
     */
    private Object data;

    /**
     * 成功的返回
     * @return
     */
    public static ResultVo success(){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(true);
        return resultVo;
    }

    /**
     * 成功的返回
     * @param data
     * @return
     */
    public static ResultVo success(Object data){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(true);
        resultVo.setData(data);
        return resultVo;
    }

    /**
     * 失敗的返回
     * @param errorCode
     * @return
     */
    public static ResultVo fail(ErrorCode errorCode){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(false);
        resultVo.setCode(errorCode.getCode());
        resultVo.setMsg(errorCode.getMsg());
        return resultVo;
    }

    /**
     * 失敗的返回
     * @param errorCode
     * @param data
     * @return
     */
    public static ResultVo fail(ErrorCode errorCode,Object data){
        ResultVo resultVo = new ResultVo();
        resultVo.setSuccess(false);
        resultVo.setCode(errorCode.getCode());
        resultVo.setMsg(errorCode.getMsg());
        resultVo.setData(data);
        return resultVo;
    }

}

後端處理後,將結果通過ResultVo 類返回給前端,返回的時候需要設置錯誤狀態碼,錯誤信息等,爲了方便查看狀態碼和狀態碼對應的錯誤信息,這裏需要建一個枚舉類(ErrorCode)存放這些狀態碼和狀態碼對應的錯誤信息

package com.zsc.enums;


public enum  ErrorCode {
    //這裏簡單的將參數狀態碼‘1000’錯誤信息設置爲‘參數不正確’
    PARAM_ERROR("1000","參數不正確");
	//這裏還可以設置其他狀態碼和對應的錯誤信息
	
    private String code;
    private String msg;

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    ErrorCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

現在需要創建一個類(CtrlAdvice )用來捕捉上面數據驗證後的處理

package com.zsc.config;

import com.zsc.enums.ErrorCode;
import com.zsc.vo.ResultVo;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
import java.util.stream.Collectors;

@ControllerAdvice(basePackages = "com.zsc.controller")//配置要捕捉的異常的包
@ResponseBody
public class CtrlAdvice {
    //捕捉到異常後跳轉到該方法
    @ExceptionHandler
    public ResultVo exceptionHandler(MethodArgumentNotValidException e){
        /**
         * MethodArgumentNotValidException:捕捉前端傳上來的參數異常
         * id - 主鍵不可以有值
         * name - 名字不能爲空
         * birthday - 出生日期不能爲空
         * age - 年齡不能爲空
         * email - 郵件格式不正確
         */
         
        /**
         * 將異常的id(FieldError::getField)和值(getDefaultMessage)封裝成一個map,返回給ResultVo
         */
        Map<String, String> collect = e.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
        return ResultVo.fail(ErrorCode.PARAM_ERROR,collect);
    }
}

配置好之後就可以進行真正的數據驗證了

四、數據驗證

控制層的校驗

做完全局異常處理後,下面就可以進行真正的數據驗證了,數據驗證除了對基本數據類型的驗證之外,還包括級聯驗證,即在一個類中存在自定義的數據類型,有一對一,一對多的情況,下面給出數據驗證例子。
實體類User

package com.zsc.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Null(message = "主鍵不可以有值")
    private Integer id;

    @NotBlank(message = "名字不能爲空")
    private String name;

    @NotNull(message = "出生日期不能爲空")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    @NotNull(message = "年齡不能爲空")
    private Integer age;

    @NotBlank(message = "郵件不能爲空")
    @Email(message = "郵件格式不正確")
    private String email;

    //驗證自定義實體類:一對一
    @Valid
    private Father father;

    //驗證自定義實體類列表:一對多
    private List<@Valid Son> sons;
}

實體類Father

package com.zsc.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Father {
    @Null(message = "主鍵不可以有值")
    private Integer id;

    @NotBlank(message = "名字不能爲空")
    private String name;

    @NotNull(message = "年齡不能爲空")
    private Integer age;
}

實體類Son

package com.zsc.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Son {
    @Null(message = "主鍵不可以有值")
    private Integer id;

    @NotBlank(message = "名字不能爲空")
    private String name;

    @NotNull(message = "年齡不能爲空")
    private Integer age;
}

控制器UserController

package com.zsc.controller;


import com.zsc.po.User;
import com.zsc.vo.ResultVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@RestController
@Validated//對本類中的方法開啓參數驗證功能
public class UserController {

    @RequestMapping("/user")
    public ResultVo user(@RequestBody @Valid User user){
        //處理業務邏輯
        return ResultVo.success();
    }
    
}

下面進行測試
在這裏插入圖片描述
在這裏插入圖片描述

服務層的校驗

服務層的校驗,校驗產生的異常就不是MethodArgumentNotValidException異常了,而是ConstraintViolationException異常,所以之前配置的異常捕捉就不會捕捉到ConstraintViolationException異常,需要在全局配置類CtrlAdvice 裏面配置捕捉ConstraintViolationException的異常並做相應處理。

CtrlAdvice中新增服務層的異常捕捉

package com.zsc.config;

import com.zsc.enums.ErrorCode;
import com.zsc.vo.ResultVo;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.Map;
import java.util.stream.Collectors;

@ControllerAdvice(basePackages = "com.zsc.controller")//配置要捕捉的異常的包
@ResponseBody
public class CtrlAdvice {
    //對應控制層的數據驗證
    //捕捉到MethodArgumentNotValidException異常後跳轉到該方法
    @ExceptionHandler
    public ResultVo exceptionHandler(MethodArgumentNotValidException e){
        /**
         * MethodArgumentNotValidException:捕捉前端傳上來的參數異常
         * id - 主鍵不可以有值
         * name - 名字不能爲空
         * birthday - 出生日期不能爲空
         * age - 年齡不能爲空
         * email - 郵件格式不正確
         */


        /**
         * 將異常的id(FieldError::getField)和值(getDefaultMessage)封裝成一個map,返回給ResultVo
         */
        Map<String, String> collect = e.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
        return ResultVo.fail(ErrorCode.PARAM_ERROR,collect);
    }


    //對應服務層的校驗
    //捕捉到ConstraintViolationException異常後跳轉到該方法
    @ExceptionHandler
    public ResultVo exceptionHandler(ConstraintViolationException e){
        Map<Path, String> collect = e.getConstraintViolations().stream()
                .collect(Collectors.toMap(ConstraintViolation::getPropertyPath, ConstraintViolation::getMessage));
        return ResultVo.fail(ErrorCode.PARAM_ERROR,collect);
    }

}

配置好服務層的異常捕捉後,設置服務層要校驗的方法
服務層接口:UserService

package com.zsc.service;

import com.zsc.po.User;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

public interface UserService {

    void add(@Valid User user);//服務層的數據校驗

    //數據校驗還可以這樣校驗
    @NotNull User getById(@NotNull Integer id);
}

服務層接口實現類UserServiceImpl

package com.zsc.service.impl;

import com.zsc.po.User;
import com.zsc.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

@Service
@Validated
public class UserServiceImpl implements UserService {

    @Override
    public void add(@Valid User user) {
        //業務邏輯
        System.out.println("數據添加成功");
    }

    @Override
    public @NotNull User getById(@NotNull Integer id) {
        return null;
    }
}

控制層新增userService方法

package com.zsc.controller;


import com.zsc.po.User;
import com.zsc.service.UserService;
import com.zsc.vo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@RestController
@Validated//對本類中的方法開啓參數驗證功能
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/user")
    public ResultVo user(@RequestBody @Valid User user){
        //處理業務邏輯
        return ResultVo.success();
    }

    @RequestMapping("/userService")
    public ResultVo userService(@RequestBody User user){
        //處理業務邏輯
        userService.add(user);
        return ResultVo.success();
    }

}

測試結果
在這裏插入圖片描述

分組校驗

在這裏插入圖片描述
設想一下,User的主鍵id由於在進行數據的插入時,主鍵id一般由數據庫默認自增,所以在前端發起插入數據時不需要傳入id,所以上面圖的id做了@Null驗證,但是如果時數據更新的話,User的id就需要傳給後端,但上面圖的id卻做了@Null驗證,爲了解決這個矛盾,就需要做分組校驗,新修改的User如下圖所示

實體類User

package com.zsc.po;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    //分組校驗:Update驗證組和Add驗證組
    public interface Update{}
    public interface Add{}

    /**
     * 如果指定了驗證組,那麼該參數就只屬於指定的驗證組
     *
     * 如果沒有指定校驗組,那麼該參數就只屬於默認組
     */


    @Null(message = "插入數據時主鍵不可以有值",groups = {Add.class})
    @NotNull(message ="更新時需要傳主鍵id過來",groups = {Update.class})
    private Integer id;

    @NotBlank(message = "名字不能爲空")
    private String name;

    @NotNull(message = "出生日期不能爲空")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    @NotNull(message = "年齡不能爲空")
    private Integer age;

    @NotBlank(message = "郵件不能爲空")
    @Email(message = "郵件格式不正確")
    private String email;

    //驗證自定義實體類:一對一
    @Valid
    private Father father;

    //驗證自定義實體類列表:一對多
    private List<@Valid Son> sons;
}

控制層

package com.zsc.controller;


import com.zsc.po.User;
import com.zsc.service.UserService;
import com.zsc.vo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.groups.Default;

@RestController
@Validated//對本類中的方法開啓參數驗證功能
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/addUser")
    public ResultVo add(@RequestBody @Validated({User.Add.class, Default.class}) User user) {
        //增加用戶時,數據校驗就採用Add驗證組和默認驗證組
        //處理業務邏輯
        return ResultVo.success();
    }

    @RequestMapping("/updateUser")
    public ResultVo update(@RequestBody @Validated({User.Update.class, Default.class}) User user) {
        //更新用戶時,數據校驗就採用Update驗證組和默認驗證組
        //處理業務邏輯
        return ResultVo.success();
    }


    @RequestMapping("/userService")
    public ResultVo userService(@RequestBody User user) {
        //處理業務邏輯
        userService.add(user);
        return ResultVo.success();
    }

}

測試插入數據(此時主鍵id校驗不能有值)
在這裏插入圖片描述
測試更新數據(此時主鍵id需要傳值過來)
在這裏插入圖片描述

自定義註解校驗

一般Validator自帶的註解校驗足夠應對正常的數據校驗,但如果沒有我們想要的數校驗方式,可以自己定義一個註解進行自定義註解校驗,假設現在要校驗一個字段,如果該字段是Integer則要求該參數必須是偶數,如果是List則要求該參數的列表的個數(list.size()必須是偶數,可以自定義該註解。

在新建的包validator下的新建註解Even

package com.zsc.validator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
 * 自定義註解校驗
 * 檢驗Integer字段是否爲偶數
 */
@Documented//生成文檔
@Target({ElementType.FIELD})//表示該註解作用於字段
@Retention(RetentionPolicy.RUNTIME)//表示在運行是依然生效
@Constraint(
        validatedBy = {EvenForInteger.class,EvenForList.class}//添加實現類
)
public @interface Even {

    String message() default "必須是偶數";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

註解對應的實現類EvenForInteger

package com.zsc.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class EvenForInteger implements ConstraintValidator<Even,Integer> {//表示作用於註解Even,要驗證的類型爲Integer
    @Override
    public void initialize(Even constraintAnnotation) {

    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        //編寫驗證的邏輯
        if(value == null){//如果null直接驗證成功,null交給NotNull註解去驗證
            return true;
        }
        return value%2==0;
    }
}

註解對應的實現類EvenForList

package com.zsc.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;

public class EvenForList implements ConstraintValidator<Even, List> {//表示作用於註解Even,要驗證的類型爲List
    @Override
    public void initialize(Even constraintAnnotation) {

    }

    @Override
    public boolean isValid(List value, ConstraintValidatorContext context) {
        //編寫驗證的邏輯
        if(value == null){//如果null直接驗證成功,null交給NotNull註解去驗證
            return true;
        }
        return value.size() %2==0;//表示要驗證的list的列表個數爲偶數
    }
}

做完就可以開始測試,這裏在Father類上增加了兩個字段用於測試註解Even
在這裏插入圖片描述
在這裏插入圖片描述

list中的分組校驗

假設有一種場景如下
在這裏插入圖片描述
在這裏插入圖片描述
爲此,需要定義一個註解用來校驗上面的場景

自定義註解ValidList

package com.zsc.validation;

import com.zsc.validation.validator.ValidListValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.groups.Default;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;


/**
 * 支持 list 中的分組校驗
 */
@Target({FIELD,PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ValidListValidator.class})
public @interface ValidList {
    /**
     * 要驗證的分組
     */
    Class<?>[] groupings() default {Default.class};

    boolean quickFail() default false;//快速失敗模式,一旦有校驗失敗的情況就不會再往下校驗


    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

對應的實現類ValidListValidator

package com.zsc.validation.validator;

import com.zsc.config.ListValidException;
import com.zsc.utils.ValidatorUtils;
import com.zsc.validation.ValidList;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class ValidListValidator implements ConstraintValidator<ValidList, List> {

    Class<?>[] groupings;
    boolean quickFail;

    @Override
    public void initialize(ValidList validList) {
        groupings = validList.groupings();
        quickFail = validList.quickFail();
    }

    @Override
    public boolean isValid(List list, ConstraintValidatorContext context) {
        Map<Integer, Set<ConstraintViolation<Object>>> errors = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            Object object = list.get(i);
            Set<ConstraintViolation<Object>> error = ValidatorUtils.validator.validate(object, groupings);
            if (error.size()>0) {
                errors.put(i, error);
                if (quickFail){
                    throw new ListValidException(errors);
                }
            }
        }

        if (errors.size()>0){
            throw new ListValidException(errors);
        }
        return true;
    }
}

因爲需要用到底層的validator,所以需要寫一個工具類ValidatorUtils將validator注入進來

package com.zsc.utils;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.validation.Validator;


@Component
public class ValidatorUtils {

    public static Validator validator;

    @Autowired
    public void setValidator(Validator validator) {
        ValidatorUtils.validator = validator;
    }
}

全局異常處理,需要在CtrlAdvice 新增異常捕獲

package com.zsc.config;

import com.zsc.enums.ErrorCode;
import com.zsc.vo.ResultVo;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import javax.validation.ValidationException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@ControllerAdvice(basePackages = "com.zsc.controller")//配置要捕捉的異常的包
@ResponseBody
public class CtrlAdvice {
    //對應控制層的數據驗證
    //捕捉到MethodArgumentNotValidException異常後跳轉到該方法
    @ExceptionHandler
    public ResultVo exceptionHandler(MethodArgumentNotValidException e){
        /**
         * MethodArgumentNotValidException:捕捉前端傳上來的參數異常
         * id - 主鍵不可以有值
         * name - 名字不能爲空
         * birthday - 出生日期不能爲空
         * age - 年齡不能爲空
         * email - 郵件格式不正確
         */


        /**
         * 將異常的id(FieldError::getField)和值(getDefaultMessage)封裝成一個map,返回給ResultVo
         */
        Map<String, String> collect = e.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
        return ResultVo.fail(ErrorCode.PARAM_ERROR,collect);
    }


    //對應服務層的校驗
    //捕捉到ConstraintViolationException異常後跳轉到該方法
    @ExceptionHandler
    public ResultVo exceptionHandler(ConstraintViolationException e){
        Map<Path, String> collect = e.getConstraintViolations().stream()
                .collect(Collectors.toMap(ConstraintViolation::getPropertyPath, ConstraintViolation::getMessage));
        return ResultVo.fail(ErrorCode.PARAM_ERROR,collect);
    }

    @ExceptionHandler
    public ResultVo exceptionHandler(ValidationException e){
        Map<Integer, Map<Path, String>> map = new HashMap<>();

        ((ListValidException)e.getCause()).getErrors().forEach((integer, constraintViolations) -> {
            map.put(integer, constraintViolations.stream()
                    .collect(Collectors.toMap(ConstraintViolation::getPropertyPath, ConstraintViolation::getMessage)));
        });
        return ResultVo.fail(ErrorCode.PARAM_ERROR,map);
    }

    @ExceptionHandler
    public ResultVo exceptionHandler(Exception e){
        return ResultVo.fail(ErrorCode.SYSTEM_ERROR);
    }

}

同時還需要一個異常類ListValidException

package com.zsc.config;

import javax.validation.ConstraintViolation;
import java.util.Map;
import java.util.Set;

public class ListValidException extends RuntimeException {
    private Map<Integer, Set<ConstraintViolation<Object>>> errors;

    public ListValidException(Map<Integer, Set<ConstraintViolation<Object>>> errors) {
        this.errors = errors;
    }

    public Map<Integer, Set<ConstraintViolation<Object>>> getErrors() {
        return errors;
    }

    public void setErrors(Map<Integer, Set<ConstraintViolation<Object>>> errors) {
        this.errors = errors;
    }
}

完成後開始進行測試,主要測試兩種模式,快速結束模式和非快速結束模式
在這裏插入圖片描述
在這裏插入圖片描述

五、常用註解

給出Hibernate Validator常用註解,下面會詳細講到這些註解

@AssertTrue用於boolean字段,該字段只能爲true  
@AssertFalse該字段的值只能爲false
@CreditCardNumber對信用卡號進行一個大致的驗證
@DecimalMax只能小於或等於該值,字段或屬性. 支持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.
@DecimalMin只能大於或等於該值,字段或屬性. 支持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.
@Digits(integer=,fraction=)檢查是否是一種數字的整數、分數,小數位數的數字,支持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.
@Email檢查是否是一個有效的email地址,需要是String類型的.
@Future檢查該字段的日期是否是屬於將來的日期,支持類型是java.util.Date 和java.util.Calendar
@Length(min=,max=)檢查所屬的字段的長度是否在min和max之間,只能用於字符串
@Max該字段的值只能小於或等於該值,持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.
@Min該字段的值只能大於或等於該值,持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.
@NotNull不能爲null,支持所有類型
@NotBlank不能爲空,檢查時會將空格忽略,一般用於String
@NotEmpty不能爲空,這裏的空是指空字符串,支持的類型包括String, Collection, Map 和數組.
@Null檢查該字段爲空
@Past檢查該字段的日期是在過去
@Pattern(regex=,flag=)被註釋的元素必須符合指定的正則表達式,必須是String類型
@Range(min=,max=,message=)被註釋的元素必須在合適的範圍內
@Size(min=, max=)檢查該字段的size是否在min和max之間,可以是字符串、數組、集合、Map等
@URL(protocol=,host,port)檢查是否是一個有效的URL,如果提供了protocol,host等,則該URL還需滿足提供的條件
@Valid該註解主要用於字段爲一個包含其他對象的集合或map或數組的字段,或該字段直接爲一個其他對象的引用,這樣在檢查當前對象的同時也會檢查該字段所引用的對象
@Range(min=,max=) min <= 數字 <= max,段或屬性. 支持類型包括BigDecimal,BigInteger, String,byte, short, int, long和其各自對應的包裝器類型.

舉例
在這裏插入圖片描述

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