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参数校验内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    本文会介绍从一个最基本的java工程,到Web工程,到集成Spring.SpringMVC.SpringDataJPA+Hibernate. 平时我们可能是通过一个模板搭建一个工程,或者是直接导入一个项目,而本文选择从最基本的java工程开始,目的是为了展示更多原理. 当然,我们还是从一个最基本的Maven工程开始,其实普通的非Maven工程,搭建过程几乎是一模一样的,只是Jar包需要我们手动的添加到工程中,而Maven工程就只是修改配置文件即可. 下面就正式开始. 1.基于Maven(如果不使

  • SpringBoot中通过实现WebMvcConfigurer参数校验的方法示例

    在Spring5.0和SpringBoot2.0中废弃了WebMvcConfigurerAdapter类. 现有两种解决方案 1 直接实现WebMvcConfigurer (官方推荐) 2 直接继承WebMvcConfigurationSupport 本篇文章讨论下使用第一种方式完成参数校验. 首先附上代码. @Slf4j @Controller @RequestMapping("/goods") public class GoodsController { @Autowired Mi

  • Java框架篇:Spring+SpringMVC+hibernate整合开发

    前言: 最近没什么事做,搭个框架写成博客记录下来,拉通一下之前所学知识. 话不多说,我们直接步入正题. 准备工作: 1/安装并配置java运行环境 2/数据库的安装配置(Mysql) 3/安装并配置服务器(Tomcat) 4/Maven 5/ IntelliJIDEA的安装配置(本人使用的主要软件是IntelliJIDEA,没用eclipse什么的) 6/ 使用IntelliJIDEA创建一个web app项目. 貌似就这些了吧 导包 不同于以往的导包,由于我们创建的是maven的webapp项

  • Spring+SpringMVC+Hibernate项目环境搭建的步骤(图文)

    工具篇:Intellij Idea+maven+Spring+SpringMVC Spring+SpringMVC环境搭建 一.SpringMVC环境搭建 1.创建新项目 (1).第一步是创建一个由Maven原型的项目,根据图片上的步骤一次选择Maven-–>create from archetype-->maven-archtype-webapp (2).第二步是填写GroupId 和ArtifactId (3).在位置1处选择我们maven安装的目录,在位置2处选择settings.xml

  • Spring MVC参数校验详解(关于`@RequestBody`返回`400`)

    前言 工作中发现一个定律,如果总是习惯别人帮忙做事的结果是自己不会做事了.一直以来,spring帮我解决了程序运行中的各种问题,我只要关心我的业务逻辑,设计好我的业务代码,返回正确的结果即可.直到遇到了400. spring返回400的时候通常没有任何错误提示,当然也通常是参数不匹配.这在参数少的情况下还可以一眼看穿,但当参数很大是,排除参数也很麻烦,更何况,既然错误了,为什么指出来原因呢.好吧,springmvc把这个权力交给了用户自己.话不多说了,来一起看看详细的介绍吧. springmvc

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

    在我们用Controller接收参数后,往往需要对参数进行校验.如果我们手写校验的话,就会有一堆的判空代码,看起来很不优雅,写起来也费时费力.下面来看下通过hibernate-validator来进行优雅的参数校验. 首先需要引入依赖: <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <v

  • SpringBoot整合Hibernate Validator实现参数验证功能

    在前后端分离的开发模式中,后端对前端传入的参数的校验成了必不可少的一个环节.但是在多参数的情况下,在controller层加上参数验证,会显得特别臃肿,并且会有许多的重复代码.这里可以引用Hibernate Validator来解决这个问题,直接在实体类进行参数校验,验证失败直接返回错误信息给前端,减少controller层的代码量. 一.xml引入Hibernate Validator <!-- 验证器 --> <dependency> <groupId>org.hi

  • golang validator库参数校验实用技巧干货

    目录 validator库参数校验若干实用技巧 基本示例 翻译校验错误提示信息 自定义错误提示信息的字段名 自定义结构体校验方法 自定义字段校验方法 自定义翻译方法 validator库参数校验若干实用技巧 在web开发中一个不可避免的环节就是对请求参数进行校验,通常我们会在代码中定义与请求参数相对应的模型(结构体),借助模型绑定快捷地解析请求中的参数,例如 gin 框架中的Bind和ShouldBind系列方法.本文就以 gin 框架的请求参数校验为例,介绍一些validator库的实用技巧.

  • SprinBoot如何集成参数校验Validator及参数校验的高阶技巧

    目录 为什么需要参数校验 SpringBoot中集成参数校验 第一步,引入依赖 第二步,定义要参数校验的实体类 第三步,定义校验类进行测试 第四步,体验效果 参数异常加入全局异常处理器 体验效果 自定义参数校验 第一步,创建自定义注解 第二步,自定义校验逻辑 第三步,在字段上增加注解 第四步,体验效果 分组校验 第一步:定义分组接口 第二步,在模型中给参数分配分组 第三步,给需要参数校验的方法指定分组 第四步,体验效果 小结 前几天写了一篇<SpringBoot如何统一后端返回格式?老鸟们都是这

  • springboot使用hibernate validation对参数校验的实现方法

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtils.isEmpty(userName)){ throw new RuntimeException("用户名不能为空"); } 下面将介绍hibernate validation的基本使用方法. 一.引入依赖 这里在springboot 2.4.1中进行实验,引入以下依赖: <pare

  • .NET Core 2.1中HttpClientFactory的最佳实践记录

    前言 ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpClient实例从其应用程序发出外部Web请求时可能遇到的一些常见问题. 介绍 在.NETCore平台的2.1新增了HttpClientFactory,虽然HttpClient这个类实现了disposable,但使用它的时候用声明using包装块的方式通常不是最好的选择.处理HttpClient,底层socket套接字不会立即释放.该HttpClient类是专为多个请求

  • React文件名和目录规范最佳实践记录(总结篇)

    目录 文件类型 处理index文件 规范 类型文件夹 特性文件夹 大驼峰命名 烧烤串命名 React在使用时非常灵活,如果没有一个规范约束项目,在开发过程中会非常混乱,本文将介绍几个优秀的规范. 文件类型 介绍文件名和目录前,需要先简述一下几种通用的类型,用来区分文件的功能. component 组件文件 page 如果有路由(React Router.NextJS等),则有页面文件 util 需要复用的工具函数 helper 一段特定逻辑,不是通用工具,可复用也可仅作为代码拆分片段 hook

  • react+ts实现简单jira项目的最佳实践记录

    练手的一套项目 react+ts 虽然内容较少,但是干货挺多,尤其是对hooks的封装,ts的泛型的理解,使用更上一层楼 项目代码:https://gitee.com/fine509/react_jiar 效果图 这是三个主要页面,还有一些小细节 等等 一些值得注意的地方(只是讲大概的功能,没有具体的详解怎么用) 使用错误边界处理,getDerivedStateFromError来处理当某个页面某处地方有报错的时候显示报错组件而不是挂掉. useSearchParams的使用 这个api可以获取

  • iOS中创建Model的最佳实践记录

    前言 作为一个优秀的程序员,或者想成为优秀的程序员,最基本的你得有MVC编程思想,那么你就要对JSON获取的数据建Model,将service和controller层都分离,从而做到低耦合.现在有很多利用runtime能快速的将json数据转为一个Model.但是我在做项目的时候,发现创建Model(特别是属性特多的)写属性代码很浪费时间,降低了编程效率.后来我自己就写了个好玩的能省去时间创建Model的一个方法,下面话不多说了,来一起看看详细的介绍吧 Immutable Model 我们以Us

  • golan参数校验Validator

    目录 1.实践 1.1校验标签 1.2字符串约束 1.3自定义校验器 前言: 开发接口的时候需要多前端提交的参数进行参数校验,如果提交的参数只有一个两个,这样我们可以简单写个if判断,但是如果提交的参数比较多,通过if判断就比较繁琐了,在Go中有一个validator包可以通过反射结构体struct的tag进行参数校验 1.实践 go get github.com/go-playground/validator/v10 定义结体: type UserInfo struct { ID int `v

随机推荐