SpringBoot注解--06--注解@Validated

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 1 简述
    • 1.1 @Validated作用
    • 1.2 所有参数注解含义
    • 1.3 异常处理
    • 1.4 @Valid和@Validated比较
      • @Valid级联校验
  • 2.@Validated 分组校验
    • 1.1为何要分组校验?
    • 1.2 代码案例
    • 1.3 @Validated分组校验顺序
        • 分组校验顺序通过==使用 @GroupSequence注解==实现
  • 3.@Validated的使用方法
    • 3.1 在方法级别上使用@Validated
    • 3.2 在==类级别==上使用@Validated
    • 3.2 Get请求参数校验


1 简述

  • @Validated是Spring框架中的一个注解,它是JSR-303规范的扩展,可以用于在方法级别上校验方法参数。
  • 它可以用于验证请求参数和请求体中的数据。@Validated注解可以用于方法级别和类级别上,用于验证方法参数和类属性。

1.1 @Validated作用

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

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

SpringBoot注解--06--注解@Validated_第1张图片

1.2 所有参数注解含义

SpringBoot注解--06--注解@Validated_第2张图片

1.3 异常处理

错误的状态码:返回的响应码推荐使用400 bad request.

说明:若不做异常处理,@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;
 

@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());
    }
}

1.4 @Valid和@Validated比较

Spring Boot–09–注解@Valid

SpringBoot注解--06--注解@Validated_第3张图片

  • @Valid支持级联校验,而@Validated不行
  • @Validated支持分组校验,而@Valid不行

@Valid级联校验

级联校验: 也叫嵌套检测.嵌套就是一个实体类包含另一个实体类
@Valid和可以用在成员属性的字段上,因此 @Valid可以提供级联校验

@Data
public class Hair {
	
	@NotBlank(message = "头发长度必须提交!")
	private Double length;
 
  	@NotBlank(message = "头发颜色必须提交!")
  	private String color;
}
 
@Data
public class Person {
	
	@NotBlank(message = "用户姓名必须提交!")
	@Size(min=2, max=8)
	private String userName;
 
  	// 添加@Valid注解实现嵌套检测
  	@Valid
    @NotEmpty(message = "用户要有头发!")
    private List<Hair> hairs;
}
 
@PostMapping("/person")
public Result addPerson(@Valid @RequestBody Person person) {
	return Result.buildSuccess(person);
}

只是在方法参数前面添加 @Valid和 @Validated注解,不会对嵌套的实体类进行校验.要想实现对嵌套的实体类进行校验,需要在嵌套的实体类属性上添加 @Valid注解

2.@Validated 分组校验

1.1为何要分组校验?

假设有这样一种场景:

我们使用同一个VO(Request)类来传递save和update方法的数据,

  • 但对于save方法来说,通常有框架帮我们生成id,我们不需要传id此时需要使用注解@Null表名id数据必须为空。
  • 但对于update方法,我们必须传id才能进行update操作,所以同一个字段面对不同的场景不同需求就可以使用分组校验。

1.2 代码案例

(1)创建分组接口
这里并不需要实现编写什么代码,标明分类。

//分组接口 1
public interface InsertGroup {
}

//分组接口 2
public class UpdateGroup {
}

(2)Request实体类

@Data
@NoArgsConstructor
public class TestRequest {

    @Null(message = "无需传id",groups = InsertGroup.class)
    @NotBlank(message = "必须传入id",groups = UpdateGroup.class)
    private String id;
    
  }

(3)controller接口

	@RequestMapping("/valid/test")
    public ResponseEntity<ResponseResult> test(@Validated({UpdateGroup.class})@RequestBody TestRequest request) {
        System.out.println(request);
        return null;
    }

(4)postman测试
SpringBoot注解--06--注解@Validated_第4张图片
(5)注意事项!!!
当我们在controller层指定分组后,属性上没有表名分组的校验还执行么?

下面的Request实体中,id进行了分组,address没有进行分组:

@Data
@NoArgsConstructor
public class TestRequest {

    @Null(message = "无需传id",groups = InsertGroup.class)
    @NotBlank(message = "必须传入id",groups = UpdateGroup.class)
    private String id;

	@Length(max = 3, message = "address最大长度是3")
    private String address;
    
  }

postman测试:

如下图,校验没有成功!!!!说明一旦开启了分组校验,就必须把所有的校验规则都指定组别,不然不生效

SpringBoot注解--06--注解@Validated_第5张图片

1.3 @Validated分组校验顺序

默认情况下,分组间的约束是无序的,但是在一些特殊的情况下可能对分组间的校验有一定的顺序

  • 比如第二组的分组的约束的校验需要依赖第一组的稳定状态来进行,此时,要求分组间的约束校验一定要有顺序
分组校验顺序通过使用 @GroupSequence注解实现
@Data
public class UserGroupSequence {
	
	public interface FirstGroup {}
 
	public interface SecondGroup {}
 
	// 使用GroupSequence定义分组校验顺序:按照FirstGroup,SecondGroup分组顺序进行校验
	@GroupSequence({FirstGroup.class, SecondGroup.class})
	public interface Group {}
 
	@NotEmpty(message = "用户ID必须提交!", group = FirstGroup.class)
	private String userId;
 
	@NotEmpty(message = "用户姓名必须提交!", group = FirstGroup.class)
	@Size(min = 2, max = 8, message = "用户姓名的长度在2~8之间", goup = Second.class)
	private String userName;
} 

Controller

@RestController
@RequestMapping("/user")
public class UserGroupSequenceController {
	// 这里方法中@Validated注解value的值是Group.class
	@PostMapping("/user")
	public Result addGroup(@Validated(value = Group.class) @RequestBody UserGroupSequence user) {
		return Result.buildSuccess(user);
	}
}

使用 @GroupSequence注解指定分组校验顺序后,第一组分组的约束的校验没有通过后,就不会进行第二组分组的约束的校验

3.@Validated的使用方法

3.1 在方法级别上使用@Validated

在方法级别上使用@Validated注解,需要在方法参数上添加该注解。下面是一个简单的示例,演示了如何在方法级别上使用@Validated注解。

@RestController
@RequestMapping("/users")
public class UserController {
 
    @PostMapping
    public User createUser(@RequestBody @Validated User user) {
        // 处理用户创建逻辑
    }
 
}

在上面的示例代码中,@Validated注解被应用在User对象上,用于验证请求体中的数据是否符合要求。

3.2 在类级别上使用@Validated

在类级别上使用@Validated注解,需要在类上添加该注解。下面是一个简单的示例,演示了如何在类级别上使用@Validated注解。

@RestController
@RequestMapping("/users")
@Validated
public class UserController {
 
    @PostMapping
    public User createUser(@RequestBody User user) {
        // 处理用户创建逻辑
    }
 
}

在上面的示例代码中,@Validated注解被应用在UserController类上,用于验证该类中所有方法的参数是否符合要求

3.2 Get请求参数校验

get参数校验,需要在类上加@Validated

@RestController
@Slf4j
@RequestMapping("/api/test")
@Validated
public class TestController {
    @GetMapping(value = "/h11")
    public String test11( @NotEmpty(message = "姓名不能为空") String name) {
 
        System.out.println("kaidsd");
        System.out.println(name);
 
        return "applyInfoDTO";
    }
}

SpringBoot注解--06--注解@Validated_第6张图片

你可能感兴趣的:(Spring基础知识--SSM,spring,boot,java,后端)