Hibernate Validator:一款优雅的验证框架

本文介绍HibernateValidator框架如何简化项目中数据校验过程,包括SpringBoot集成、全局异常捕获及分组验证,提升代码整洁度和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate Validator:一款优雅的验证框架

1、Hibernate Validator的简单介绍

  平常的项目当中,无论是从controller接受传递来的数据,还是内部方法接口的形参赋值,都离不开数据的校验。这些校验有着实际的业务需求,例如你定义了一个价格,它肯定是非负数,但是前端传来一个负数,是不是需要校验避免把错误的数据写进数据库呢?但是在平常的项目开发中,这些校验的编写,存在于我们的业务逻辑当中,使我们的代码变得臃肿复杂。
  有没有一款框架能够简便校验的编写呢?Hibernate Validator就是为了解决这个问题的。只要加上注解,我们就可以一行轻松解决校验问题,十分方便。

2、SpringBoot集成Hibernate Validator
2.1、引入依赖
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
2.2、使用Validator和手写验证对比

  现在我们写一个简单的小demo,来对比一些手写校验逻辑和使用Hibernate Validator框架,到底简便多少吧!
  假设有个添加员工信息需求,前端传来数据,映射到后台的Javabean类是Employee类,也就是员工类。员工类中有四个属性,id就是员工编号,parent_id就是员工对应的部门编号,name对应员工的名字,createtime表示员工的入职时间。
  Employee类有以下要求:
  1、前端传入的id必须为空,因为id在数据库里是自增字段,不支持手动赋值。
  2、parent_id不能为空,每个员工必须有一个部门编号。
  3、name也不能为空。
  4、createtime时间必须小于当前查询的系统时间。

  Employee类的具体属性

public class Employee {

    private Integer id;
    
   private Integer parent_id;

    private String name;

    private LocalDateTime createtime;
}

  那现在我们用普通的方式,对controller获得数据进行校验

@RestController
public class TestController {

    @PostMapping("/add")
    public Object add(@RequestBody Employee employee){
        String msg="";
        boolean flag=false;
        if(employee.getId()!=null){
            msg += "id必须为空";flag=true;
        }
        if(employee.getParent_id()==null){
            msg += "parent_id不能为空";flag=true;
        }
        if(employee.getName()==null){
            msg += "name不能为空";flag=true;
        }
        if(employee.getCreatetime().isAfter(LocalDateTime.now())){
            msg += "createtime必须在当前时间之前";flag=true;
        }
        if(flag==true){
            return msg;
        }
        return "ok";
    }

}

  我们可以看到在正式的业务逻辑之前,只是校验数据代码就很多行了,如果存在多个controller,这些校验代码还要重复写,使得整个项目的代码变得臃肿起来。

  现在我们使用Hibernate Validator来编写校验逻辑。
  1、在Employee类上加上具体的约束注解。

public class Employee {
   @Null
   private Integer id;
    
   @NotNull
   private Integer parent_id;
   
   @NotBlank
   private String name;

   @PastOrPresent
   private LocalDateTime createtime;
}

  2、在controller的类上加上@Validated注解,标注这个类需要校验。在需要校验的参数前面加上@Valid注解,使这个实体类的属性得到校验。

@RestController
@Validated
public class TestController2 {

    @PostMapping("/add")
    public Object add(@RequestBody @Valid Employee employee){
        return "ok";
    }
}

  当前端传来不合规范的数据时,控制台就会报错,并显示对应的错误信息。这样看来,使用validator来进行数据校验,是不是简洁很多呢?

3、Validator的全局异常捕获

  当输入前端输入的数据不规范时,控制台就会报错,那我们怎么把错误的信息,返回把前端页面显示呢?这时候就要用到异常捕获。我们可以定义一个全局异常的捕获类,当出现某种异常时,就捕获它,对数据进行封装,返回到前端。
  GlobalExceptionHandler.java(全局捕获类)

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    public Object expHandler(Exception e){
        if (e instanceof MethodArgumentNotValidException){
            log.error(e.getMessage());
            String msg="";
            List<ObjectError> errors=((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
            for(ObjectError error : errors){
                msg += error.getDefaultMessage();
                msg += ",";
            }
            return msg;
        }
        return null;
    }
}
4、Validator的分组验证

  Hibernate Validator可以用在JavaBean的数据校验上,但是这样可能会产生一个问题:一个Javabean对应的多个controller,不同的controller对于实体类的约束都不一样。例如当前端更新数据的时候,它可能需要A属性为空,但是当前端新增数据的时候,它可能需要A属性不为空。这就涉及分组了。
  1、首先在分组的实体类中定义组别接口进行区分,然后对应分组的注解后面添上组别接口,如果不标注则代表是默认组别。

public class Employee {

    @Positive(message = "id必须为正数",groups = {Employee.add.class})
    private int id;

    @Positive(message = "parent_id必须为正数",groups = {Employee.add.class})
    private int parent_id;

    @NotBlank(message = "name不能为空")
    private String name;

    @NotNull(message = "createtime不能为空")
    @PastOrPresent
    private LocalDateTime createtime;

    @Valid
    private List<Department> departments;

    public interface add{};

    public interface update{};

}

  2、因为@Valid注解是不可以区别组别的,所以我们改用@Validated注解,后面跟上组别区分。

@RestController
@Validated
public class Testcontroller {

    @PostMapping("/add")
    public Object add(@RequestBody  @Validated({Employee.add.class}) Employee employee){
        return "add ok";
    }

    @PostMapping("/update")
    public Object update(@RequestBody @Validated({Default.class}) Employee employee){
        return "update ok";
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值