SpringMVC使用hibernate-validator进行参数校验最佳实践记录

 更新时间:2021年05月12日 10:32:57   作者:kusedexingfu  
这篇文章主要介绍了SpringMVC使用hibernate-validator进行参数校验最佳实践,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

在我们用Controller接收参数后,往往需要对参数进行校验。如果我们手写校验的话,就会有一堆的判空代码,看起来很不优雅,写起来也费时费力。下面来看下通过hibernate-validator来进行优雅的参数校验。

首先需要引入依赖:

<dependency>
	<groupId>org.hibernate.validator</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>6.2.0.Final</version>
</dependency>

hibernate-validator注解

hibernate-validator提供了很多注解来让我们进行参数校验:

常用的校验注解如下表所示:

注解 说明
@Null 被注释的元素必须为null
@AssertTrue 被注释的元素必须为true
@AssertFalse 被注释的元素必须为false
@DecimalMin(value=,message=) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value=,message=) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Email 被注释的元素必须是电子邮箱地址

主要区分下@NotNull、@NotEmpty、@NotBlank 3个注解的区别:
(1)@NotNull:任何对象的value不能为null。
(2)@NotEmpty:集合对象的元素不为0,即集合不为空,也可以用于字符串不为null。
(3)@NotBlank:只能用于字符串不为null,并且字符串trim()以后length要大于0。

需要注意如下几点:
(1)除了@Empty要求字符串不能全是空格,其他的字符串校验都是允许空格的。
(2)message是可以引用常量的,但是如@Size里max不允许引用对象常量,基本类型常量是可以的。message是错误提示信息,是可以返回给前台的。
(3)大部分规则校验都是允许参数为null,即当不存在这个值时,就不进行校验了。


不太常用的校验注解如下表所示:

注解 说明
@Null 被注释的元素必须为null
@AssertTrue 被注释的元素必须为true
@AssertFalse 被注释的元素必须为false
@DecimalMin(value=,message=) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value=,message=) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Email 被注释的元素必须是电子邮箱地址

代码实战

1.、使用BindingResult获取检验结果

我们可以使用BindingResult获取检验结果,构造友好的返回信息

Controller中的代码如下:

@Api(tags = "校验框架")
@RestController
@RequestMapping("/validate")
public class ValidatedController {
 
 
    @ApiOperation(value = "bindValidate")
    @PostMapping("bindValidate")
    public ValidatedVO bindValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO, BindingResult result) {
        if (result.hasErrors()) {
            StringBuilder message = new StringBuilder("参数校验失败:");
            List<ObjectError> errors = result.getAllErrors();
            for (ObjectError error : errors) {
                message.append(error.getDefaultMessage()).append(".");
            }
            throw HttpError.error(111, message.toString());
        }
        return validatedVO;
    }
 
 
}

我们用以下实体类来作为Controller的参数接收实体

import lombok.Data;
 
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
 
@Data
public class ValidatedVO {
 
    //更新、删除时不能为空
    @NotNull(message = "id不能为空", groups = {ValidatedGroup.UPDATE.class, ValidatedGroup.DELET.class})
    private Long id;
 
    //新增、更新时不能为空
    @NotBlank(message = "name不能为空", groups = {ValidatedGroup.CREATE.class ,ValidatedGroup.UPDATE.class})
    private String name;
 
    //查询时不能为空
    @NotBlank(message = "queryParam不能为空", groups = {ValidatedGroup.QUERY.class})
    private String queryParam;
 
}

分组的类:

public class ValidatedGroup {
 
    public interface CREATE{}
 
    public interface DELET{}
 
    public interface UPDATE{}
 
    public interface QUERY{}
}

需要注意的是,@Validated支持分组校验,即校验注解中的groups属性。这个为我们的校验也提供了便利。我们可以在Controller需要校验的参数前用@Validated的value属性来表示需要校验的分组,那么就会只会校验实体对象中拥有相同的分组的属性。这样我们就可以只用一个实体满足不同的场景了。

启动项目后,我们在swagger上请求,传递空的json字符串【{}】,返回结果:

{
  "code": 111,
  "message": "参数校验失败:id不能为空."
}

 然而每次都需要在请求进来时用BindingResult做处理,很不优雅。

2.通过@RestControllerAdvice统一处理参数校验信息

如果我们不用BindingResult获取校验结果,即不做处理,框架就会抛出异常,响应400码,返回一些不友好的错误信息。即用如下代码:

@ApiOperation(value = "bindValidate")
    @PostMapping("bindValidate")
    public ValidatedVO bindValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO/*, BindingResult result*/) {
        /*if (result.hasErrors()) {
            StringBuilder message = new StringBuilder("参数校验失败:");
            List<ObjectError> errors = result.getAllErrors();
            for (ObjectError error : errors) {
                message.append(error.getDefaultMessage()).append(".");
            }
            throw HttpError.error(111, message.toString());
        }*/
        return validatedVO;
    }

那么我们就可以使用@RestControllerAdvice来对异常进行处理,进行友好信息的提示

如果对@RestControllerAdvice和@ControllerAdvice不了解的,可以去查询学习,这里不进行讲述

@RestControllerAdvice
public class GlobalExceptionHandler {    
 
    @ExceptionHandler(Exception.class)
    public CommonErrorVO handle(Exception e){
        if (e instanceof HttpError) {
            HttpError error = (HttpError)e;
            return CommonErrorVO.builder().code(error.getCode()).message(error.getMessage()).build();
        } else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e;
            StringBuilder message = new StringBuilder("");
            validException.getBindingResult().getAllErrors().forEach(err -> {
                message.append(err.getDefaultMessage()).append(".");
            });
            return CommonErrorVO.builder().code(888).message(message.toString()).build();
        } else {
            return CommonErrorVO.builder().code(999).message(e.getMessage()).build();
        }
    }    
}

MethodArgumentNotValidException异常即为hibernate-validator校验不通过抛出的异常信息,我们从其中获取到校验失败的信息来进行组装。

如上,我们通过@Validated配合@RestControllerAdvice完成了优雅的参数校验。

为了体现分组校验的便利性,我做了如下的测试,如果每个请求参数都是空的json字符串【{}】的话,那么返回的信息如下。

@Api(tags = "校验框架")
@RestController
@RequestMapping("/validate")
public class ValidatedController {
 
    /**
     * @Validated注解表示开启Spring的校验机制,支持分组校验,声明在入参上。
     * @param validatedVO
     * @return
     */
    @ApiOperation(value = "分组校验:QUERY参数校验")//返回 【queryParam不能为空】
    @PostMapping("queryValidate")
    public ValidatedVO queryValidate(@RequestBody @Validated(value= {ValidatedGroup.QUERY.class}) ValidatedVO validatedVO) {
        return validatedVO;
    }
 
    @ApiOperation(value = "分组校验:CREATE参数校验")// 返回 【name不能为空】
    @PostMapping("createValidate")
    public ValidatedVO createValidate(@RequestBody @Validated(value= {ValidatedGroup.CREATE.class}) ValidatedVO validatedVO) {
        return validatedVO;
    }
 
    @ApiOperation(value = "分组校验:UPDATE参数校验") // 返回【id不能为空.name不能为空.】
    @PostMapping("updateValidate")
    public ValidatedVO updateValidate(@RequestBody @Validated(value= {ValidatedGroup.UPDATE.class}) ValidatedVO validatedVO) {
        return validatedVO;
    }
 
    @ApiOperation(value = "分组校验:DELETE参数校验") //返回 【id不能为空】
    @PostMapping("deleteValidate")
    public ValidatedVO deleteValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO) {
        return validatedVO;
    }
}

到此这篇关于SpringMVC使用hibernate-validator进行参数校验最佳实践记录的文章就介绍到这了,更多相关SpringMVC参数校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot快速通关自动配置应用

    SpringBoot快速通关自动配置应用

    在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制,只有把这些都搞清楚了,我们在之后使用才会更加得心应手
    2022-07-07
  • java中CompletableFuture异步执行方法

    java中CompletableFuture异步执行方法

    本文主要介绍了java中CompletableFuture异步执行方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • LinkedList学习示例模拟堆栈与队列数据结构

    LinkedList学习示例模拟堆栈与队列数据结构

    这篇文章主要介绍了LinkedList学习示例,模拟一个堆栈与队列数据结构,大家参考使用吧
    2014-01-01
  • 如何用nacos搭建微服务注册配置中心

    如何用nacos搭建微服务注册配置中心

    这篇文章主要介绍了如何用nacos搭建微服务注册配置中心问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • 深入浅析Java中的volatile

    深入浅析Java中的volatile

    volatile是Java提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色.这篇文章主要介绍了深入浅析Java中的volatile,需要的朋友可以参考下
    2017-03-03
  • Spring Boot 实现程序的优雅退出(详细步骤)

    Spring Boot 实现程序的优雅退出(详细步骤)

    Spring Boot 为我们提供了优雅退出的功能,使应用程序能够在关闭时正常处理完所有当前请求,避免请求被中断导致数据丢失或不一致等问题,本文将全面介绍如何在 Spring Boot 应用程序中实现优雅退出,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • Spring Security实现登录认证实战教程

    Spring Security实现登录认证实战教程

    这篇文章主要介绍了Spring Security实现登录认证实战教程,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2024-06-06
  • Java设计模式中的建造者模式详解

    Java设计模式中的建造者模式详解

    这篇文章主要介绍了Java设计模式中的建造者模式详解,建造者模式使我们日常工作中比较常见的一种设计模式,和工厂模式一样属于创建型设计模式,用于解耦对象创建和对象使用的逻辑,需要的朋友可以参考下
    2023-12-12
  • Java的MyBatis框架中Mapper映射配置的使用及原理解析

    Java的MyBatis框架中Mapper映射配置的使用及原理解析

    Mapper用于映射SQL语句,可以说是MyBatis操作数据库的核心特性之一,这里我们来讨论Java的MyBatis框架中Mapper映射配置的使用及原理解析,包括对mapper的xml配置文件的读取流程解读.
    2016-06-06
  • eclipse/intellij idea 查看java源码和注释方法

    eclipse/intellij idea 查看java源码和注释方法

    下面小编就为大家带来一篇eclipse/intellij idea 查看java源码和注释方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05

最新评论