news 2026/10/14 3:32:34

13 Validation校验在springboot中使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
13 Validation校验在springboot中使用

1 引入依赖

Spring Boot 3.x 也使用这个 starter,但包名迁移到了 jakarta.validation。

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

2 在 DTO 上加注解

publicclassUserDTO{@NotBlank(message="用户名不能为空")privateStringusername;@Email(message="邮箱格式不正确")privateStringemail;@NotNull(message="年龄不能为空")@Min(value=0,message="年龄不能小于0")privateIntegerage;}

3 @Valid触发默认校验

@PostMapping("/users")publicResultaddUser(@Valid@RequestBodyUserDTOuser){returnResult.success("添加成功");}

4 @Validated触发分组校验

4.1 定义分组接口

publicinterfaceAddGroup{}publicinterfaceUpdateGroup{}

4.2 在 DTO 上用 groups 指定分组

注意:

  • 没写 groups 的注解,属于 默认分组 Default.class。
  • 如果写了 groups,它只属于指定分组,默认分组不会触发。
publicclassUserDTO{// 新增和修改都需要 id@NotNull(message="id不能为空",groups={UpdateGroup.class})privateLongid;@NotBlank(message="用户名不能为空",groups={AddGroup.class,UpdateGroup.class})privateStringusername;@Email(message="邮箱格式不正确",groups={AddGroup.class})privateStringemail;@NotNull(message="年龄不能为空",groups={AddGroup.class,UpdateGroup.class})@Min(value=0,message="年龄不能小于0",groups={AddGroup.class,UpdateGroup.class})privateIntegerage;}

4.3 方法参数上用 groups 指定分组

@PostMapping("/add")publicRadd(@Validated(AddGroup.class)@RequestBodyOrderDTOorder){...}

5 @Valid和@Validated区别

参考文章:别再混淆了!一文带你搞懂@Valid和@Validated的区别

维度@Valid@Validated
来源JSR 303/380 标准,javax.validation/jakarta.validationSpring 扩展,org.springframework.validation.annotation
分组校验❌ 不支持✅ 支持,@Validated(AddGroup.class)
嵌套校验✅ 支持,可标在字段上触发子对象校验❌ 不支持,不能标在字段上
可用位置方法参数、成员变量(递归校验)、构造函数参数方法参数、方法、类 (开启该类校验)
校验失败异常MethodArgumentNotValidExceptionMethodArgumentNotValidException(Controller 参数);ConstraintViolationException(Service 层 AOP)

5.1 类上的 @Validated:开启方法级校验

下面情况 类上不用添加@Validated开启方法校验,默认触发校验。

场景情况
@RequestBody对象参数@Valid @RequestBody会触发 DTO 内部校验
@ModelAttribute/ 表单绑定对象表单提交、查询参数绑定到对象时,@Valid也能触发校验
@RequestParam、@PathVariable、Service 方法参数这些不是@RequestBody,@Valid放在参数上通常不会自动生效;需要类上加@Validated走方法级校验

下面情况 类上必须加@Validated开启方法校验,否则@NotBlank校验不生效

@RestController@RequestMapping("/brand")@Validated// 关键:类上必须加 @ValidatedpublicclassBrandController{/** * 按品牌名称查询 */@GetMapping("/search")publicRsearch(@RequestParam("name")@NotBlank(message="品牌名称不能为空")Stringname){returnR.ok();}}

5.2 方法参数上的@Valid/@Validated:分组与嵌套

@Validated可以实现分组校验,@Valid无此功能。 @Valid可以实现嵌套校验,@Validated不能触发。

public R save(@Valid @RequestBody BrandEntity brand)
public R save(@Validated(AddGroup.class) @RequestBody BrandEntity brand)

嵌套校验举例

publicclassBrandEntity{privateStringname;// 嵌套对象privateAddressEntityaddress;}
  1. 如果你用 @Valid:Spring 不仅会校验 BrandEntity 的 name,还会自动进入 AddressEntity 里面,去校验它的字段。
  2. 如果你用@Validated不会进入 AddressEntity 里面。
  3. 如果想要同时实现分组校验和嵌套校验,@Validated修饰方法参数并在AddressEntity嵌套对象上添加@Valid。

5.3 成员变量上的@Valid:嵌套

@Valid private Address address;,这是它和 @Validated 的关键区别之一
开启嵌套校验

publicclassUserDTO{@NotBlank(message="姓名不能为空")privateStringname;@NotNull(message="地址不能为空")@Valid// 加上 @Valid:会递归校验嵌套对象privateAddressDTOaddress;}

所以@Validated修饰的方法参数内部,可以在成员private AddressDTO address上添加@Valid,实现分组校验和嵌套校验。

6 异常处理

6.1全局异常处理

参考文章:SpringBoot 使用Spring Validation实现接口参数校验
全局异常处理类只需要在类上标注@RestControllerAdvice,并在处理相应异常的方法上使用@ExceptionHandler注解,写明处理哪个异常即可。

  1. @RestControllerAdvice本质上是@Component,可以注入全局异常处理bean。配置basePackages参数,处理指定包下抛出的异常。如果不指定,则会处理所有的@Controller标注的类抛出的异常。
  2. @ExceptionHandler 标注异常处理方法,其value标注要处理的异常类型,一般配置一个value = Exception.class处理其他未配置异常类型
@RestControllerAdvice(basePackages="com.atguigu.gulimall.product.controller")publicclassGulimallExceptionControllerAdvice{@ExceptionHandler(value=MethodArgumentNotValidException.class)publicRhandleValidException(MethodArgumentNotValidExceptione){BindingResultbindingResult=e.getBindingResult();HashMap<String,String>erroMap=newHashMap<>();bindingResult.getFieldErrors().forEach((fieldError->{erroMap.put(fieldError.getField(),fieldError.getDefaultMessage());}));returnR.error(BizCodeEnume.VALID_EXCEPTION.getCode(),BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data",erroMap);}@ExceptionHandler(value=Exception.class)publicRhandleException(Exceptionexception){returnR.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());}}

6.2 BingResult

BindingResult 是 Spring MVC 里用来接收参数校验结果的对象。校验失败时,它会把错误信息存起来,而不会直接抛异常。
它必须紧跟在被 @Valid 或 @Validated 标注的参数后面

@PostMapping("/user")publicStringcreateUser(@Valid@RequestBodyUseruser,BindingResultresult){if(result.hasErrors()){Stringmsg=result.getFieldErrors().stream().map(e->e.getField()+": "+e.getDefaultMessage()).collect(Collectors.joining("; "));returnResult.fail(400,msg);}...}
方法作用
hasErrors()是否有校验错误
hasFieldErrors()是否有字段级别的错误
getFieldErrors()获取所有字段错误列表
getFieldError("name")获取指定字段的第一个错误
getAllErrors()获取所有错误(含全局错误)
getErrorCount()错误总数

7 自定义校验注解

7.1 自定义注解@Phone

@Documented@Constraint(validatedBy={PhoneValidator.class})@Target({ElementType.FIELD,ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public@interfacePhone{Stringmessage()default"手机号格式校验不正确";Class<?>[]groups()default{};Class<?extendsPayload>[]payload()default{};StringphoneReg()default"^1[3-9]\\d{9}$";}

@Constraint(validatedBy = PhoneValidator.class):指定7.2 注解校验处理方法PhoneValidator
这里三个属性是 Bean Validation 规范要求保留的:

属性作用
message()校验失败时的提示信息
groups()分组校验使用
payload()附加元数据,一般默认即可

7.2 注解校验处理方法

publicclassPhoneValidatorimplementsConstraintValidator<Phone,String>{privateStringregPhone;@Overridepublicvoidinitialize(PhoneconstraintAnnotation){//获取注解中phoneReg的值StringphoneReg=constraintAnnotation.phoneReg();this.regPhone=phoneReg;}@OverridepublicbooleanisValid(Stringvalue,ConstraintValidatorContextcontext){//value匹配正则表达式,返回是否符合//为空时交由其他校验(如@NotBlank)处理,此处直接视为通过if(value==null||value.isEmpty()){returntrue;}returnvalue.matches(this.regPhone);}}
  1. ConstraintValidator<A, T>的两个泛型含义是:
    A:自定义注解类型。
    T:被校验字段的数据类型。

  2. isValid(String value, ConstraintValidatorContext context)两个参数含义:
    value:当前正在被校验的那个值。
    context:校验上下文对象,用来控制“校验失败后怎么报错”。修改错误提示的message消息。

  3. isValid方法返回布尔类型,代表校验通过与否。

7.3 使用

· DTO层

@DatapublicclassPhoneDTO{@NotNull(message="姓名不能为空")privateStringname;@Phone(phoneReg="^15[3-9]\\d{8}$",message="请填写15开头的手机号码")privateStringphone;}

· Controller层

@RestController@RequestMapping("product/category")publicclassCategoryController{@RequestMapping("/test/phone")publicRtestPhone(@Valid@RequestBodyPhoneDTOphone,BindingResultbindingResult){StringerrorMessage=null;if(bindingResult.hasErrors()){errorMessage=bindingResult.getFieldErrors().get(0).getDefaultMessage();returnR.error(400,"参数错误").put("errors",errorMessage);}returnR.ok().put("page",errorMessage);}}

7.4 Http测试

POST http://localhost:10001/product/category/test/phone Content-Type: application/json { "name": "test", "phone": "1381234567" }

8 常见的Validation注解

8.1 空值校验

注解适用类型校验规则用例
@NotNull任意类型不能为null,但可以是空字符串、空集合@NotNull(message="id不能为空") private Long id;
@NotBlankString不能为null,且去除首尾空格后长度必须大于 0@NotBlank(message="用户名不能为空") private String username;
@NotEmptyString、集合、数组、Map不能为null,且长度/元素个数大于 0@NotEmpty(message="标签不能为空") private List<String> tags;

简单区分:
字符串必填优先用 @NotBlank;集合/数组必填用 @NotEmpty;非字符串对象、数字、日期用 @NotNull。

8.2 字符串格式与长度

注解适用类型校验规则用例
@Min数值类型必须 ≥ 指定值@Min(18) private Integer age;
@Max数值类型必须 ≤ 指定值@Max(120) private Integer age;
@DecimalMin数值类型、字符串数字必须 ≥ 指定值,适合金额、小数@DecimalMin("0.00") private BigDecimal price;
@DecimalMax数值类型、字符串数字必须 ≤ 指定值@DecimalMax("99999.99") private BigDecimal price;
@Positive数值类型必须大于 0@Positive private Integer count;
@PositiveOrZero数值类型必须 ≥ 0@PositiveOrZero private BigDecimal amount;
@Negative数值类型必须小于 0@Negative private Integer loss;
@NegativeOrZero数值类型必须 ≤ 0@NegativeOrZero private BigDecimal change;
@Digits数值类型限制整数位数和小数位数@Digits(integer=10, fraction=2) private BigDecimal amount;

8.3 日期时间校验

注解适用类型校验规则用例
@Past日期时间必须是过去时间@Past private LocalDate birthday;
@PastOrPresent日期时间必须是过去或当前时间@PastOrPresent private LocalDate startDate;
@Future日期时间必须是未来时间@Future private LocalDate expireDate;
@FutureOrPresent日期时间必须是未来或当前时间@FutureOrPresent private LocalDateTime endTime;

8.4 布尔校验

注解适用类型校验规则用例
@AssertTrueBoolean必须为true@AssertTrue private Boolean agreed;
@AssertFalseBoolean必须为false@AssertFalse private Boolean deleted;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:32:04

强化学习的动态规划

一、动态规划的介绍1、动态规划动态规划 (Dynamic programming, DP)是一类优化算法动态规划将待求解问题分解成若干子问题&#xff0c;先求解子问题&#xff0c;然后从这些 子问题的解得到目标问题的解。2、动态规划与强化学习的关系在完备的马尔可夫决策过程中&#xff0c;DP可…

作者头像 李华
网站建设 2026/10/14 3:31:51

移动端射击游戏性能优化实战:帧率、渲染与手感调优全攻略

做移动端射击游戏&#xff0c;和做PC/主机射击游戏完全不是一个物种。去年我们团队把《三角洲行动》移动端的帧率、内存、发热和手感反复打磨了大半年&#xff0c;期间踩了大量文档里根本找不到的坑。这篇文章不讲教科书式的架构&#xff0c;而是把真机调试、压测和上线前优化过…

作者头像 李华
网站建设 2026/10/14 3:31:49

Codex Skill 入门与实战:安装、调用和自建

整理时间&#xff1a;2026-10-12 核心标签&#xff1a;#Codex #AgentSkills #AI编程 #效率工具 资料来源 [S1] 视频&#xff1a;《Codex Skill 到底是什么&#xff1f;10分钟入门使用、安装、自建》&#xff0c;Bilibili。[S2] 官方文档&#xff1a;Build skills&#xff08;O…

作者头像 李华
网站建设 2026/10/14 3:31:06

airllm分层推理:低显存跑大模型的工程实践

1. 当显存告急时&#xff0c;我们还能不能跑大模型第一次在单卡24G显存上尝试加载一个70B参数级别的模型时&#xff0c;我盯着终端里那行红色的显存溢出报错看了很久。这不是什么罕见的场景——任何一个在消费级硬件上折腾过大模型推理的人&#xff0c;大概都经历过类似的时刻。…

作者头像 李华
网站建设 2026/10/14 3:31:04

3秒焦耳热合成Cu-N₃单原子催化剂,锌碘电池循环5万次

最近某高校团队发表了一项让我印象很深的工作&#xff1a;用焦耳热在3秒内合成出配位不饱和的Cu-N₃单原子催化剂&#xff0c;把它用在水系锌碘电池正极上&#xff0c;实现了50,000次超长循环。这个数据一出来&#xff0c;圈内不少人都挺振奋的。单原子催化剂虽然已经被追捧了很…

作者头像 李华
网站建设 2026/10/14 3:31:03

DINA认知诊断模型全解析:原理、改进与工程实践

简介&#xff1a;《认知诊断DINA模型研究进展》&#xff08;张潇&#xff09;是一篇关于认知诊断模型DINA的理论综述&#xff0c;面向教育学、心理学及测量学方向的研究者&#xff0c;系统梳理了DINA模型从提出到改进的发展脉络&#xff0c;帮助读者快速把握该模型的核心思想、…

作者头像 李华