@Validation 和@Valid 常常配合使用对传输的参数进行数据校验的注解,并通过配置全局异常处理器进行合理化的提示,增加用户的体验
并且@Validated可以通过分组来指定什么时候触发什么样的参数校验(这里看一下就行,下面有说什么是分组)
其实不用这两个注解也可以完成对传输的参数进校验,那样我们就需要一直写if语句进行判断 ,如果不为xxx,抛出异常,然后进行捕获处理
但是当多处都用到的一样的传输参数的时候,我们每次都需要写一些重复的if进行校验,其实代码是不优雅的。因此有了这两个组件来帮我们进行传输参数的校验。
-
-
org.springframework.boot -
spring-boot-starter-web -
-
-
-
-
org.springframework.boot -
spring-boot-starter-validation -
-
-
-
org.projectlombok -
lombok -
-
-
-
-
org.springframework.boot -
spring-boot-starter-test -
test -
-
-
junit -
junit -
-
常用的校验注解

- package com.sofwin.validator.domain;
-
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.config.Status;
- import com.sofwin.validator.config.UpdateGroup;
- import lombok.Data;
- import org.hibernate.validator.constraints.Range;
- import org.springframework.web.bind.annotation.Mapping;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- import java.math.BigDecimal;
- import java.util.List;
-
- /**
- * @packageName: com.sofwin.validator.domain
- * @author: wentao
- * @date: 2023/9/4 21:17
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 测试
- */
- @Data
- public class UserR {
-
- @NotBlank(message = "名称不能为空")
- private String name;
-
- @NotNull(message = "年龄不能为空")
- @Range(min = 1,max = 200,message ="最小为{min}岁,最大为{max}岁" )
- private Integer age;
-
- @Size(message ="编号长度为 [4-8] ", min = 4, max = 8)
- private String idNo;
-
- }
注意需要在请求参数的前面加上@Valid注解
- package com.sofwin.validator.config;
-
- import lombok.Data;
-
- /**
- * @packageName: com.sofwin.validator.config
- * @author: wentao
- * @date: 2023/9/4 21:34
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 统一返回参数
- */
- @Data
- public class BaseResult
{ - private int code;
- private String message;
- private T data;
-
- public BaseResult() {
- }
-
- public BaseResult(int code, T data,String message) {
- this.code = code;
- this.message = message;
- this.data = data;
- }
-
- public static
BaseResult build(int code, T data, String message) { - return new BaseResult
(code,data,message); - }
-
- public static
BaseResult build( T data, BaseResult resultCodeEnum) { - return new BaseResult
(resultCodeEnum.getCode(),data,resultCodeEnum.getMessage()); - }
-
- public static
BaseResult ok(T data) { - return new BaseResult<>(20000,data,"success");
- }
-
- public static
BaseResult fail(T data) { - return new BaseResult<>(50000,data,"error");
- }
-
-
-
- }
- package com.sofwin.validator.controller;
-
- import com.sofwin.validator.config.BaseResult;
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.domain.UserR;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotNull;
-
- /**
- * @packageName: com.sofwin.validator.controller
- * @author: wentao
- * @date: 2023/9/4 21:14
- * @version: 1.0
- * @description: 请求参数校验
- */
-
- @RestController
- @RequestMapping("validator")
- public class ValidatorController {
-
-
- @PostMapping("/validPost")
- public BaseResult validPostTest(@Valid @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }
-
- }


我们发现没有提示我们在实体中message中写的提示信息,是因为我们没有设置全局异常处理器
,它只是在控制台返回了提示信息
2023-09-05 21:24:03.305 WARN 20924 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.sofwin.validator.config.BaseResult com.sofwin.validator.controller.ValidatorController.validPostTest(com.sofwin.validator.domain.UserR): [Field error in object 'userR' on field 'age': rejected value [1111]; codes [Range.userR.age,Range.age,Range.java.lang.Integer,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userR.age,age]; arguments []; default message [age],200,1]; default message [最小为1岁,最大为200岁]] ]
- package com.sofwin.validator.config;
-
- import lombok.extern.slf4j.Slf4j;
- import org.slf4j.LoggerFactory;
- import org.springframework.validation.BindException;
- import org.springframework.web.bind.annotation.ControllerAdvice;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
-
- import javax.validation.ConstraintViolation;
- import javax.validation.ConstraintViolationException;
- import java.util.Set;
- import org.slf4j.Logger;
-
- /**
- * @packageName: com.sofwin.validator.config
- * @author: wentao
- * @date: 2023/9/4 21:28
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 全局异常处理器
- */
-
- @RestControllerAdvice
- @Slf4j
- public class GlobExceptionHandeler {
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
- //valid参数校验出现异常
- @ExceptionHandler(BindException.class)
- public BaseResult bindException(BindException e) {
- logger.error("valid参数校验出现异常");
- System.out.println(e);
- return BaseResult.build(441,null,e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
- }
-
- //validated参数校验出现异常
- @ExceptionHandler(ConstraintViolationException.class)
- public BaseResult constraintViolationException(ConstraintViolationException e) {
- logger.error("validated参数校验出现异常");
-
- return BaseResult.build(441,null,e.getLocalizedMessage().split(":")[1].trim());
- }
-
- @ExceptionHandler(Exception.class)
- public BaseResult constraintViolationException(Exception e) {
- logger.error("Exception");
- return BaseResult.build(441,null,e.getLocalizedMessage());
- }
- }

一定要在controller上加入@Validated才生效
- @RestController
- @RequestMapping("validator")
- @Validated
- public class ValidatorController {
-
-
- @PostMapping("/validPost")
- public BaseResult validPostTest(@Valid @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }
-
-
- @GetMapping("/validGet1")
- public BaseResult validGetTest( @NotBlank(message = "名字不能为空") String name ) {
- return BaseResult.ok(name);
- }
- }
当我们在特定情况下才进行参数校验才进行分组,例如只有当我们插入的时候我们进行校验,其他时候不进行参数的校验,这个时候就可以使用分组
- package com.sofwin.validator.domain;
-
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.config.Status;
- import com.sofwin.validator.config.UpdateGroup;
- import lombok.Data;
- import org.hibernate.validator.constraints.Range;
- import org.springframework.web.bind.annotation.Mapping;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- import java.math.BigDecimal;
- import java.util.List;
-
- /**
- * @packageName: com.sofwin.validator.domain
- * @author: wentao
- * @date: 2023/9/4 21:17
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 测试
- */
- @Data
- public class UserR {
-
- @NotBlank(message = "名称不能为空")
- //进行分组
- @NotBlank(message = "名称不能为空(InsertGroup)",groups = InsertGroup.class)
- private String name;
-
- @NotNull(message = "年龄不能为空")
- @NotNull(message = "年龄不能为空(InsertGroup)",groups = {InsertGroup.class,UpdateGroup.class})
- @Range(min = 1,max = 200,message ="最小为{min}岁,最大为{max}岁" )
- private Integer age;
-
-
-
- @Size(message ="编号长度为 [4-8] ", min = 4, max = 8)
- private String idNo;
-
-
-
- }
其中InsertGroup和UpdateGroup只是一个普通的接口
-
- public interface InsertGroup {
-
- }
-
-
-
- public interface UpdateGroup {
-
- }
- package com.sofwin.validator.controller;
-
- import com.sofwin.validator.config.BaseResult;
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.domain.UserR;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
-
- /**
- * @packageName: com.sofwin.validator.controller
- * @author: wentao
- * @date: 2023/9/4 21:14
- * @version: 1.0
- * @description: 请求参数校验
- */
-
- @RestController
- @RequestMapping("validator")
- @Validated
- public class ValidatorController {
-
-
- @PostMapping("/validPost")
- public BaseResult validPostTest(@Valid @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }
- @PostMapping("/validPost2")
- public BaseResult validPostTest2(@Validated(InsertGroup.class) @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }
-
- @GetMapping("/validGet1")
- public BaseResult validGetTest( @NotBlank(message = "名字不能为空") String name ) {
- return BaseResult.ok(name);
- }
-
- @GetMapping("/validGet2")
- public BaseResult validGetTest2(@Validated(InsertGroup.class) @NotNull(message = "名字不能为空") String name ) {
- return BaseResult.ok(name);
- }
- }
validPost2、validGet2



当它提供的注解我们没有办法解决我们的问题的时候,我们就可以自定义注解
- package com.sofwin.validator.config;
-
- import javax.validation.Constraint;
- import javax.validation.Payload;
- import java.lang.annotation.*;
-
- /**
- * @packageName: com.sofwin.validator.config
- * @author: wentao
- * @date: 2023/9/4 21:52
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 自定义校验注解
- */
- @Target({ElementType.FIELD,ElementType.PARAMETER})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- //自己写校验规则
- @Constraint(validatedBy = {StatusConstraint.class})
- //元注解 可以分组使用,如果不写定义相同的注解会出现错误
- @Repeatable(Status.List.class)
- public @interface Status {
-
- String[] statusType() default {};
-
- String message() default "状态传递有误";
-
- Class>[] groups() default {};
-
- Class extends Payload>[] payload() default {};
-
- @Target({ElementType.FIELD,ElementType.PARAMETER})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @interface List {
- Status[] value();
- }
-
- }
- package com.sofwin.validator.config;
-
- import javax.validation.ConstraintValidator;
- import javax.validation.ConstraintValidatorContext;
- import java.lang.annotation.Annotation;
- import java.util.Arrays;
- import java.util.List;
-
- /**
- * @packageName: com.sofwin.validator.config
- * @author: wentao
- * @date: 2023/9/4 22:04
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 自定义校验柜子
- */
- public class StatusConstraint implements ConstraintValidator
{ -
- List
statusType; -
- /**
- * 一般进行初始化
- * @param constraintAnnotation
- */
- @Override
- public void initialize(Status constraintAnnotation) {
- String[] strings = constraintAnnotation.statusType();
- statusType = Arrays.asList(strings);
- }
-
- /**
- *
- * @param value 参数的值
- * @param context
- * @return true 通过不抛出异常 fasle不通过抛出异常
- */
- @Override
- public boolean isValid(Integer value, ConstraintValidatorContext context) {
- if (value !=null) {
- if (!statusType.contains(String.valueOf(value))) {
- return false;
- }
- return true;
- }
- return false;
- }
- }
实体类
- package com.sofwin.validator.domain;
-
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.config.Status;
- import com.sofwin.validator.config.UpdateGroup;
- import lombok.Data;
- import org.hibernate.validator.constraints.Range;
- import org.springframework.web.bind.annotation.Mapping;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- import java.math.BigDecimal;
- import java.util.List;
-
- /**
- * @packageName: com.sofwin.validator.domain
- * @author: wentao
- * @date: 2023/9/4 21:17
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 测试
- */
- @Data
- public class UserR {
-
- @NotBlank(message = "名称不能为空")
- //进行分组
- @NotBlank(message = "名称不能为空(InsertGroup)",groups = InsertGroup.class)
- private String name;
-
- @NotNull(message = "年龄不能为空")
- @NotNull(message = "年龄不能为空(InsertGroup)",groups = {InsertGroup.class,UpdateGroup.class})
- @Range(min = 1,max = 200,message ="最小为{min}岁,最大为{max}岁" )
- private Integer age;
-
- @Status(statusType = {"1","2"})
- private Integer status;
-
- @Size(message ="编号长度为 [4-8] ", min = 4, max = 8)
- private String idNo;
-
-
-
- }
controller
- @PostMapping("/validPost")
- public BaseResult validPostTest(@Valid @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }
正常传参

非正常传参
3.7 当出现类中出现嵌套的情况当出现嵌套的情况只需要在类的属性中在加一个注解@Valid

- package com.sofwin.validator.domain;
-
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.config.Status;
- import com.sofwin.validator.config.UpdateGroup;
- import lombok.Data;
- import org.hibernate.validator.constraints.Range;
- import org.springframework.web.bind.annotation.Mapping;
-
- import javax.validation.Valid;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- import java.math.BigDecimal;
- import java.util.List;
-
- /**
- * @packageName: com.sofwin.validator.domain
- * @author: wentao
- * @date: 2023/9/4 21:17
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 测试
- */
- @Data
- public class UserR {
-
- @NotBlank(message = "名称不能为空")
- //进行分组
- @NotBlank(message = "名称不能为空(InsertGroup)",groups = InsertGroup.class)
- private String name;
-
- @NotNull(message = "年龄不能为空")
- @NotNull(message = "年龄不能为空(InsertGroup)",groups = {InsertGroup.class,UpdateGroup.class})
- @Range(min = 1,max = 200,message ="最小为{min}岁,最大为{max}岁" )
- private Integer age;
-
- @Status(statusType = {"1","2"})
- private Integer status;
-
- @Size(message ="编号长度为 [4-8] ", min = 4, max = 8)
- private String idNo;
-
-
- //嵌套使用valid才能生效
- @Valid
- private List
sonUserList; - }
- package com.sofwin.validator.domain;
-
- import com.sofwin.validator.config.InsertGroup;
- import com.sofwin.validator.config.UpdateGroup;
- import lombok.Data;
-
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
- import java.math.BigDecimal;
-
- /**
- * @packageName: com.sofwin.validator.domain
- * @author: wentao
- * @date: 2023/9/4 21:17
- * @version: 1.0
- * @email 1660420659@qq.com
- * @description: 测试
- */
- @Data
- public class SonUser {
-
- @NotBlank(message = "sonName不能为空")
- private String sonName;
-
- }
- @PostMapping("/validPost")
- public BaseResult validPostTest(@Valid @RequestBody UserR user ) {
- return BaseResult.ok(user);
- }

@Valid:没有分组的功能。
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能