SpringMVC/Boot中的校验框架 @Valid 和 @Validated的使用

1、@Valid 和 @Validated 的区别

@Validated 对@Valid 进行了二次封装,在使用上并没有区别。推荐使用 @Validated。但在分组、注解位置、嵌套验证等功能上有所不同,这里主要就这几种情况进行说明。

不同点 @Valid @Validated
来源 是Hibernate validation 的 校验注解 是 Spring Validator 的校验注解,是 Hibernate validation 基础上的增加版
注解位置 用在 构造函数、方法、方法参数 和 成员属性上 用在 类、方法和方法参数上。
但不能用于成员属性
嵌套验证 用在级联对象的成员属性上面 不支持
分组 无此功能 提供分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制

2、 对象校验 (最普通)

这是最普通的校验。

public class User implements Serializable {

	@NotNull(message = "uid不能为空")
	@Min(value = 1, message = "pid必须为正整数")
	private Long uid;

	@NotBlank(message = "userName不能为空")
	private String userName;

	@NotBlank(message = "address 不能为空")
	private String address;
	// getter/setter
}
@RequestMapping("/user/saveUser")
public void saveUser(@Valid User user, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        for (ObjectError error : bindingResult.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }
    }
}

测试:

在这里插入图片描述

运行结果:

address 不能为空
userName不能为空

3、多个对象的校验

User 对象:

上面已经有了,本处省略。

Student 对象:

public class Student implements Serializable {

	@NotNull(message = "sid不能为空")
	@Min(value = 1, message = "pid必须为正整数")
	private Long sid;

	@NotBlank(message = "sUserName不能为空")
	private String sUserName;

	@NotBlank(message = "sAddress 不能为空")
	private String sAddress;
    
    //getter/setter
}

Controller:

定义 user、student 两个对象和对应的 bindingResult、bindingResult2 异常对象。

/**
 * 多个对象校验
 * @param user
 * @param bindingResult
*/
@RequestMapping("/user/saveAll")
public void saveAll(@Validated User user, BindingResult bindingResult,@Validated Student student, BindingResult bindingResult2) {
    if (bindingResult.hasErrors()) {
        for (ObjectError error : bindingResult.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }

    }
    System.out.println("-----------");

    if (bindingResult2.hasErrors()) {
        for (ObjectError error : bindingResult2.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }

    }
}

测试数据:

uid=1111
userName=xxxx
pid=2222
sAddress=bbbbb

在这里插入图片描述

测试结果:

address 不能为空
-----------
sid不能为空
sUserName不能为空

4、对象级联校验

与对象校验 的唯一区别是 在关联对象的的 users 属性上加 @Valid

4.1、配置:

Item 对象:

关联的 users 属性上,必须加上 @Valid

public class Item implements Serializable {

	@NotNull(message = "id不能为空")
	@Min(value = 1, message = "id必须为正整数")
	private Long id;
	
	@Valid
	@NotNull(message = "users 不能为空")
	@Size(min = 1, message = "users 至少要有一个属性")
	private List<User> users;
}

User 对象:

User 上面已经有,本处省略。

Controller:

此处 ,既可以使用 @Valid ,也可以使用 @Validated 。如果使用分组,则只能使用 @Validated

@RequestMapping("/user/saveItem")
public void saveItem(@RequestBody @Validated Item item, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        for (ObjectError error : bindingResult.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }
    }
}

4.2、测试:

测试数据:

地址: http://127.0.0.1/user/saveItem

{
    "id": 0,
    "users": [
        {
            "uid": 11111,
            "userName": "北京时"
        }
    ]
}

在这里插入图片描述

测试结果:

address 不能为空
id必须为正整数

4.3、分析:

从测试结果中可以看出,已经开校验 User 中 address 属性值不能为空。说明级联校验起作用了。

正确的数据:

{
	"id":3333,
    "users": [
        {
            "uid": 11111,
            "userName": "北京时",
            "address":"bbbb"
        }
    ]
}

5、方法级别的单个参数校验

1、在方法所在的类上添加 @Validated 。注意,此处 只能使用 @Validated 注解@Valid 无效 ,因为 @Valid 不能用在类上。

2、为方法的每个参数上加上需要的验证注解,如 @Rang@Max@Min等注解 ;

3、定义 ConstraintViolationException 的异常拦截器 (不加此步骤时,无法捕获异常)。

5.1、配置:

Controller :

@Validated   //第1步,告诉MethodValidationPostProcessor此Bean需要开启方法级别验证支持
@RestController
public class ValidationController {

	@RequestMapping(value = "/validation/demo")
	public void demo1(
			@Range(min = 1, max = 9, message = "年级只能从1-9")   //第2步
			@RequestParam(name = "grade", required = true) int grade, //
			
			@Min(value = 1, message = "班级最小只能1") @Max(value = 99, message = "班级最大只能99")  //第2步
			@RequestParam(name = "classroom", required = true) int classroom) { //

		System.out.println(grade + "," + classroom);
	}
}

5.2、全局异常捕获:

@ControllerAdvice:

@ControllerAdvice
@Component
public class GlobalExceptionHandler {

	/**
	 * 拦截捕捉 MissingServletRequestParameterException 异常
	 */
	@ResponseBody
	@ExceptionHandler(value = MissingServletRequestParameterException.class)
	public String doMissingServletRequestParameterHandler(MissingServletRequestParameterException exception) {
		MissingServletRequestParameterException exs = (MissingServletRequestParameterException) exception;
		System.err.println(exs.getMessage());
		return "bad request, ";
	}

	/**
	 * 拦截捕捉 ConstraintViolationException 异常
	 */
	@ResponseBody
	@ExceptionHandler(value = ConstraintViolationException.class)
	public Map ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
		Map map = new HashMap();
		Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
		Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
		List<String> msgList = new ArrayList<>();
		while (iterator.hasNext()) {
			ConstraintViolation<?> cvl = iterator.next();
			System.err.println(cvl.getMessageTemplate());
			msgList.add(cvl.getMessageTemplate());
		}
		map.put("status", 500);
		map.put("msg", msgList);
		return map;
	}
}

5.3、测试:

测试数据:

grade=0
classroom=0

在这里插入图片描述

测试结果:

班级最小只能1
年级只能从1-9

6、分组校验

7、组序列 @GroupSequence

猜你喜欢

转载自blog.csdn.net/xiaojin21cen/article/details/90572980
今日推荐