JSR303是一套JavaBean参数校验的标准,定义了很多常用的校验注解
可以直接将这些注解加在我们JavaBean的属性上面就可以在需要校验的时候进行校验了

依赖

<!-- 属性效验-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

一、JSR303定义的校验类型

空检查
@Null 传参不包括该字段,或者传参该字段值为null
@NotNull 字段必传,且字段值不能为null,String可为空字符串,Interger不能为空字符串(表单值为 “” 时,可以转换:Stirng为"",Integer为Null),一般加在Interger类型上
@NotBlank 字段必传,且字段值不能为null,去掉前后空格长度大于0(trim()),一般加在字符串上
@NotEmpty 字段必传,且字段值不能为null,加在字符串上效果同@NotBlank,也可以加在(Array,Collection,Map)上,判断不能null,一般加在集合、列表、Map上
Booelan检查
@AssertTrue Boolean 成员变量的值只能为 true
@AssertFalse Boolean 成员变量的值只能为 false
长度检查
@Size(min=, max=) 校验对象(Array,Collection,Map,String)长度是否在给定的范围之内,一般加在列表、集合、Map上
@Length(min=, max=) 校验字符串长度是否在指定范围内,只能加在字符串上
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查 建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min Number 和 String 对象值大于等于指定的值
@Max Number 和 String 对象值小于等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 检查数字是否介于min和max之间.
@Range(min=10000,max=50000,message=“range.bean.wage”) private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber 信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)

场景一:前端传过来的字段如何在后台做效验,最老的方法就是if else显得不是很灵活。如果前端传来100个字段就得写许多多余的代码。
第一个场景就是在后台创建的实体和前端传来的字段做对应映射,加上JSR303注解来做灵活的效验

1:给Bean实体添加校验注解:javax.validation.constraints(大部分注解都在这个包下),并定义自己的message提示如下:

二、在Springboot项目中使用

2.1、编写需要校验的Bean

package com.example.jsr.entity;import com.example.jsr.Constant;
import lombok.Data;
import org.hibernate.validator.constraints.Length;import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.List;/*** @author Deyou Kong* @description 品牌实体类* @date 2023/2/25 9:16 上午*/@Data
public class Brand implements Serializable {/*** ID*/private Integer id;/*** 品牌名称*/@NotBlank(message = Constant.NAME_NOT_NULL)@Length(min = 2, max = 32, message = "品牌长度为2-32")private String name;/*** 描述*/@NotNull(message = "描述不能为空NotNull")private String description;/*** 排序*/@Min(value = 1, message = "不能小于1")@Max(value = 10, message = "不能大于10")@NotNull(message = "排序不能为空")private Integer sort;@NotEmpty(message = "关联应用不能为空")@Size(min = 1, message = "品牌最少关联一个应用")private List<Integer> appList;}

2.2、Controller方法中增加校验注解

@RestController
@RequestMapping("/brand")
public class BrandController {@Resourceprivate BrandService brandService;@PostMapping("/save")public JsonResult saveBrand(@Validated @RequestBody Brand brand, BindingResult bindingResult) {System.out.println("进入controller的save方法");if (bindingResult.hasErrors()) {//1.出现参数非法情况Map<String, String> map = new HashMap<>();bindingResult.getFieldErrors().forEach(fieldError -> {map.put(fieldError.getField(), fieldError.getDefaultMessage());});JsonResult jsonResult = JsonResult.fail("参数不正确,请检查");jsonResult.setData(map);return jsonResult;} else {//2.参数验证通过, 执行正常逻辑brandService.saveBrand(brand);return JsonResult.commonSuccess();}}
}

备注:这里一个@Validated (org.springframework.validation.annotation.Validated;)的参数后必须紧挨着一个BindingResult 参数接收参数效验的结果,否则spring会在校验不通过时直接抛出异常

2.3、统一异常处理

添加BindingResult参数后,虽然可以使后台在出现异常时,进行处理并返回统一的结果。但是我们会发现,我们写了许多与业务不相关的代码,为了解决这个问题,我们可以通过@ControllerAdvice进行异常的统一处理。

1、编写统一异常处理类

package com.example.jsr.advice;import com.example.jsr.entity.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;
import java.util.Map;/*** @author Deyou Kong* @description 全局异常捕获处理器* @date 2023/2/25 10:57 下午*/@RestControllerAdvice
@Slf4j
public class GlobalExceptionControllerAdvice {/*** 出现参数非法情况,抛出MethodArgumentNotValidException异常,在此捕获处理* @param e* @return*/@ExceptionHandler(MethodArgumentNotValidException.class)public JsonResult handlerMethodArgumentNotValidException(MethodArgumentNotValidException e){BindingResult bindingResult = e.getBindingResult();Map<String, String> map = new HashMap<>();bindingResult.getFieldErrors().forEach(fieldError -> {map.put(fieldError.getField(), fieldError.getDefaultMessage());});JsonResult jsonResult = JsonResult.fail("参数不正确,请检查");jsonResult.setData(map);return jsonResult;}/**兜底* @param e* @return*/@ExceptionHandler(Exception.class)public JsonResult handlerException(Exception e){JsonResult jsonResult = JsonResult.fail("未知的系统异常");jsonResult.setData(e.getMessage());return jsonResult;}
}

2、把之前加的BindingResult去掉,还原成原先最干净的代码

@RestController
@RequestMapping("/brand")
public class BrandController {@Resourceprivate BrandService brandService;@PostMapping("/save")public JsonResult saveBrand(@Validated @RequestBody Brand brand) {System.out.println("进入controller的save方法");brandService.saveBrand(brand);return JsonResult.commonSuccess();}
}

三、分组效验

在简单的数据验证中,我们使用完成了数据验证。但是还存在一些问题,如在添加品牌的时候Id为null,但在修改品牌的时候Id不能为null,这样的话,就冲突了。

那怎么办呢?我们可以给他们分个组,添加操作使用一组验证规则,修改操作使用一组验证规则。这就是分组验证的功能。

以@NotNull注解为例

@Constraint(validatedBy = { })
public @interface NotNull {String message() default "{javax.validation.constraints.NotNull.message}";//分组验证时使用Class<?>[] groups() default { };...

我们通过@NotNul注解的groups指定属于哪个组

实现步骤:

1、创建AddGroupUpdateGroup接口分别表示添加组和更新组

//这俩个接口只是用来标记的,不需要实现
public interface AddGroup {}public interface UpdateGroup {}

2、实体类中使用注解时,标明该验证规则属于哪个组


@Data
public class Brand implements Serializable {/*** ID*/@NotNull(message = "ID不能为空", groups = {UpdateGroup.class})private Integer id;/*** 品牌名称*/@NotBlank(message = Constant.NAME_NOT_NULL, groups = {AddGroup.class, UpdateGroup.class})@Length(min = 2, max = 32, message = "品牌长度为2-32", groups = {AddGroup.class, UpdateGroup.class})private String name;/*** 描述*/@NotNull(message = "描述不能为空NotNull")private String description;/*** 排序*/@Min(value = 1, message = "不能小于1")@Max(value = 10, message = "不能大于10")@NotNull(message = "排序不能为空")private Integer sort;@NotEmpty(message = "关联应用不能为空")@Size(min = 1, message = "品牌最少关联一个应用")private List<Integer> appList;
}

3、Controller中娇艳注解必须为@Validated

注意:
使用分组功能时,必须使用 @Validated 替代 @Valid,它支持分组效验功能

@PostMapping("/save")
public JsonResult saveBrand(@Validated(AddGroup.class) @RequestBody Brand brand) {System.out.println("进入controller的save方法");brandService.saveBrand(brand);return JsonResult.commonSuccess();
}@PostMapping("/update")
public JsonResult updateBrand(@Validated(UpdateGroup.class) @RequestBody Brand brand){System.out.println("进入controller的update方法");brandService.updateBrand(brand);return JsonResult.success("");
}

4、测试

1、上面实体类中 name 字段的@NotBlank、@Length两个注解对AddGroup、UpdateGroup两个分组都生效,所以测试结果中都有错误提示
2、ID字段只针对UpdateGroup分组生效,测试结果显示只针对update接口进行判断
3、其他字段的注解均未指定分组,那么在Controller指定分组的情况下,这些字段上面的校验注解不生效

四、自定义效验注解

步骤:
1、编写一个自定义的效验注解
2、编写一个自定义的效验器
3、关联自定义的效验器和自定义的效验注解

1、Brand实体类中增加一个字段

private String logo;   // 需要判断logo地址是否以http开头

2、、自定义 IsUrl 注解类

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {IsUrlValidator.class })
public @interface IsUrl {//JSR303规范中,要求必须有message、groups、payload这三个方法//default: 当message为null时,默认会到ValidationMessages.properties配置文件中找com.fcp.common.valid.ListValue.message的值String message() default "{com.fcp.common.valid.ListValue.message}";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };// 注解中用户配置的字段值,如我指定url的规则存放哪个字段,这里存放在value字段中String value() default "";
}

3、编写一个自定义的效验器IsUrlValidator.class
校验器的类名与注解类中Constraint中类名一致


//IsUrl:自定义的注解
//String:注解参数类型
public class IsUrlValidator implements ConstraintValidator<IsUrl, String> {/*** 接收我们自定义的属性value,默认为""*/private String value = "";/*** 1、初始化方法:通过该方法我们可以拿到我们的注解* @param constraintAnnotation*/@Overridepublic void initialize(IsUrl constraintAnnotation) {// 接收我们自定义的属性value,默认为""value = constraintAnnotation.value();}/*** //2、逻辑处理* @param s    前端传参的值* @param constraintValidatorContext* @return*/@Overridepublic boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {System.out.println("注解获取到的值为:" + value);System.out.println("用户传参:"+ s);boolean b = s.startsWith(value);System.out.println(b);return b;}
}

4、在实体类中使用注解

    @IsUrl(value = "https:", message = "URL地址不正确", groups = {AddGroup.class, UpdateGroup.class})@NotBlank(message = "logo不能为空")private String logo;

5、测试

五、校验顺序

在测试过程中,发现多个注解校验顺序不定,这里还不知道怎么解决
看到一篇文章https://blog.csdn.net/qq_41762594/article/details/109326971,等后面有空在研究

JSR303注解字段校验相关推荐

  1. aop+注解 实现对实体类的字段校验_SpringBoot实现通用的接口参数校验

    来自:掘金,作者:cipher 链接:https://juejin.im/post/5af3c25b5188253064651c76 原文链接:http://www.ciphermagic.cn/sp ...

  2. hibernate-validate如何校验controller+service+分组校验+自定义注解实现校验规则等

    配置参数启动时校验 如果配置文件没有相关的配置,那么**启动时**就会出现以下异常: Description:Binding to target com.toby.provide.Applicatio ...

  3. 使用validate注解做校验以及自定义validate注解

    Springboot版本:2.3.1.RELEASE 引入依赖 <dependency><groupId>org.springframework.boot</groupI ...

  4. java 实体字段校验@Valid - @NotNull @NotEmpty @NotBlank - ValidExceptionHandler

    java 实体字段校验@NotNull @NotEmpty @NotBlank 注意在使用 @NotBlank 等注解时,一定要和 @valid 一起使用,否则 @NotBlank 不起作用. 1.@ ...

  5. 【工具】JSR-303后端参数校验框架的使用方法及说明

    [工具]JSR-303后端参数校验框架的使用方法及说明 文章目录 [工具]JSR-303后端参数校验框架的使用方法及说明 1. 统一校验需求 2. 使用说明 2.1 引入依赖 2.2 规则说明 2.3 ...

  6. java自定义注解实现校验对象属性是否为空

    前面学习了如何自定义一个注解:java如何优雅的自定义一个注解 下面来实战演示一下如何使用自定义注解做一些实际的功能.比如校验对象属性是否为空. 一.自定义一个NotNull注解 我们自定义一个Not ...

  7. DRF框架—序列化器中的字段校验规则

    一.怎么校验创建的项目名是否是唯一的,当项目名name字段不唯一,怎么设置提示信息? 方法:导入UniqueValidator from rest_framework.validators impor ...

  8. 实体字段校验@NotNull、@NotEmpty、@NotBlank

    在前段向后端提交较多数据时,我们一般都会遇到字段校验的问题,使用Spring的字段验证很省事,一般会使用@NotNull.@NotEmpty.@NotBlank这三个东西,但使用的时候后端接收参数一定 ...

  9. Python全量字段校验

    Python全量字段校验 1.概念与安装 1.1全量字段校验概念 校验接⼝返回响应结果的全部字段 1.2校验内容 字段值 字段名 或 字段类型 1.3校验流程 定义json语法校验格式 ⽐对接口实际响 ...

最新文章

  1. POJ-1430 Binary Stirling Numbers 组合数学
  2. Kali Linux安装Google中文输入法(只需5步)
  3. 【Android 热修复】热修复原理 ( 热修复框架简介 | 将 Java 字节码文件打包到 Dex 文件 )
  4. Ubuntu18.04安装Dlib-19.19.0成功
  5. php oracle 中文字段,怎么解决php oracle乱码问题
  6. 18春学期《计算机应用基础》,18春学期(1709、1803)《计算机应用基础》在线作业及答案.pdf...
  7. 统一并发 III——跨基准测试
  8. android常用的工厂模式,Android的设计模式-简单工厂模式
  9. 何恺明!再斩ICCV 2017最佳论文
  10. oracle中的符号含义
  11. Autocad 2015如何激活成功
  12. 【数学信号处理】基于matlab数字信号频谱分析【含Matlab源码 1544期】
  13. 【0.96OLED屏幕】原理图及SSD1306引脚功能
  14. 使用IDEA进行Lua代码调试、自动提示、代码跳转、智能重命名
  15. Foxit PDF Editor(福昕阅读器)中插入新的PDF空白页方法
  16. 互联网起源之工人阶级
  17. ECharts :lable显示所有数据、修改字体样式
  18. git 将暂存区文件提交_git 暂存区
  19. r语言中which的使用_大数据分析R语言RStudio使用教程
  20. js实现页面定时跳转

热门文章

  1. 暴风魔镜 光标漂移_如何防止光标在游戏过程中漂移到另一个监视器
  2. matlab三个商人三个随从,商人们怎样安全过河 (附MATLAB程序完整)
  3. ORA-03113: end-of-file on communication channel 解决方法
  4. 「为了孩子上海淀小学,我一周上七节课」
  5. 二叉树寻找节点x的所有祖先
  6. MathType怎么编辑等号带点
  7. matlab小船渡河物理模型,高中物理 | 小船渡河模型和斜拉船模型
  8. oracle txn,Oracle 11gR2上遇到blocking txn id for DDL等待事件,11gr2txn
  9. 【转载】分页插件中关于PageInfo
  10. 期货股票自动交易下单接口怎么执行策略函数?