spring中使用@Validated,什么是JSR 303数据校验,spring boot中怎么使用数据校验

文章目录

      • 一、JSR 303后台数据校验
        • 1.1 什么是 JSR303?
        • 1.2 为什么使用 JSR 303?
      • 二、Spring Boot 中使用数据校验
        • 2.1 基本注解校验
          • 2.1.1 使用步骤
          • 2.1.2 举例
            • @Valid注解
            • 全局统一异常处理
        • 2.2 分组校验
          • 2.2.1 使用步骤
          • 2.2.2 举例
            • @Validated注解
            • @Validated和@Valid的区别
        • 2.3 自定义校验注解
          • 2.3.1 使用步骤
          • 2.3.2 举例
        • 2.4 相关注解
          • 2.4.1 空检查相关注解
          • 2.4.2 长度检查
          • 2.4.3 布尔值检查
          • 2.4.4 日期检查
          • 2.4.5 数值检查
          • 2.4.6 其他

一、JSR 303后台数据校验

1.1 什么是 JSR303?

JSR 是 Java Specification Requests 的缩写,即 Java 规范提案。存在各种各样的 JSR,简单的理解为 JSR 是一种 Java 标准。JSR 303 是其中数据检验的一个标准(Bean Validation 1.0 (JSR 303))。

1.2 为什么使用 JSR 303?
  • 处理一段业务逻辑,首先要确保数据输入的正确性,所以需要先对数据进行检查,保证数据在语义上的正确性,再根据数据进行下一步的处理。

  • 前端可以通过 js 程序校验数据是否合法,后端同样也需要进行校验。而后端最简单的实现就是直接在业务方法中对数据进行处理,但是不同的业务方法可能会出现同样的校验操作,这样就出现了数据的冗余。

  • 为了解决这个情况,JSR 303 出现了。JSR 303 使用 Bean Validation,即在 Bean 上添加相应的注解,去实现数据校验。这样在执行业务方法前,都会根据注解对数据进行校验,从而减少自定义的校验逻辑,减少代码冗余。

二、Spring Boot 中使用数据校验

2.1 基本注解校验

之前在 Spring MVC 中介绍了数据校验,也例举了常用的注解。但是使注解生效必须要在 springmvc.xml 中配置,假如没有配置文件(比如在 spring boot)中怎么办?----> 下面详细介绍

spring boot 中需要引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.1.1 使用步骤

1、在相关的 Bean 上标注需要处理的注解,并指定需要提示的信息(若不指定,会从默认配置文件中读取默认的信息)。

2、在相关的方法上,使用 @Valid 注解(或者 @Validated 指定组名)标记需要被校验的数据,否则会不生效。

注意:检测到数据异常后,系统会向外抛出异常,如果做了统一异常处理,可以根据 postman 测试的结果,找到控制台打印出的相应的异常,并处理。

3、处理异常。

  • 使用 BindingResult 处理;

  • 也可以使用 全局统一异常 处理(@RestControllerAdvice 与 @ExceptionHandler

    全局统一异常处理后续会讲

2.1.2 举例

1、在相关的 Bean 上标注注解,并写上指定信息。

@Data
public class Emp {
    @NotNull(message = "id 不能为 null")
    private Integer id;

    @NotNull(message = "name 不能为 null")
    private String name;
}
@Valid注解

2、Controller层中使用 @Valid 注解标记需要检测的数据。

@RestController
public class EmpController {
    
    @PostMapping("/emp")
    public String createEmp(@Valid @RequestBody Emp emp) {
       return "ok";
    }
}

3、测试时,假如不传 id、name,会抛出 MethodArgumentNotValidException 异常。使用 BindingResult 可以处理异常信息,但 通常使用统一异常处理

① 使用 BindingResult:

@RestController
public class EmpController {
    @PostMapping("/emp")
    public Map createEmp(@Valid @RequestBody Emp emp, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, String> map = new HashMap<>();
            // 获取校验结果,遍历获取捕获到的每个校验结果
            result.getFieldErrors().forEach(item -> {
                // 获取校验的信息
                String message = item.getDefaultMessage(); // 也获取message的值
                String field = item.getField(); //获取属性名
                // 存储得到的校验结果
                map.put(field, message);
            });
            return map;
        }
        return "ok";
    }
}

问题:通过上面的步骤,已经可以捕获异常、处理异常,但是每次都是在业务方法中手动处理逻辑,这样的实现,代码肯定会冗余。可以将其抽出,使用 统一异常处理,每次异常发生时,将其捕获。

全局统一异常处理

② 全局统一异常处理:@RestControllerAdvice、@ExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map handlerValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        Map<String, String> map = new HashMap<>();
        // 获取校验结果,遍历获取捕获到的每个校验结果
        result.getFieldErrors().forEach(item ->{
            // 存储得到的校验结果
            map.put(item.getField(), item.getDefaultMessage());
        });
        return map;
    }
}

Controller 中不需要再用 BindingResult 去处理数据了。

2.2 分组校验

1、为什么使用 分组校验?

上面的过程,如果出现多个方法,都需要校验 Bean,且校验规则不同的时候,怎么办呢?分组校验就可以去解决该问题,每个分组指定不同的校验规则,不同的方法执行不同的分组,就可以得到不同的校验结果。

2、JSR 303 的每个注解都默认具备三个属性

  • message 用来定义数据校验失败后的提示消息,默认读取配置文件的内容。idea 全局搜索 ValidationMessages.properties,可以看到默认的信息。
  • groups 用来定义分组,它是一个 class 数组,可以指定多个分组。
  • payload()
String message() default "{javax.validation.constraints.NotNull.message}";

Class<?>[] groups() default { };

Class<? extends Payload>[] payload() default { };
2.2.1 使用步骤

1、定义一个空接口,用于指定分组,内部不需要任何实现。

2、指定 注解时,通过 groups 指定分组。用于指定在某个分组条件下,才去执行校验规则。

3、在 Controller 中通过 @Validated 注解指定分组,去指定校验。

注:使用分组校验后,Bean 注解上若不指定分组,则不会执行校验规则。

2.2.2 举例

1、如:创建两个分组接口 AddGroup、UpdateGroup。

AddGroup 用于指定 添加数据 时的校验规则(比如:id、name 均不为 null)。

UpdateGroup 用于指定 修改数据 时的校验规则(比如:name 不允许为 null)。

2、给 Bean 添加注解,并指定分组信息。

@Data
public class Emp {
  
    @NotNull(message = "id 不能为 null", groups = {AddGroup.class})
    private Integer id;

    @NotNull(message = "name 不能为 null", groups = {AddGroup.class, UpdateGroup.class})
    private String name;
}
@Validated注解

3、通过 @Validated 注解指定分组,去指定校验

@RestController
public class EmpController {
    @PostMapping("/emp")
    public void createEmp(@Validated({AddGroup.class}) @RequestBody Emp emp) {
       
    }

    @PutMapping("/emp")
    public void UpdateEmp(@Validated({UpdateGroup.class}) @RequestBody Emp emp) {
      
    }
}
@Validated和@Valid的区别
  • @Validated:

    • Spring 框架特有的注解,是标准 JSR-303 的一个变种,提供了一个分组功能。
    • 作用在类上、方法上、方法参数上,不能作用于成员属性上。
  • @Valid:

    • 标准 JSR-303 规范的标记型注解。

    • 作用在方法、构造函数、方法参数、成员属性上。

2.3 自定义校验注解

上面的注解满足不了业务需求时,可以自定义校验注解、然后自定义校验规则

2.3.1 使用步骤

1、自定义一个校验注解。可以创建一个 ValidationMessages.properties 用于保存默认的 message 信息。

2、自定义一个校验器(即自定义校验规则):实现 ConstraintValidator 接口,并重写相关方法。

  • initialize :初始化,可以获取 自定义的属性的值。

  • isValid :校验,可以获取到实际的值,然后与自定义的属性值进行比较。

3、将校验注解 与 校验器 关联起来。@Constraint(validatedBy = {校验器类.class})

2.3.2 举例

自定义一个校验规则,判断数据长度是否合法。

1、自定义一个校验注解:(比如这里是@TestValid)

@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy={JiaoYan.class})
public @interface TestValid {
    // 提示信息
    String message() default "{本自定义注解的全类名.message}";
   	
    class<?>[] groups() default {};
    
    Class<? extends Payload>[] payload() default {};
    
    /**
     * 返回一个长度
     * @return 默认为 5
     */
    int length() default 5; 
}

在这里插入图片描述

配置文件内容为:

自定义注解的全类名.message=值不能为 Null,且长度不超过 5

2、自定义一个校验器(比如这里是 JiaoYan)

/**
 * 实现 ConstraintValidator 接口,
 * 其中 ConstraintValidator 的泛型,一个需要指定自定义的注解,一个需要指定需要获取的值的类型。
 * 比如:
 *  ConstraintValidator<TestValid, String> 中
 *      TestValid   表示自定义注解
 *      String      表示获取的值的类型
 * 即定义规则,判断一个 String 的值的长度是否满足条件
 */
public class JiaoYan implements ConstraintValidator<TestValid, String> {
    /**
     * 用于保存自定义的(默认)长度
     */
    private int length;
    
    /**
     * 初始化方法,获取默认数据
     * @param test 注解对象
     */
    @Override
    public void initialize(TestValid test) {
        length = test.length();
    }
    
    /**
     * 自定义校验规则,如果 String 为 Null 或者 长度大于 5,则校验失败(返回 false)
     * @param value 需要校验的值
     * @param context
     * @return true 表示校验成功,false 表示校验失败
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value == null ? false : length > value.length();
    }
}

3、使用注解

@Data
public class Emp {
   
    @NotNull(message = "id 不能为 null", groups = {AddGroup.class})
    private Integer id;
    
    // 默认
    @TestValid()
    @NotNull(message = "name 不能为 null", groups = {AddGroup.class, UpdateGroup.class})
    private String name;

    // 自定义
    @TestValid(length = 10, message = "值不能为 Null 且长度不超过 10", groups = {AddGroup.class})
    private String email;
}
2.4 相关注解
2.4.1 空检查相关注解
注解注解详情
@Null被指定的注解元素必须为 Null
@NotNull任意类型,不能为 Null,但可以为空,比如:空数组[]、空字符串""
@NotBlank针对字符串,不能为 Null,且去除前后空格后的字符串长度要大于 0
@NotEmpty针对字符串、集合、数组,针对字符串时,不能为 Null,且长度要大于 0
2.4.2 长度检查
注解注解详情
@Size针对字符串、集合、数组,判断长度是否在给定范围内
@Length针对字符串,判断长度是否在给定范围内
2.4.3 布尔值检查
注解注解详情
@AssertTrue针对布尔值,用来判断布尔值是否为 true
@AssertFalse针对布尔值,用来判断布尔值是否为 false
2.4.4 日期检查
注解注解详情
@Past针对日期,用来判断当前日期是否为 过去的日期
@Future针对日期,用来判断当前日期是否为 未来的日期
2.4.5 数值检查
注解注解详情
@Max(value)针对字符串、数值,用来判断是否小于等于某个指定值
@Min(value)针对字符串、数值,用来判断是否大于等于某个指定值
2.4.6 其他
注解注解详情
@Pattern验证字符串是否满足正则表达式
@Email验证字符串是否满足邮件格式
@Url验证是否满足 url 格式
@Digits验证数字整数和小数位数,如:@Digits(integer=6, fraction=2)

文章结束!恭喜你又学会了一个知识点!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947607.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AWS K8s 部署架构

Amazon Web Services&#xff08;AWS&#xff09;提供了一种简化的Kubernetes&#xff08;K8s&#xff09;部署架构&#xff0c;使得在云环境中管理和扩展容器化应用变得更加容易。这个架构的核心是AWS EKS&#xff08;Elastic Kubernetes Service&#xff09;&#xff0c;它是…

设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而使原本因接口不兼容而无法一起工作的类能够协同工作。这种设计模式在软件开发中非常有用&#xff0c;尤其是在需要集成…

MCU芯片是什么意思_有哪些作用?

MCU(Microcontroller Unit)芯片&#xff0c;即微控制单元&#xff0c;是一种集成了中央处理器(CPU)、存储器(ROM、RAM)以及各种外设接口(如输入输出引脚、定时器、串口等)的集成电路芯片。它通过超大规模集成电路技术&#xff0c;将具有数据处理能力的中央处理器、随机存储器、…

如何免费解锁 IPhone 网络

您是否担心 iPhone 上的网络锁定&#xff1f;如果您的 iPhone 被锁定到特定运营商&#xff0c;解锁它可以连接到不同的运营商。好吧&#xff0c;我们为您准备了一份指南。 iPhone运营商免费解锁将是小菜一碟。在我们的解锁运营商 iphone 免费指南中。我们为您提供了一份简介&am…

Spring Security(maven项目) 3.0.2.4版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

计算机的错误计算(二百)

摘要 用三个大模型计算 exp(123.456). 结果保留10位有效数字。三个大模型的输出均是错误的&#xff0c;虽然其中一个给出了正确的 Python代码。 例1. 计算 exp(123.456). 保留10位有效数字。 下面是与第一个大模型的对话。 以上为与一个大模型的对话。 下面是与另外一个大模…

Golang的缓存一致性策略

Golang的缓存一致性策略 一致性哈希算法 在Golang中&#xff0c;缓存一致性策略通常使用一致性哈希算法来实现。一致性哈希算法能够有效地解决缓存节点的动态扩容、缩容时数据重新分布的问题&#xff0c;同时能够保证数据访问的均衡性。 一致性哈希算法的核心思想是将节点的哈希…

.e01, ..., .e0n的分卷压缩包怎么解压

用BandiZip&#xff0c;这些分卷压缩中还有一个.exe的文件&#xff0c;这个不是可执行文件&#xff0c;是一个解压缩的开头。 安装好bandiZip后&#xff0c;右键这个.exe文件 点击打开就是开始解压了&#xff1a; 最后解压后是这些。然后一个个再次解压.

微机接口课设——基于Proteus和8086的打地鼠设计(8255、8253、8259)Proteus中Unknown 1-byte opcode / Unknown 2-byte opcode错误

原理图设计 汇编代码 ; I/O 端口地址定义 IOY0 EQU 0600H IOY1 EQU 0640H IOY2 EQU 0680HMY8255_A EQU IOY000H*2 ; 8255 A 口端口地址 MY8255_B EQU IOY001H*2 ; 8255 B 口端口地址 MY8255_C EQU IOY002H*2 ; 8255 C 口端口地址 MY8255_MODE EQU IOY003H*2 ; …

密码学精简版

密码学是数学上的一个分支&#xff0c;同时也是计算机安全方向上很重要的一个原理&#xff0c;设置密码的目的是保证信息的机密性、完整性和不可抵赖性&#xff0c;安全方向上另外的功能——可用性则无法保证。 密码的发展也已由来已久&#xff0c;最早的密码可追溯到罗马时期…

在 macOS 上,你可以使用系统自带的 终端(Terminal) 工具,通过 SSH 协议远程连接服务器

文章目录 1. 打开终端2. 使用 SSH 命令连接服务器3. 输入密码4. 连接成功5. 使用密钥登录&#xff08;可选&#xff09;6. 退出 SSH 连接7. 其他常用 SSH 选项8. 常见问题排查问题 1&#xff1a;连接超时问题 2&#xff1a;权限被拒绝&#xff08;Permission denied&#xff09…

【书籍连载】《软件测试架构实践与精准测试》| 有关软件测试模型的调查结果

各位软件领域的精英们&#xff0c;今天小编邀请你继续深入学习《软件测试架构实践与精准测试》。 《软件测试架构实践与精准测试》是作者李龙&#xff08;安畅检测首席技术专家&#xff09;基于软件测试“川模型”的著作。本书结合作者首次提出的软件测试新的模型“川模型”测试…

软件工程大作业——图书管理系统/图书个性化推荐与实现系统

目录 1 绪论 1.1研究背景 1.2研究现状 1.3研究内容 2 系统关键技术 2.1 Spring Boot框架 2.2 JAVA技术 2.3 MYSQL数据库 2.4 B/S结构 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2经济可行性 3.1.3操作可行性 3.2 系统性能分析 3.3 系统功能分析 3.4系统流程分析 3.4.1登…

“AI智慧教学系统:开启个性化教育新时代

大家好&#xff0c;我是老王&#xff0c;一个在产品圈摸爬滚打多年的资深产品经理。今天&#xff0c;我想和大家聊聊一个最近特别火的概念——AI智慧教学系统。这东西听起来好像很高大上&#xff0c;但其实和我们每个人都息息相关&#xff0c;因为它关系到我们下一代的教育。 一…

vue实现平滑滚动到目标标签页

平滑滚动 <div class"tabs" ref"tabList"><div class"tab" v-for"(item, index) in 10":key"index" click"clickTab(index)"><div class"inside" :class"tabIndex index ? ins…

防御式CSS是一种编写CSS的方法,旨

1.防御式CSS 防御式CSS是一种编写CSS的方法&#xff0c;旨在提高样式的健壮性和可维护性。以下是一些实现防御式CSS的关键策略&#xff1a; 避免使用!important 尽量避免使用!important&#xff0c;因为它会破坏CSS的优先级规则&#xff0c;导致样式难以调试和维护。 使用具…

Python实现接口签名调用

目录: 1、第三方接口签名调用2、调用结果 1、第三方接口签名调用 import json import requests import hashlib import time import hmac access_key xxxxxxxxxxxxxxx secret_key xxxxxxxxxxxxxxx # 应用信息 def _wps4_sig(method, url, date, body): print(body)if bod…

【Hackthebox 中英 Write-Up】Web Request | 分析 HTTP 请求和响应

欢迎来到我的writeup分享&#xff01;我希望大家不要只关注结果或答案&#xff0c;而是通过耐心阅读&#xff0c;尝试逆向工程理解背后的运作原理。在这里&#xff0c;你不仅能找到解题的思路&#xff0c;还能学到更多与Hack The Box等平台相关的技术和技巧&#xff0c;期待与你…

物联网控制期末复习

第3章 物联网控制系统的过程通道设计 3.1 模拟量输出通道 3.1.1单模拟量输出通道的构成 计算机控制系统的模拟量输出通道将计算机产生的数字控制信号转换为模拟信号&#xff08;电压或电流&#xff09;作用于执行机构&#xff0c;以实现对被控对象的控制。 多D/A结构&#…

探索Wiki:开源知识管理平台及其私有化部署

在如今的信息时代&#xff0c;企业和团队的知识管理变得愈发重要。如何有效地存储、整理、共享和协作&#xff0c;是提高团队效率和创新能力的关键因素之一。今天&#xff0c;我要为大家介绍一款非常有用的github上开源知识管理工具——Wiki&#xff0c;并分享它的私有化部署方…