优雅的使用Validated

article/2025/10/1 8:51:30

前言

@Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。
这个技术一直都想进行梳理了很多复杂校验不会使用,本章节用来进行梳理
validated 用于参数的校验,支持简单和复杂(分组/嵌套)校验

@Validated / @Valid 的区别

功能@validated 提供了分组能力而@Valid没有
位置@Valid作用于 方法\构造方法\方法参数\成员属性@Validdated作用于  类\方法\方法参数

注意事项

可能不生效的几个原因:1. @validate 默认将所有校验加入到了Default组中,如果指定了自定义组将不会校验Default组中的校验,如果需要校验默认组需要加上Default组,面对复杂的校验很有可能会搞混2. 如果需要使用分组,那么定义分组类型需要是接口类型,否则会报错~~3. 如果使用了正则校验查看 正则是否正确

注解

在这里插入图片描述

逻辑图

Validatad 工作机制描述
调用者发送请求后端 -> Validatad拦截器将请求体进行拦截后校验 -> 校验成功 -> 通过-> 校验失败 -> 抛出异常  -> 对异常进行处理(通过@RestControllerAdvice + @ExceptionHandler 注解进行异常处理)

在这里插入图片描述

依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

校验

目前有关于商品的接口需要进行校验

异常的处理

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.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;@RestControllerAdvice
public class MyControllerAdvice {@ExceptionHandler(MethodArgumentNotValidException.class)public String 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;stringBuilder.append(fieldError.getDefaultMessage());});}}return stringBuilder.toString();}
}

简单校验

目前商品添加了一个新增接口需要进行校验
校验内容:商品的名称不能为空
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;@Data
@Accessors(chain = true)
public class MyTestDTO {@NotEmpty(message = "产品名称不能为空")private String product;
}
@RestController
@RequestMapping("api")
public class MyController {@PostMapping("addProduct")public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {return myTestDTO;}
}

在这里插入图片描述

分组校验

分组: 如果在Controller中设置了分组,那么校验的时候只会走对应的分组拦截器,默认没有分组的校验都在javax.validation.groups.Default.class组中目前关于商品又增加了一个删除的接口原限制不变新增接口:产品名称不能为空修改接口:产品名称长度不能超过10位
//定义分组接口
public interface Group1 { //新增商品的分组
}
public interface Group2 { //修改商品的分组
}
import com.chen.advice.Group1;
import com.chen.advice.Group2;
import com.chen.pojo.MyTestDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("api")
public class MyController {@PostMapping("addProduct")public MyTestDTO addProduct(@RequestBody @Validated(Group1.class) MyTestDTO myTestDTO) {return myTestDTO;}@PutMapping("putProduct")public MyTestDTO putProduct(@RequestBody @Validated(Group2.class) MyTestDTO myTestDTO) {return myTestDTO;}}
import com.chen.advice.Group1;
import com.chen.advice.Group2;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;@Data
@Accessors(chain = true)
public class MyTestDTO {@NotEmpty(message = "产品名称不能为空",groups = Group1.class)@Size(max = 10,message = "产品名称长度不能超过10位",groups = Group2.class)private String product;
}

在这里插入图片描述
在这里插入图片描述

嵌套校验

	注意事项:嵌套校验:  对象中的对象属性需要加上@valid的注解
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;@Data
@Accessors(chain = true)
public class MyTestDTO {@Size(max = 10,message = "产品名称长度不能超过10位")private String product;@Valid@NotNull(message = "医疗实体类不能为null")private YiLiaoDTO yiLiaoDTO;
}
import lombok.Data;
import javax.validation.constraints.Positive;@Data
public class YiLiaoDTO {@Positive(message = "产品数量必须为正整数")private Integer count;}
import com.chen.pojo.MyTestDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("api")
public class MyController {@PostMapping("addProduct")public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {return myTestDTO;}
}

在这里插入图片描述

注解的尝试

自定义注解校验

注解类 -- 模仿自带的注解类进行编写
@Constraint(validateBy = 指定配置类)
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyValidCheck.class)
public @interface MyValid {int min() default  0;String message() default "{javax.validation.constraints.Size.message}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
配置类
initalize() 初始化方法用于获取注解设置的值
isValid() 判断是否通过校验
import com.example.demo.annotation.MyValid;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class MyValidCheck implements ConstraintValidator<MyValid,Object> {int min ;@Overridepublic void initialize(MyValid constraintAnnotation) {min = constraintAnnotation.min();}@Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {if (o != null && o.toString().length() <= min) {return true;}return false;}
}
Controller类
@RestController
@RequestMapping("api")
public class MyController {@PostMapping("addProduct")public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {return myTestDTO;}
}
import com.example.demo.annotation.MyValid;
import lombok.Data;@Data
public class MyTestDTO {private String id;private String product;@MyValid(min =  10,message = "你小子不按规则走呀,输入10位以内")private Integer size;
}

正则校验

@Pattern(regexp = "^[A-Za-z0-9]+$",message = "不符合正则规定了哦小伙子")
private String name;

特殊校验

校验List<对象>

// 自行封装一个 List 没有经过尝试
@***Mapping("/**")
public *** apiName(@RequestBody @Validated(Add.class) ValidList<Bean> aObject)
package com.analog.greatbolderserver.config.valid;import lombok.Data;
import lombok.NoArgsConstructor;import javax.validation.Valid;
import java.util.*;/*** @ClassName ValidList* @Description ValidList* @Author TY* @Date 2020/8/26 16:05* @Version 1.0**/
@Data
@NoArgsConstructor
public class ValidList<E> implements List<E> {@Validprivate List<E> list = new LinkedList<>();public ValidList(List<E> paramList) {this.list = paramList;}@Overridepublic int size() {return list.size();}@Overridepublic boolean isEmpty() {return list.isEmpty();}@Overridepublic boolean contains(Object o) {return list.contains(0);}@Overridepublic Iterator<E> iterator() {return list.iterator();}@Overridepublic Object[] toArray() {return list.toArray();}@Overridepublic <T> T[] toArray(T[] a) {return list.toArray(a);}@Overridepublic boolean add(E e) {return list.add(e);}@Overridepublic boolean remove(Object o) {return list.remove(o);}@Overridepublic boolean containsAll(Collection<?> c) {return list.containsAll(c);}@Overridepublic boolean addAll(Collection<? extends E> c) {return list.addAll(c);}@Overridepublic boolean addAll(int index, Collection<? extends E> c) {return list.addAll(index, c);}@Overridepublic boolean removeAll(Collection<?> c) {return list.removeAll(c);}@Overridepublic boolean retainAll(Collection<?> c) {return list.retainAll(c);}@Overridepublic void clear() {list.clear();}@Overridepublic E get(int index) {return list.get(index);}@Overridepublic E set(int index, E element) {return list.set(index, element);}@Overridepublic void add(int index, E element) {list.add(index, element);}@Overridepublic E remove(int index) {return list.remove(index);}@Overridepublic int indexOf(Object o) {return list.indexOf(o);}@Overridepublic int lastIndexOf(Object o) {return list.lastIndexOf(o);}@Overridepublic ListIterator<E> listIterator() {return list.listIterator();}@Overridepublic ListIterator<E> listIterator(int index) {return list.listIterator(index);}@Overridepublic List<E> subList(int fromIndex, int toIndex) {return list.subList(fromIndex, toIndex);}
}

http://chatgpt.dhexx.cn/article/vC00YLid.shtml

相关文章

@Valid与@Validated区别

1.Valid与Validated作用 Valid与Validated都是用来校验接收参数的。Valid是使用Hibernate validation的时候使用Validated是只用Spring Validator校验机制使用说明&#xff1a;java的JSR303声明了Valid这类接口&#xff0c;而Hibernate-validator对其进行了实现。Validated与V…

java中换行符_Java 中的空格符、换行符等怎么表示

展开全部 特殊字符的自表示方法&#xff1a;&#xff1a; 1、\t 空格2113 (\u0009) 2、\n 换行 (\u000A) 3、\\ 反斜杠5261 4、\r 回车 (\u000D) 5、\d 数字4102等价1653于[0-9] 6、\D 非数字等价于[^0-9] 7、\s 空白符号 [\t\n\x0B\f\r] 8、\S 非空白符号 [^\t\n\x0B\f\r] 9、…

java通用文件换行符_java通用文件换行符

java通用文件换行符 [2021-02-07 00:14:46] 简介: java中的换行符是【\n】和【\r】。二者的区别是:【\r】表示回车,【\n】表示新行,但两者都可以实现换行。具体实现方法如:【System.out.print("\n")】。在java中,可以使用\n和\r来 php如何去掉换行符 2020-09-0…

java 处理换行符_Java 文件换行符识别与转换

项目经验,如需转载,请注明作者:Yuloran (t.cn/EGU6c76) 背景 项目开发需要手动合入几十种语言的翻译到 string.xml 中,这是一件非常痛苦的事情:Copy、Paste,Copy、Paste,Copy、Paste... 人都快疯了!被逼无奈写了个自动替换翻译的工具,原理很简单:解析 Excel中的翻译,…

java回车换行符linux,回车换行符 java

回车换行符 java [2021-01-31 11:28:50] 简介: java中的换行符是【\n】和【\r】。二者的区别是:【\r】表示回车,【\n】表示新行,但两者都可以实现换行。具体实现方法如:【System.out.print("\n")】。在java中,可以使用\n和\r来 php如何去掉换行符 2020-09-02 p…

java 分行符_java换行符有哪些

在java中可以使用的换行符有&#xff1a;"\n"表示新行、“\r”表示回车&#xff0c;\r \n”。 在java中需要在字符串(文本)末尾包含换行符"\n"&#xff0c;“\r”或者“\r \n”就可以进行换行。 换行符"\n" "\n"也称换行&#xff0c;一…

java换行符如何使用

java换行符的使用方法&#xff1a;1、换一行【System.out.print(" “)】&#xff1b;2、换两行【System.out.println(” “)】&#xff1b;3、换三行【System.out.println(” " )】。 java换行符的使用方法&#xff1a; 可以使用Java中 和 的换行&#xff0c;不过也…

java:换行符“\n”

换行符 一、关键代码二、简单说明三、源码&#xff08;一&#xff09;、源码A&#xff08;二&#xff09;、源码A的运行效果 四、结语五、定位日期 一、关键代码 java的换行符 "\n" 两次换行&#xff08;相当于摁两次回车键的效果&#xff09; System.out.println(&…

关于ping命令出现大量dup原因

(DUP!) 这个东西是DUPLICATE的一个缩写&#xff0c;也就是ping包的时候收到多个重复值回应&#xff0c;通常发生在linux环境下比较多&#xff0c;windows环境对ping的reply只接到第一个&#xff0c;后续的重复回应会被废弃。 发生这种情况通常是主宿机的IP冲突&#xff0c;或者…

c语言 字符串dup,C语言中dup和dup2函数的不同和使用

在unix高级编程中有介绍dup和dup2&#xff0c;但是没有实例说明&#xff0c; 笔者自己结合实例进行了测试了解。 在linux下&#xff0c;通过open打开以文件后&#xff0c;会返回一个文件描述符&#xff0c;文件描述符会指向一个文件表&#xff0c;文件表中的节点指针会指向节点…

汇编语言之 DUP 套 DUP

题目&#xff1a;下列变量各占多少字节。 A1 DW 23H, 5876H A2 DB 3 DUP(?), 0AH, 0DH, $ A3 DW 4 DUP(3 DUP(1, 2, AB)) 为了更直观地进行观察&#xff0c;我们编写如下程序。 DSEG SEGMENTA1 DW 23H, 5876HA2 DB 3 DUP(?), 0AH, 0DH, $A3 DW 4 DUP(3 DUP(1, 2, AB)) DSE…

函数dup和dup2

这两个函数包含在#include<unistd.h>之中。他们都是用来复制一个现有的文件描述符。 函数原型 函数功能&#xff1a;若成功返回新的文件描述符&#xff0c;否则返回-1&#xff0c;并且dup返回的文件描述符一定是当前可用文件描述符中最小的。 dup2可以用newfd指定新描述…

dup2使用

头文件&#xff1a; 参数&#xff1a; dup2是帮助我们进行重定向的系统调用接口 使用方法&#xff1a;把fd_arrays[oldfd]拷贝到fd_arrays[newfd]&#xff0c;实现重定向 原理&#xff1a; 要会使用dup2&#xff0c;要先了解文件描述符fd 文件描述符 下面这段代码就是不调用…

重定向dup和dup2

dup和dup2 返回值是int的文件描述符&#xff0c;参数是已有的文件描述符 此时打印的文件描述符为4&#xff0c;使用这个文件描述符可以访问打开的文件&#xff0c;可以通过这个往新的文件描述符写&#xff0c;主只需把打开方式改成可读可写即可。 dup2&#xff1a; 注意两个指针…

dup dup2 fcntl函数

dup函数 dup函数&#xff1a;用来复制文件描述符 函数原型&#xff1a; int dup(int oldfd);//oldfd为要复制的文件描述符 成功返回最小且没被占用的文件描述符,失败返回-1 dup函数复制的文件描述符与原文件描述符指向同一个文件 //测试dup函数复制文件描述符 #include <std…

【Linux】dup、dup2函数

目录 dup函数dup2函数 橙色 dup函数 int dup(int oldfd); //复制文件描述符 /*#include <unistd.h>int dup(int oldfd);作用&#xff1a;复制一个新的文件描述符fd3, int fd1 dup(fd),fd指向的是a.txt, fd1也是指向a.txt从空闲的文件描述符表中找一个最小的&#xff…

dup、dup2介绍

dup和dup2也是两个非常有用的调用&#xff0c;它们的作用都是用来复制一个文件的描述符。它们经常用来重定向进程的stdin、stdout和stderr。这两个函数的 原形如下&#xff1a;#include <unistd.h> int dup( int oldfd ); int dup2( int oldfd, int targetfd ) …

Linux应用编程之dup函数和dup2函数

在 Linux 系统中&#xff0c; open 返回得到的文件描述符 fd 可以进行复制&#xff0c;复制成功之后可以得到一个新文件描述符&#xff0c;使用新的文件描述符和旧的文件描述符都可以对文件进行 IO 操作&#xff0c;复制得到的文件描述符和旧的文件描述符拥有相同的权限&…

linux文件重定向 dup,linux之dup和dup2函数解析

linux之dup和dup2函数解析 linux之dup和dup2函数解析 系统调用dup和dup2能够复制文件描述符。dup返回新的文件文件描述符(没有用的文件描述符最小的编号)。dup2可以让用户指定返回的文件描述符的值&#xff0c;如果需要&#xff0c;则首先接近newfd的值&#xff0c;他通常用来重…

dup和dup2函数

dup和dup2函数 dup和dup2用于复制文件描述符&#xff0c;通常用于重定向。 #include <unistd.h>int dup(int oldfd); int dup2(int oldfd, int newfd);dup函数创建一个新的文件描述符&#xff0c;该新文件描述符和原有文件描述符oldfd指向相同的文件、管道或者网络连接…