@Validated注解详解,分组校验,嵌套校验,@Valid和@Validated 区别,Spring Boot @Validated

别再混淆了!一文带你搞懂@Valid和@Validated的区别 本文介绍了@Valid注解和@Validated注解的不同,同时也进一步介绍了Springboot 参数校验的使用。 阅读详情

技术栈:

spring boot 2.3.3.RELEASE

hibernate-validator

文末附项目源代码

@Valid和@Validated 区别
简述

@Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。

@Validated作用在类、方法和参数上

    @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Validated {
        Class<?>[] value() default {};
    }

错误的状态码

返回的响应码推荐使用400 bad request.

所有参数注解含义

项目依赖

Maven 依赖坐标:

说明:在演示项目中所有实体类均在包entity,控制层均在包controller。
全局异常处理类

说明:若不做异常处理,@Validated注解的默认异常消息如下(示例):

2020-09-05 21:48:38.106 WARN 9796 — [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.validateddemo.controller.DemoController.validatedDemo1(com.example.validateddemo.entity.dto.UseDto): [Field error in object ‘useDto’ on field ‘username’: rejected value [null]; codes [NotBlank.useDto.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [useDto.username,username]; arguments []; default message [username]]; default message [用户名不能为空!]] ]

因此我们在这里做了一个全局的异常处理类,用于处理参数校验失败后抛出的异常,同时进行日志输出。

package com.example.validateddemo.handler;
 
import com.example.validateddemo.base.Result;
import com.example.validateddemo.enums.ResultEnum;
import com.example.validateddemo.utils.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
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.ResponseStatus;
import java.util.List;
 
/**
 * @author He Changjie on 2020/9/5
 */
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {
 
    /**
     * 处理@Validated参数校验失败异常
     * @param exception 异常类
     * @return 响应
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result exceptionHandler(MethodArgumentNotValidException exception){
        BindingResult result = exception.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    log.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]",fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
                    stringBuilder.append(fieldError.getDefaultMessage());
                });
            }
        }
        return ResultUtil.validatedException(stringBuilder.toString());
    }
}

基础参数校验
实体类

package com.example.validateddemo.entity.dto;
 
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
 
import javax.validation.constraints.*;
 
/**
 * 用户实体
 * 数据传输对象
 * @author He Changjie on 2020/9/5
 */
@Data
public class User1Dto {
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空!")
    private String username;
    /**
     * 性别
     */
    @NotBlank(message = "性别不能为空!")
    private String gender;
    /**
     * 年龄
     */
    @Min(value = 1, message = "年龄有误!")
    @Max(value = 120, message = "年龄有误!")
    private int age;
    /**
     * 地址
     */
    @NotBlank(message = "地址不能为空!")
    private String address;
    /**
     * 邮箱
     */
    @Email(message = "邮箱有误!")
    private String email;
    /**
     * 手机号码
     */
    @Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!")
    private String mobile;
}

控制类

package com.example.validateddemo.controller;
 
import com.example.validateddemo.entity.dto.Use1Dto;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author He Changjie on 2020/9/5
 */
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
 
    @PostMapping("/insert")
    public String validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
        System.out.println(use1Dto);
        return "success";
    }
}

测试

1、参数校验通过:

2、参数校验不通过:

嵌套参数验证

验证实体中的其他需要被验证的对象集合或其他对象
实体类

package com.example.validateddemo.entity.dto;
 
import lombok.Data;
 
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
 
/**
 * 队伍实体
 * 数据传输对象
 * @author He Changjie on 2020/9/5
 */
@Data
public class Team1Dto {
    /**
     * 队伍名称
     */
    @NotBlank(message = "队伍名称不能为空!")
    private String name;
    /**
     * 队伍人员
     */
    @NotNull(message = "队伍人员不能为空!")
    @Valid
    private List<User1Dto> userList;
 
    /**
     * 队伍负责人
     */
    @NotNull(message = "队伍负责人不能为空!")
    @Valid
    private User1Dto user;
}

控制类

package com.example.validateddemo.controller;
 
import com.example.validateddemo.base.Result;
import com.example.validateddemo.entity.dto.Team1Dto;
import com.example.validateddemo.entity.dto.Use1Dto;
import com.example.validateddemo.utils.ResultUtil;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author He Changjie on 2020/9/5
 */
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
 
    @PostMapping("/insert")
    public Result validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
        return ResultUtil.success(use1Dto);
    }
 
    @PostMapping("/insert2")
    public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
        return ResultUtil.success(team1Dto);
    }
}

测试

1、参数验证通过:

2、参数验证不通过:

分组参数验证

将不同的校验规则分给不同的组,在使用时,指定不同的校验规则
接口类

package com.example.validateddemo.interfaces;
 
/**
 * 校验分组1
 * @author He Changjie on 2020/9/5
 */
public interface Group1 {
}



package com.example.validateddemo.interfaces;
 
/**
 * 校验分组2
 * @author He Changjie on 2020/9/5
 */
public interface Group2 {
}

实体类

package com.example.validateddemo.entity.dto;
 
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import lombok.Data;
 
import javax.validation.constraints.*;
 
/**
 * @author He Changjie on 2020/9/5
 */
@Data
public class User2Dto {
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空!", groups = {Group1.class})
    private String username;
    /**
     * 性别
     */
    @NotBlank(message = "性别不能为空!")
    private String gender;
    /**
     * 年龄
     */
    @Min(value = 1, message = "年龄有误!", groups = {Group1.class})
    @Max(value = 120, message = "年龄有误!", groups = {Group2.class})
    private int age;
    /**
     * 地址
     */
    @NotBlank(message = "地址不能为空!")
    private String address;
    /**
     * 邮箱
     */
    @Email(message = "邮箱有误!", groups = {Group2.class})
    private String email;
    /**
     * 手机号码
     */
    @Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!", groups = {Group2.class})
    private String mobile;
}

控制类

package com.example.validateddemo.controller;
 
import com.example.validateddemo.base.Result;
import com.example.validateddemo.entity.dto.Team1Dto;
import com.example.validateddemo.entity.dto.User1Dto;
import com.example.validateddemo.entity.dto.User2Dto;
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import com.example.validateddemo.utils.ResultUtil;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author He Changjie on 2020/9/5
 */
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
 
    @PostMapping("/insert")
    public Result validatedDemo1(@Validated @RequestBody User1Dto user1Dto){
        return ResultUtil.success(user1Dto);
    }
 
    @PostMapping("/insert2")
    public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
        return ResultUtil.success(team1Dto);
    }
 
    @PostMapping("/insert3")
    public Result validatedDemo3(@Validated @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
 
    @PostMapping("/insert4")
    public Result validatedDemo4(@Validated(Group1.class) @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
 
    @PostMapping("/insert5")
    public Result validatedDemo5(@Validated(Group2.class) @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
}

测试

1、未分组校验通过:

2、未分组参数校验不通过:

3、分组1参数校验通过

4、分组1参数校验不通过

5、分组2参数校验通过

6、分组2参数校验不通过

7、使用默认分组,参数校验通过:

说明:将控制层/insert3接口调整如下后测试

@PostMapping("/insert3")
    public Result validatedDemo3(@Validated(Default.class) @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }

Default.class为Validated依赖中含有的接口类,非自定义接口类

8、使用默认分组,参数校验不通过:

说明:同第7点相同操作

@Valid和@Validated 区别

通过源码分析:

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Valid {
}

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
    Class<?>[] value() default {};
}

@Valid:没有分组的功能。

@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上

@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制

@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上

两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能

码云地址:https://gitee.com/jie_harris/validateddemo.git

原文链接: https://blog.youkuaiyun.com/qq_32352777/article/details/108424932

Spring 中@Validated 分组校验使用 Spring注解之@validated的使用 通过本文你能学习到@Validated 的基本使用,以及如何再spring-boot 中进行数据异常的统一处理 Spring Validation验证框架对参数的验证机制提供了@Validated(Spring’s JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。 在检验入参是否符合规范时,使用@Validated或者@Valid在基本验证 阅读详情

相关推荐

【AutoDL】使用云服务器跑深度学习代码

1.算力市场 租用服务器,选择自己心仪的服务器2.镜像可以选择一些基础的镜像,社区镜像里是git上有的环境。3.上传文件在文件存储中,选择上传的区,在右边点击上传,选择自己的文件上传到云服务器中。

weixin_45768644的博客 3701

Java代码瘦身,巧用 @Valid,@Validated 的分组校验和嵌套检验,实现高阶参数校验操作

使用@Valid,@Validated,不仅可以减轻代码量,还加强了代码的易读性,避免if...else...操作。

Java Punk 1万+

深入解析mSATA与mini-PCIE接口的硬件设计要点

本文深入解析mSATA与mini-PCIE接口的硬件设计要点,涵盖信号定义、电源设计、高速信号处理及PCB布局布线等关键内容。通过实战案例和调试技巧,帮助工程师规避常见设计陷阱,提升电路设计效率,特别适合工业控制和嵌入式系统开发场景。

weixin_28741413的博客 315

validate分组校验

自己新建接口,继承Default和不继承Default,区别就是继承Default的分组就是使用当前分组的时候,默认分组下的校验都会生效,如@NotNull@NotBlank类似这种。在上面的例子中account属性的校验就是属于UpdateElement组的校验,而password属于Default分组的校验,什么时候校验,报什么错误信息呢,这是在与前后端交互的VO中,在属性上标注哪个组的校验规格是什么。这个情况下,@Validated使用的是默认分组,这时候不会对account属性进行校验。...

mmdsl083的博客 2490

网站进行企业微信授权登录(附带代码超详细版)

企业微信的扫码登录官方文档 https://work.weixin.qq.com/api/doc/90000/90135/90988 企业微信扫码登录认证流程 上面是官方的图片,看上去比较复杂。因此我用直白简洁的语言梳理下流程。 1、首先在自己的网站上获取到企业微信登录的二维码(二维码怎么获取稍后再说,这里想象下你已经有了一个二维码) 2、你拿着手机扫描二维码,确认登录之后,页面就会自己进行重定向的跳转,跳转的url如何配置下面再讲,但是注意,这个重定向的url可以是内网地址 3、重定向到指

Gzf的博客 1万+

CANoe LIN一致性测试之干扰测试Test moudle_LIN Disturbance Block

注意:相邻两个显隐性不同的bit不允许干扰,例如我同时选择bit6和bit7,相邻两个同显隐性的bit允许干扰,例如当我选择bit3和bit4,项,这里我选择ID:为0x2F(PID:0x6F)的frame。需按照具体测试规范实施干扰项,帧头和数据段都可以实现干扰。最近发现一个干扰测试模块,下面是一些具体使用方法。选择干扰项:PID的奇偶校验位(一致性测试干扰测试之手动测试。一个待测试frameD。

yuanyikangkang的博客 3410

Spring Boot中@Valid 与 @Validated 注解的详解

Valid是Java EE提供的标准注解,它是JSR 303规范的一部分,主要用于Hibernate Validation等场景。在Spring Boot中,@Valid注解用于触发参数校验,确保请求参数的合法性。@Validated是Spring框架特有的注解,属于Spring的一部分,也是JSR 303的一个变种。它提供了一些@Valid所没有的额外功能,比如分组验证。@Validated注解可以用在类、方法和方法参数上,但不能用于成员属性。

yang_love1011的博客 1877

《网络安全自学教程》- Nmap使用及扫描原理分析

使用Nmap进行端口扫描、主机发现、服务识别、操作系统识别、指定脚本、结果导出文件,使用wireshark抓包分析扫描原理。

wangyuxiang946的博客 1万+

@Validated注解和@Valid注解区别

@Validated注解和@Valid注解详解引入依赖@Validated注解和@Valid注解区别@Valid注解使用场景演示嵌套校验和controller层请求参数校验@Valid注解校验不通过会抛出MethodArgumentNotValidException异常@Valid注解的请求参数后面紧跟一个BindingResult对象,来封装校验结果全局处理异常MethodArgumentNotValidException@Validated使用场景演示controller请求参数校验对配置文件的装配进行

m0_53157173的博客 6161

【深度学习新浪潮】近三年垂域大模型研究与产品进展全景洞察(2022-2025)

近三年来,垂域大模型完成了从技术探索到产业落地的关键跨越,在多个行业实现效率提升与价值创造。面对数据治理、技术适配、生态建设等挑战,未来需要通过技术创新、标准制定、人才培养等多维度发力,推动垂域大模型向更高效、更可靠、更普惠的方向发展。随着"人工智能+"行动的深入推进,垂域大模型将成为数字经济与实体经济深度融合的核心驱动力,为产业智能化升级注入持续动能。

专注:太空算力、AI infra、异构调度、大模型成本工程 786

<IBM AIX> 《HACMP 实用手册和命令 HA切换手册》 - 鸿篇巨制,全网最全

操作命令检查磁盘预留策略要将磁盘预留策略更改为 no_reserve集群状态实用程序查看集群状态是否正常SMIT System Management (C-SPOC)Cluster ServicesShow Cluster Services 面板上的选项或 lssrc 命令查看资源组、资源组对应的VG、资源组对应的APPLICATION SERVER# ./cldispsmit常用命令F3退出F4列表Esc+6或者F6查看命令Esc+7或者F7选择多项检查状态。

Else 的博客 3361
上一篇: git Failed to connect to 127.0.0.1 port xxxx: Connection refused
下一篇: Java8 Stream流递归, 遍历树形结构
Chery Qi
博客等级 码龄10年 154粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值