菜鸟的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和其各自对应的包装器类型.

举例
在这里插入图片描述

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