前言

后台开发中对参数的校验是不可缺少的一个环节,为了解决如何优雅的对参数进行校验?

  • JSR303(Java Specification Requests)应运而生,JSR303 是JavaBean参数校验的标准。
  • Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。
  • Hibernate validator 5 是 Bean Validation 1.1的实现。

常见注解

  • Bean Validation中定义的注解:
注解 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
  • Hibernate validator 在JSR303的基础上对校验注解进行了扩展,扩展注解如下:
注解 详细信息
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内

参数校验的应用

依赖

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

简单的参数校验示例

  • 要想开启参数校验,需要在类上标注@Validated注解
  • 控制器
 @PostMapping(value = "/test")
public ValidOneEvt param(@RequestBody @Validated ValidOneEvt evt){
return evt;
}
  • 实体验证
@Getter
@Builder
public class ValidOneEvt { @NotEmpty(message = "名称不能为空")
private String name; private String sex; }
  • 测试结果

级联校验

  • 级联校验需要在校验的实体上添加@Valid。
  • 控制器
@PostMapping(value = "/test")
public ValidOneEvt param(@RequestBody @Validated ValidOneEvt evt){
return evt;
}
  • 实体验证
@Getter
@Builder
public class ValidOneEvt { @NotEmpty(message = "名称不能为空")
private String name; private String sex; @Valid
private ValidTwoEvt validTwoEvt; }
  • 级联实体
@Getter
@Setter
public class ValidTwoEvt { @Length(min = 2)
private String name; }
  • 请求示例

  • 校验结果

@Validated 与 @Valid

两者具有相似性

注解地方

  • @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上。
  • @Validated:可以用在类型、方法和方法参数上,不能用在成员属性(字段)上。

@Validated和@Valid在级联验证功能上的区别

  • @Valid:用在方法入参上无法单独提供级联验证功能。能够用在成员属性(字段)上,提示验证框架进行级联验证。

  • @Validated:用在方法入参上无法单独提供级联验证功能。不能用在成员属性(字段)上,也无法提示框架进行级联验证。能配合级联验证注解@Valid进行级联验证。

  • 总结: 通常使用@Validated, 级联验证使用@Valid。

自定义校验注解

自定义校验注解用于基础校验注解不能满足业务需求。

  • 自定义效验注解验证密码是否相等
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*; /**
* @Description 自定义参数校验注解
* @Documented 注解中的注释加入文档
* @Retention 注解保留阶段 RetentionPolicy.RUNTIME 运行阶段
* @Target 作用目标,注解的使用范围 TYPE:用于描述类、接口(包括注解类型) 或enum声明
* @Constraint 将注解和注解关联类关联到一起
* @author coisini
* @date Aug 10, 2021
* @Version 1.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Constraint(validatedBy = PasswordValidator.class)
public @interface PasswordEquals { int min() default 4; int max() default 6; String message() default "passwords are not equal"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
  • 自定义校验注解关联类
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; /**
* @Description 自定义校验注解关联类
* ConstraintValidator的第一个参数:注解的类型
* ConstraintValidator的第二个参数:自定义注解修饰的目标的类型
* @author coisini
* @date Aug 10, 2021
* @Version 1.0
*/
public class PasswordValidator implements ConstraintValidator<PasswordEquals, ValidEvt> { private int min;
private int max; /**
* 初始化获取注解参数
* @param constraintAnnotation
*/
@Override
public void initialize(PasswordEquals constraintAnnotation) {
this.min = constraintAnnotation.min();
this.max = constraintAnnotation.max();
} /**
* 校验参数
* @param value
* @param context
* @return
*/
@Override
public boolean isValid(ValidEvt value, ConstraintValidatorContext context) {
String password1 = value.getPassword1();
String password2 = value.getPassword2(); return password1.equals(password2) && this.validLength(password1, password2);
} /**
* 校验密码长度
* @param password1
* @param password2
* @return
*/
private boolean validLength(String password1, String password2) {
return password1.length() > min && password1.length() < max
&& password2.length() > min && password2.length() < max;
} }
  • 自定义注解校验类
/**
* @Description 自定义注解校验类
* @author coisini
* @date Aug 10, 2021
* @Version 1.0
*/
@Getter
@Builder
@PasswordEquals(min = 1, message = "Incorrect password length or passwords are not equal")
public class ValidEvt { private String password1;
private String password2; }
  • 参数验证异常统一处理
@ControllerAdvice
public class GlobalExceptionAdvice {
/**
* 参数校验异常处理器
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public UnifyMessage handleBeanValidation(HttpServletRequest request, MethodArgumentNotValidException e) {
String method = request.getMethod();
String requestUrl = request.getRequestURI();
System.out.println(e); List<ObjectError> errors = e.getBindingResult().getAllErrors();
String message = formatAllErrorMessages(errors); return new UnifyMessage(10001, message,method + " " + requestUrl);
} /**
* 自定义注解校验异常处理器
* @param req
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public UnifyMessage handleConstrainException(HttpServletRequest req, ConstraintViolationException e){
String method = req.getMethod();
String requestUrl = req.getRequestURI();
String message = e.getMessage();
return new UnifyMessage(10001, message,method + " " + requestUrl);
} /**
* 异常消息拼接
* @param errors
* @return
*/
private String formatAllErrorMessages(List<ObjectError> errors){
StringBuffer errorMsg = new StringBuffer();
errors.forEach(error ->
errorMsg.append(error.getDefaultMessage()).append(";")
);
return errorMsg.toString();
}
}
  • 统一消息返回
/**
* @Description 统一消息返回
* @author coisini
* @date Aug 9, 2021
* @Version 1.0
*/
public class UnifyMessage { private int code;
private String message;
private String requestUrl; public int getCode() {
return code;
} public String getMessage() {
return message;
} public String getRequestUrl() {
return requestUrl;
} public UnifyMessage(int code, String message, String requestUrl) {
this.code = code;
this.message = message;
this.requestUrl = requestUrl;
} }
  • 测试类
@PostMapping(value = "/test1")
public ValidEvt test1(@RequestBody @Validated ValidEvt evt){
return evt;
}
  • 测试结果

- End -



梦想是咸鱼
关注一下吧

SpringBoot - Bean validation 参数校验的更多相关文章

  1. 测试开发专题:如何在spring-boot中进行参数校验

    上文我们讨论了spring-boot如何去获取前端传递过来的参数,那传递过来总不能直接使用,需要对这些参数进行校验,符合程序的要求才会进行下一步的处理,所以本篇文章我们主要讨论spring-boot中 ...

  2. 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知

    乔丹是我听过的篮球之神,科比是我亲眼见过的篮球之神.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免 ...

  3. SpringBoot 如何进行参数校验,老鸟们都这么玩的!

    大家好,我是飘渺. 前几天写了一篇 SpringBoot如何统一后端返回格式?老鸟们都是这样玩的! 阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数 ...

  4. SpringBoot 如何进行参数校验

    为什么需要参数校验 在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加用户的时候校验用户邮箱地址.手机号码格式是否正确. ...

  5. springboot项目--传入参数校验-----SpringBoot开发详解(五)--Controller接收参数以及参数校验----https://blog.csdn.net/qq_31001665/article/details/71075743

    https://blog.csdn.net/qq_31001665/article/details/71075743 springboot项目--传入参数校验-----SpringBoot开发详解(五 ...

  6. SpringBoot Validation参数校验 详解自定义注解规则和分组校验

    前言 Hibernate Validator 是 Bean Validation 的参考实现 .Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的 ...

  7. 【全网最全】springboot整合JSR303参数校验与全局异常处理

    一.前言 我们在日常开发中,避不开的就是参数校验,有人说前端不是会在表单中进行校验的吗?在后端中,我们可以直接不管前端怎么样判断过滤,我们后端都需要进行再次判断,为了安全.因为前端很容易拜托,当测试使 ...

  8. java bean validation 参数验证

    一.前言 二.几种解决方案 三.使用bean validation 自带的注解验证 四.自定义bean validation 注解验证 一.前言 在后台开发过程中,对参数的校验成为开发环境不可缺少的一 ...

  9. javax.validation参数校验

    在实体字段加注解: /** * 机构名称 */ @ApiParam(name = "orgName", value = "机构名称") @Size(max = ...

随机推荐

  1. Sai学习笔记

    颜色模块的功能介绍 色轮 RGB滑块 HSV滑块(常用) H:色相 S:纯度 V:明度 中间色条,主要用来混色 颜料盒 调色板 选择工具的使用 选择框 快捷键:Ctrl+D 套索 魔棒 图文工具使用 ...

  2. 关于使用Draw.io画数据库E-R图的说明

    背景简介 E-R图也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型.属性和联系的方法,用来描述现实世界的概念模型. diagrams.net是用于构建图表 ...

  3. consul 多节点/单节点集群搭建

    三节点配置 下载安装包 mkdir /data/consul mkdir /data/consul/data curl -SLO https://github.com/consul/1.9.5/con ...

  4. 深入理解Java多线程——ThreadLocal

    目录 定义 API 场景分析 场景实验,观察Spring框架在多线程场景的执行情况 10000此请求,单线程 10000次请求,线程数加到100 对c的访问加锁 把c设为ThreadLocal 收集多 ...

  5. NSIS 插件开发引发的思考

    支持NSIS的DLL扩展编程通用语法结构 #include <windows.h> #include <stdio.h> #define FORCE_SWITCH " ...

  6. python 09篇 操作Excel

    一.往Excel中写数据 使用pip install xlwt安装xlwt模块,用xlwt模块进行对Excel进行写数据. import xlwt # book = xlwt.Workbook() # ...

  7. Linux系统下Java 转换Word到PDF时,结果文档内容乱码的解决方法

    本文分享在Linux系统下,通过Java 程序代码将Word转为PDF文档时,结果文档内容出现乱码该如何解决.具体可参考如下内容: 1.问题出现的背景 在Windows系统中,使用Spire.Doc ...

  8. element取消全局loading

    背景 前两天在开发一个管理后台项目时, 遇到了一个问题,后端接口返回特别慢,由于该接口调用的是第三方API,无法通过后端去处理.此时想到用loading动画,但随之而来也产生了不少问题, 在此记录一下 ...

  9. 【洛谷 P2388 阶乘之乘】模拟

    分析 求因数5的个数 AC代码 #include<iostream> using namespace std; int main() { long long n,t,ans=0,s=0; ...

  10. Rowid和Rownum

    Rowid和Rownum对于数据库开发人员来说基本很少用到,因为在企业数据库开发中大多都是进行数据批处理,但是对于其他数据库人员来说还是会用到的. rowid和rownum都是虚列,但含义完全不同.r ...