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

@Validated注解详解,分组校验,嵌套校验,@Valid和@Validated 区别,Spring Boot @Validated技术栈 springboot2 3 3 RELEASEhiber validator 文末附项目源代码目录简述项目依赖全局异常处理类基础参数校验实体类控制类测试嵌套参数验证实体类控制类测试分组参数验证接口类实体类控制类测试 Valid 和 Validated 区别简述 Validation 是一套帮助我们继续对传输的参数进行数据校验的注解 通过配置 Validation 可以很轻松的完成对数据的约束

技术栈:

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.

所有参数注解含义

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

项目依赖

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 
   
     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[0]|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、参数校验通过:

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

2、参数校验不通过:

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

嵌套参数验证

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

实体类

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 
   
     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、参数验证通过:

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

2、参数验证不通过:

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

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

分组参数验证

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

接口类

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[0]|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、未分组校验通过:

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

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

@Validated注解详解,分组校验,嵌套校验,@Valid和@Validated 区别,Spring Boot @Validated
3、分组1参数校验通过

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

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

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

5、分组2参数校验通过

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

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

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

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

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

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

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

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

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

说明:同第7点相同操作

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

 @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://javaforall.net/204527.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午8:07
下一篇 2026年3月19日 下午8:07


相关推荐

  • java saxreader_JAVA解析XML,SAXReader无法使用

    java saxreader_JAVA解析XML,SAXReader无法使用写了段代码要解析 XML 文件 for intp 0 p 写了段代码要解析 XML 文件 for intp 0 p

    2026年3月16日
    1
  • Idea激活码最新教程2024.1版本,永久有效激活码,亲测可用,记得收藏

    Idea激活码最新教程2024.1版本,永久有效激活码,亲测可用,记得收藏Idea 激活码教程永久有效 2024 1 激活码教程 Windows 版永久激活 持续更新 Idea 激活码 2024 1 成功激活

    2025年5月27日
    6
  • c++ listnode 赋值_C++之ListNode结构

    c++ listnode 赋值_C++之ListNode结构自己保存一下 建立链表的程序 省的以后每次建立链表的时候 还需要重新在写 通过下面的代码 建立的链表节点数为 10 每个节点保存的数为其下标即 0 9 这里要注意一点 在 voidcreateLi ListNode amp pHead 的时候 用的是指针引用 因为在 main 中 head 并没有开辟空间 如果在 createList 中为 pHead 开辟空间的时候 main 中的 head 依旧还是指向 NULL

    2026年3月17日
    2
  • 使用MYccl特征定位

    使用MYccl特征定位nbsp nbsp MYCLL 是一款特征定位工具 选择一个文件后 设置一下块 然后就可以进行特征定位 第一次处理后 使用杀毒软件杀 然后再次使用二次处理进行复合特征定位 nbsp nbsp 完了以后一般都能定位出特征码出来 然后估计就是修改其特征码 达到免杀的目的

    2026年3月18日
    2
  • file write error怎么解决_error attempt to read or write

    file write error怎么解决_error attempt to read or write做64位程序dll注入时候出现 WriteProcessMemory的299错误,查找错误代码解释为“仅完成部分的ReadProcessMemory或WriteProcessMemory请求。”完全搞不清楚怎么回事,因为调用了两次 WriteProcessMemory,第一次正常,第二次调用出错, 最后发现 release模式不会出错,然后对比,发现关闭“启动增量连接” 可

    2025年11月4日
    7
  • 使用RadControls的RadMenu控件开发系统菜单

    使用RadControls的RadMenu控件开发系统菜单关于菜单这个话题我想应该是不讲则懂,所以本文不会多讲这些概念,则重关注RadControls控件中的RadMenu控件的使用,结合数据库来开发一个系统菜单。一、数据库设计这里我就使用Access作为示例数据库,详细见下图:表字段依次为:自动编号、菜单编码、菜单名称、请求地址、菜单上显示的图片地址、快捷键(RadMenu控件支持)、菜单顺序、菜单级限、是否为末级和父菜单编码。整个设计中…

    2022年7月24日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号