• Hibernate Validator使用


    Hibernate Validator官方文档

    https://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#validator-usingvalidator-validationgroups

    JSR 303 - Bean Validation - 为实体验证定义了元数据模型和API. 默认的元数据模型是通过 Annotations来描述的,但是也可以使用XML来重载或者扩展. Bean Validation API 并不局限于应 用程序的某一层或者哪种编程模型, 例如,如图所示, Bean Validation 可以被用在任何一层, 或 者是像类似Swing的富客户端程序中.

    Hibernate Validator是JSR 303的一种参考实现。
    Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种)
    似乎可以混用 '_'

    • @Valid属于javax.validation包下,是jdk给提供的

    • @Validated是org.springframework.validation.annotation包下的,是spring提供的

    • @Validated要比@Valid更加强大 支持分组校验

    常用的校验注解 @NotNull、@NotBlank....

    默认是校验所有字段并返回所有错误信息,也可以配置为校验到一个字段错误就返回结果。

    1.添加引用

    <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.0.9.Final</version>
          <scope>compile</scope>
    </dependency>
    

    2.创建实体

    package com.zhujun.model;
    import lombok.Data;
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    
    @Data
    public class Student {
        public interface GymStudent{};//分组定义接口
        //姓名
        @NotBlank(message = "姓名未知")
        private String name;
        //年龄
        @NotNull(message = "年龄未知")
        private Integer age;
    
        //分组校验
        @NotBlank(message = "体育生编号不能为空!",groups = GymStudent.class)
        private String gymStudentNo;
    }
    
    

    GymStudent组只会校验gymStudentNo,如果需要校验其他字段,可以使GymStudent extends Default
    或者在使用 @Validated({Student.GymStudent.class, Default.class} 声明默认组

    Clazz类 持有List对象 用于嵌套检验

    package com.zhujun.model;
    import lombok.Data;
    
    import javax.validation.Valid;
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import java.util.List;
    
    @Data
    public class Clazz {
        @NotBlank(message = "班级编号不能为空")
        private  String clazzNo;
    
        @NotNull(message = "班级不能没有学生")
        @Valid  //嵌套校验 需要使用该注解
        private List<Student> studentList;
    }
    

    3.检验

    package com.zhujun.controller;
    import com.zhujun.model.Clazz;
    import com.zhujun.model.Student;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.validation.Valid;
    import javax.validation.groups.Default;
    
    @Slf4j
    @RestController
    @RequestMapping("/school")
    public class SchoolController {
        @RequestMapping("/createStudent")
        public String createStudent(@Validated Student student){
            //不指定校验分组class 默认为Default.class
            log.info(student.toString());
            return "success";
        }
        @RequestMapping("/createClazz")
        public String createClazz(@Valid @RequestBody Clazz clazz){
            //嵌套校验 
            log.info(clazz.toString());
            return "success";
        }
        @RequestMapping("/createGymStudent")
        public String createGymStudent( @RequestBody @Validated({Student.GymStudent.class, Default.class}) Student student){
            //分组校验
            log.info(student.toString());
            return "success";
        }
    }
    

    分组校验时可以根据需要 定义组之间校验的顺序

    4.统一异常处理

    package com.zhujun.config;
    
    import com.zhujun.common.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.validation.BindingResult;
    import org.springframework.validation.FieldError;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import java.util.List;
    @Slf4j
    @RestControllerAdvice
    public class BadRequestExceptionHandler {
        /**
         * 校验错误拦截处理
         *
         * @param exception 错误信息集合
         * @return 错误信息
         */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public Result validationBodyException(MethodArgumentNotValidException exception) {
            BindingResult result = exception.getBindingResult();
            if (result.hasErrors()) {
                List<ObjectError> errors = result.getAllErrors();
                for(ObjectError error:errors){
                    FieldError fieldError = (FieldError) error;
                    log.error("Data check failure : object{"+fieldError.getObjectName()+"},field{"+fieldError.getField()+
                            "},errorMessage{"+fieldError.getDefaultMessage()+"}");
                    return Result.error(fieldError.getDefaultMessage());//异常信息中 返回一个错误信息即停止
                }
            }
            return null;
        }
    }
    
    使用@RequestBody参数注解的情况下,抛出的都是MethodArgumentNotValidException异常

    不使用时 抛出的则是BindException

    啊...这还以为是分组校验导致的,统一异常处理失效了^^

    5.手动检验

    有时可能会出现Service之间互相调用,没有SpringMVC中的Bind过程,可以在代码中手动进行校验。

    public static <T> Map<String, StringBuffer> validate(T obj,Class var) {
            Map<String,StringBuffer> errorMap = null;
            Set<ConstraintViolation<T>> set = validator.validate(obj, var==null ? Default.class : var);
            if(!CollectionUtils.isEmpty(set)){
                errorMap = new HashMap<>();
                String property = null;
                for(ConstraintViolation<T> cv : set){
                    //这里循环获取错误信息,可以自定义格式
                    property = cv.getPropertyPath().toString();
                    if(errorMap.get(property) != null){
                        errorMap.get(property).append("," + cv.getMessage());
                    }else{
                        StringBuffer sb = new StringBuffer();
                        sb.append(cv.getMessage());
                        errorMap.put(property, sb);
                        // 有错误就返回,根据需要是否停止循环
                        break;
                    }
                }
            }
            return errorMap;
        }
    

    6.默认返回的Json数据格式

    {
        "timestamp": "2020-05-21T10:56:53.371+0000",
        "status": 400,
        "error": "Bad Request",
        "errors": [
            {
                "codes": [
                    "NotNull.student.age",
                    "NotNull.age",
                    "NotNull.java.lang.Integer",
                    "NotNull"
                ],
                "arguments": [
                    {
                        "codes": [
                            "student.age",
                            "age"
                        ],
                        "arguments": null,
                        "defaultMessage": "age",
                        "code": "age"
                    }
                ],
                "defaultMessage": "年龄未知",
                "objectName": "student",
                "field": "age",
                "rejectedValue": null,
                "bindingFailure": false,
                "code": "NotNull"
            },
            {
                "codes": [
                    "NotBlank.student.name",
                    "NotBlank.name",
                    "NotBlank.java.lang.String",
                    "NotBlank"
                ],
                "arguments": [
                    {
                        "codes": [
                            "student.name",
                            "name"
                        ],
                        "arguments": null,
                        "defaultMessage": "name",
                        "code": "name"
                    }
                ],
                "defaultMessage": "姓名未知",
                "objectName": "student",
                "field": "name",
                "rejectedValue": null,
                "bindingFailure": false,
                "code": "NotBlank"
            }
        ],
        "message": "Validation failed for object='student'. Error count: 2",
        "path": "/school/createStudent"
    }
    
  • 相关阅读:
    Matrix-tree 定理的一些整理
    多项式
    多项式
    vijos 1641 Vs Snowy
    noip 提高组 2010
    军训有感
    我的将军啊
    洛谷 P3302 [SDOI2013]森林
    关于线段树
    关于KMP
  • 原文地址:https://www.cnblogs.com/shinyrou/p/12932738.html
Copyright © 2020-2023  润新知