JSR303

news/2024/11/7 11:09:34/

文章目录

  • 一.引入
  • 二.实例需求
  • 三.环境搭建
    • 1.依赖引入
    • 2.常用注解
  • 四.使用
    • 1.简单使用
    • 2.自定义错误信息
    • 3.添加多个字段错误信息回去
    • 4.改进
    • 5.全局异常处理
  • 五.异常代码
    • 1.图解
    • 2.实例
  • 六.分组校验
    • 1.引入
    • 2.groups属性
    • 3.修改实体类
    • 3.controller修改

一.引入

日常开发中,需要使用参数校验。
前端防君子,后端防小人。
学习谷里商城~

JSR 303验证框架

  1. JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 中
  2. JSR 303 通过在Bean属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则, 并通过标准的验证接口对 Bean 进行验证

在这里插入图片描述

  • Hibernate Validator扩展注解
  1. Hibernate Validator 和 Hibernate 没有关系,只是 JSR 303 实现的一个扩展.
  2. Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支 持以下的扩展注解:

在这里插入图片描述

二.实例需求

在这里插入图片描述

要求在图中都有显示。

三.环境搭建

1.依赖引入

引入spring-boot-starter-web
会自动导入,也可以单独导入

<parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.1.8.RELEASE</version>
</parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

在这里插入图片描述

如果,不使用Spring-boot,也可以单独引入依赖。
版本由自己指定

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>版本按需指定。
</dependency>

2.常用注解

约束注解名称约束注解说明
@Null用于验证对象为null
@NotNull用于对象不能为null,无法查检长度为0的字符串
@NotBlank只用于String类型上,不能为null且trim()之后的size>0
@NotEmpty用于集合类、String类不能为null,且size>0。但是带有空格的字符串校验不出来
@Pattern用于String对象是否符合正则表达式的规则
@Email用于String对象是否符合邮箱格式

具体使用注解,可以根据源码中注释进行使用。

注解也可以组合使用【在同一个实体属性上使用2个注解】。
通常组合注解是,要求属性不为Null,且符合某个标准
在这里插入图片描述

在这里插入图片描述

四.使用

1.简单使用

在这里插入图片描述

在接受数据的Controller中加@Valid注解,才会触发校验规则。
在这里插入图片描述

我们这里简单测试一下
在这里插入图片描述

另外,我们可以将校验过程中发生的错误保存到对象中去。
现在实际操作。

/*** 1.@Valid Monster monster:表示对monster接受的数据进行校验* 2.Errors errors:如果校验出现错误,将校验的错误信息保存到errors* 3.Map<String, Object> map:表示如果校验出现错误,将校验的错误信息保存到map中,同时保存Monster信息* 4.校验发生的时机:在SpringMVC底层,反射调用目标方法时,会接收http请求的数据。* 然后,根据注解【Monster实体类中标注的】进行验证。* 验证过程中,如果出现了错误,将错误信息填充到errors和map中*/@RequestMapping("/save")public R save(@Valid @RequestBody BrandEntity brand, Errors errors, Map<String, Object> map){System.out.println("======map======");for (Map.Entry<String, Object> entry : map.entrySet()) {System.out.println("key = " + entry.getKey() + " ,,,value = " + entry.getValue());}System.out.println("======errors======");if(errors.hasErrors()){List<ObjectError> allErrors = errors.getAllErrors();for (ObjectError error : allErrors) {//在这里可以凭借error获取错误的属性名,以及默认错误的返回信息//System.out.println(error.getObjectName() + "," + error.getDefaultMessage());//brandEntity,不能为空System.out.println("error = " + error);}//在这里,写入错误信息return R.error(400, "消息不能为空");}brandService.updateById(brand);return R.ok();}

----map----
key = org.springframework.validation.BindingResult.brandEntity,value = org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object ‘brandEntity’ on field ‘name’: rejected value []; codes [NotBlank.brandEntity.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [brandEntity.name,name]; arguments []; default message [name]]; default message [不能为空]

------errors------
Field error in object ‘brandEntity’ on field ‘name’: rejected value []; codes [NotBlank.brandEntity.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [brandEntity.name,name]; arguments []; default message [name]]; default message [不能为空]


2.自定义错误信息

在这里插入图片描述

3.添加多个字段错误信息回去

/*** @param bindingResult 封装前面对象的结果信息【可以查看是否有错误】* 这里写bindingResult,该方法发生异常就会在这里捕获。不会抛出;* 如果不写bindingResult,就会抛出异常。这个在之后简化的时候使用*/@RequestMapping("/save")public R save(@Valid @RequestBody BrandEntity brand, BindingResult bindingResult) {if (bindingResult.hasErrors()){//如果校验有错误Map<String,String> map = new HashMap<>();//遍历所有的错误bindingResult.getFieldErrors().forEach((item) -> {//获取到发生错误的属性名String field = item.getField();//获取到错误提示//这里的defaultMessage来自我们实体类上配置的message//如果没有配置,默认使用系统自动添加的String defaultMessage = item.getDefaultMessage();map.put(field,defaultMessage);});return R.error(400, "提交的数据不合法").put("data",map);}brandService.updateById(brand);return R.ok();}

添加其他Field检验注解

package com.atguigu.gulimall.product.entity;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;import javax.validation.constraints.*;/*** 品牌* * @author sht* @email sht@gmail.com* @date 2022-10-30 13:47:36*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 品牌id*/@TableIdprivate Long brandId;/*** 品牌名*/@NotBlank(message = "品牌名必须提交")private String name;/*** 品牌logo地址* logo必须是一个URL,我们在设置一个自定义信息提示*/@URL(message = "logo必须是一个合法的url地址")@NotBlank(message = "不能为空")private String logo;/*** 介绍*/@NotBlank(message = "不能为空")private String descript;/*** 显示状态[0-不显示;1-显示]*/@NotNull(message = "不能为空")private Integer showStatus;/*** 检索首字母* 2.@Pattern是正则* 使用组合注解*/@Pattern(regexp = "^[a-zA-Z]$",message = "需要填写a-z或A-Z")@NotBlank(message = "不能为空")private String firstLetter;/*** 排序*/@Min(value = 0,message = "排序必须大于等于0")@NotNull(message = "不能为空")private Integer sort;}

在这里插入图片描述

4.改进

目前,我们将数据校验放到特定Controller中。
每次执行controller,都需要调用代码。
多个controller,需要在每个controller写一个校验,非常麻烦。
将校验提取出来,放到一个专门的类中。


使用ControllerAdvice,全局异常处理。

/*** 1.@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")* basePackages = "com.atguigu.gulimall.product.controller":异常处理扫描的包* 2.因为,要以Json格式返回,添加@ResponseBody* 3.有@ControllerAdvice、@ResponseBody,简化这2个注解@RestControllerAdvice[包含2个注解]**/
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionAdvice {/*** 1.value = Exception.class,可以处理的异常信息* 2.Exception e:捕获到的异常信息*/@ExceptionHandler(value = Exception.class)public R handlerValidException(Exception e){log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());return R.error();}
}

然后,发送一个请求,查看idea报的异常信息是什么。
主要是异常类型是什么
在这里插入图片描述

在这里插入图片描述

然后根据获取到的异常信息,修改全局异常处理类

package com.atguigu.gulimall.product.exception;import com.atguigu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;
import java.util.Map;/*** 1.@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")* basePackages = "com.atguigu.gulimall.product.controller":异常处理扫描的包* 2.因为,要以Json格式返回,添加@ResponseBody* 3.有@ControllerAdvice、@ResponseBody,简化这2个注解@RestControllerAdvice[包含2个注解]**/
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionAdvice {/*** 1.value = Exception.class,可以处理的异常信息* 2.Exception e:捕获到的异常信息* 捕获异常类型, 一般根据业务进行判断*/@ExceptionHandler(value = MethodArgumentNotValidException.class)public R handlerValidException(MethodArgumentNotValidException e){log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());//这个和之前是一样的,niceBindingResult bindingResult = e.getBindingResult();Map<String,String> errMap = new HashMap<>();bindingResult.getFieldErrors().forEach((fieldError -> {errMap.put(fieldError.getField(),fieldError.getDefaultMessage());}));return R.error(400, "数据校验出现问题").put("data", errMap);}
}

在这里插入图片描述

在这里插入图片描述

5.全局异常处理

/*** 处理其他出现的任何异常*/@ExceptionHandler(value = Throwable.class)public R handlerException(Throwable throwable){return R.error();}

五.异常代码

1.图解

在这里插入图片描述
将错误代码,使用枚举一一列举出来,使用的时候,用枚举引入。

2.实例

在gulimall-common中创建一个枚举类
在这里插入图片描述

package com.atguigu.common.exception;import lombok.AllArgsConstructor;
import lombok.Getter;@Getter
@AllArgsConstructor
public enum BizCodeEnums {UNKNOW_EXCEPTION(10000,"系统未知异常"),VALID_EXCEPTION(10001,"参数格式校验失败");private Integer code;private String msg;
}

此时,数据校验错误,我们直接用枚举中的。

package com.atguigu.gulimall.product.exception;import com.atguigu.common.exception.BizCodeEnums;
import com.atguigu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;
import java.util.Map;/*** 1.@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")* basePackages = "com.atguigu.gulimall.product.controller":异常处理扫描的包* 2.因为,要以Json格式返回,添加@ResponseBody* 3.有@ControllerAdvice、@ResponseBody,简化这2个注解@RestControllerAdvice[包含2个注解]**/
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionAdvice {/*** 1.value = Exception.class,可以处理的异常信息* 2.Exception e:捕获到的异常信息*/@ExceptionHandler(value = MethodArgumentNotValidException.class)public R handlerValidException(MethodArgumentNotValidException e){log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());//这个和之前是一样的,niceBindingResult bindingResult = e.getBindingResult();Map<String,String> errMap = new HashMap<>();bindingResult.getFieldErrors().forEach((fieldError -> {errMap.put(fieldError.getField(),fieldError.getDefaultMessage());}));return R.error(BizCodeEnums.VALID_EXCEPTION.getCode(), BizCodeEnums.VALID_EXCEPTION.getMsg()).put("data", errMap);}/*** 处理其他出现的任何异常*/@ExceptionHandler(value = Throwable.class)public R handlerException(Throwable throwable){return R.error(BizCodeEnums.UNKNOW_EXCEPTION.getCode(),BizCodeEnums.UNKNOW_EXCEPTION.getMsg());}
}

在这里插入图片描述

在这里插入图片描述

六.分组校验

1.引入

一个实体类,对应数据库一张表。
在对一张表,进行增删查改操作时,校验规则有时候不一样。新增情况、修改情况,校验规则不同。
新增,不需要携带品牌id,且一些数据必须填写。
修改,必须携带品牌id,而且一些不用改的数据不需要填写。此时,我们就要使用JSR303提供的分组校验功能。我们使用groups,这个在每个校验规则中有这个属性。

2.groups属性

在这里插入图片描述

groups属性,是一个类型数组。因此,可以有多种情况。我们需要定义几个类型,使用接口。这里接口只起到标注作用。因为,很多微服务有这个需求,我们放到gulimall-common中。

![在这里插入图片描述](https://img-blog.csdnimg.cn/caad3e8a48834c878746cb3a14981550.png)

3.修改实体类

package com.atguigu.gulimall.product.entity;import com.atguigu.common.valid.AddGroup;
import com.atguigu.common.valid.UpdateGroup;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;import javax.validation.constraints.*;/*** 品牌* * @author sht* @email sht@gmail.com* @date 2022-10-30 13:47:36*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 品牌id* 修改时,提交该字段* 新增时,不提交该字段*/@NotNull(message = "修改不需指定id",groups = {UpdateGroup.class})@Null(message = "新增不能指定id",groups = {AddGroup.class})@TableIdprivate Long brandId;/*** 品牌名* 新增,修改时,必须提交改字段*/@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})private String name;}

3.controller修改

需要在待校验的对象之前添加注解@Validated

在这里插入图片描述

添加@Validated注解后,指定分组后。
其他未指定分组的校验,就不会生效。
只会按照分组进行校验。
想要生效,必须在其他校验上写上分组。


在其他所有校验注解中添加groups = {AddGroup.class}

package com.atguigu.gulimall.product.entity;import com.atguigu.common.valid.AddGroup;
import com.atguigu.common.valid.ListValue;
import com.atguigu.common.valid.UpdateGroup;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;import javax.validation.constraints.*;/*** 品牌* * @author sht* @email sht@gmail.com* @date 2022-10-30 13:47:36*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 品牌id**/@NotNull(message = "修改不需指定id",groups = {UpdateGroup.class})@Null(message = "新增不能指定id",groups = {AddGroup.class})@TableIdprivate Long brandId;/*** 品牌名**/@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})private String name;/*** 品牌logo地址* logo必须是一个URL,我们在设置一个自定义信息提示*/@URL(message = "logo必须是一个合法的url地址",groups = {AddGroup.class})@NotBlank(message = "不能为空",groups = {AddGroup.class})private String logo;/*** 介绍*/@NotBlank(message = "不能为空",groups = {AddGroup.class})private String descript;/*** 显示状态[0-不显示;1-显示]*/@NotNull(message = "不能为空",groups = {AddGroup.class})@ListValue(vals = {0,1},message = "状态必须为0或1",groups = {AddGroup.class})private Integer showStatus;/*** 检索首字母* 2.@Pattern是正则* 使用组合注解*/@Pattern(regexp = "^[a-zA-Z]$",message = "需要填写一个字母[a-z或A-Z]",groups = {AddGroup.class})@NotBlank(message = "不能为空",groups = {AddGroup.class})private String firstLetter;/*** 排序*/@Min(value = 0,message = "排序必须大于等于0",groups = {AddGroup.class})@NotNull(message = "不能为空",groups = {AddGroup.class})private Integer sort;}

http://www.ppmy.cn/news/142789.html

相关文章

ORA-39002

oracle 11g执行expdp导出脚本时报错&#xff1a; ORA-39002:操作无效 ORA39070:无法打开日志文件 ORA-29283:文件操作无效 ORA-06512:在“SYS.UTL_FILE”,line 536 ORA-29283:文件操作无效 解决方式&#xff1a; 这是由于导出的目录不存在&#xff0c;需要新建directory相关目…

as3930工作流程简述

奥地利微电子公司扩展旗下射频产品线,推出单通道、低功耗、低频唤醒接收器AS3930,以最低的电流消耗实现了最高灵敏度和业内最大范围。 AS3930全面优化了功耗、灵敏度和可编程性,支持广泛使用的125 kHz频带,适合各种应用。 AS3930芯片里包括一个接收通道&#xff0c;一个频率探…

【渝粤题库】国家开放大学2021春3930事故管理与应急处置题目

试卷代号&#xff1a;3930 2021年季学期期末统一考试 事故管理与应急处置 试题&#xff08;开卷&#xff09; 2021年7月 一、单选题&#xff08;每题3分&#xff0c;共30分&#xff09; 1.《突发事件应对法》规定&#xff0c;国家建立统一领导、综合协调、分类管理、分级负责、…

机器视觉怎么对陶瓷板的外观尺寸进行自动检测?

随着工业自动化的不断发展&#xff0c;机器视觉技术在制造业中的应用越来越广泛。在陶瓷板行业中&#xff0c;机器视觉技术可以用于自动检测陶瓷板的外观尺寸&#xff0c;提高生产效率和产品质量。下面我们来介绍机器视觉如何对陶瓷板的外观尺寸进行自动检测。 一、检测原理 …

离散数学-数理逻辑

《离散数学》是计算机专业的一门十分重要的专业基础课。离散数学作为有力的数学工具对计算机的发展、计算机研究起着重大的作用。目前&#xff0c;计算机科学中普通采用离散数学中的一些基本概念、基本思想和基本方法。通过本课程的学习&#xff0c;掌握数理逻辑、集合论、代数…

linux(system V标准)进程间通信2

目录&#xff1a; 1.回顾上一节的代码 2.shmat、shmdt的使用 3.共享内存的大小为什么最好设置成4096字节的整数倍呢&#xff1f; 4.操作系统如何管理共享内存的 ----------------------------------------------------------------------------------------------------------…

Bug管理神器推荐:高效实用的Bug管理工具和软件

当涉及到错误管理时&#xff0c;bug管理软件或工具可能是一个很好的资产。使用正确的bug管理系统&#xff0c;团队可以有效地发现、处理和跟踪软件中的错误。市场上有许多不同的bug管理系统和工具&#xff0c;这使得选择正确的系统和工具变得困难。在要求bug管理软件或工具时&a…

第十二篇、基于Arduino uno,获取多个按键的输入信号(滤波消抖)——结果导向

0、结果 说明&#xff1a;先来看看串口调试助手显示的结果&#xff0c;当按下按键的时候&#xff0c;按一次会打印一次按键被按下&#xff0c;并且打印是哪个按键被按下。如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;虽然每个型号的按键形态各异&a…