@Validated和@Valid区别

2024-08-06 14:09:08 浏览数 (1)

@Validated和@Valid区别

分组:

定义接口 ,根据接口 将不同的校验规则分给不同的组,在使用时,指定不同的校验规则

接口类

Group1.Java

代码语言:javascript复制
package com.example.validateddemo.interfaces;
/**
 * 校验分组1
 * @author He Changjie on 2020/9/5
 */
public interface Group1 {
}

Group2.Java

代码语言:javascript复制
package com.example.validateddemo.interfaces;
 
/**
 * 校验分组2
 * @author He Changjie on 2020/9/5
 */
public interface Group2 {
}
实体类

使用注解时,可以给属性设置多个校验进行分组!

User2Dto.Java

代码语言:javascript复制
package com.example.validateddemo.entity.dto;
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import lombok.Data;
import javax.validation.constraints.*;
@Data
public class User2Dto {
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空!", groups = {Group1.class})		//给属性设置组!
    private String username;
    /**
     * 性别
     */
    @NotBlank(message = "性别不能为空!")
    private String gender;
    /**
     * 年龄
     */
    @Min(value = 1, message = "年龄有误!", groups = {Group1.class})		//设置 Group1
    @Max(value = 120, message = "年龄有误!", groups = {Group2.class})	//设置 Group2
    private int age;
    /**
     * 地址
     */
    @NotBlank(message = "地址不能为空!")
    private String address;
    /**
     * 邮箱
     */
    @Email(message = "邮箱有误!", groups = {Group2.class})
    private String email;
    /**
     * 手机号码 正则表达式...
     */
    @Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$",message = "手机号码有误!", groups = {Group2.class})
    private String mobile;
}
控制类

Controller 中指定了,校验的组类型!

Demo1Controller.Java

代码语言:javascript复制
package com.example.validateddemo.controller;
 
import com.example.validateddemo.base.Result;
import com.example.validateddemo.entity.dto.Team1Dto;
import com.example.validateddemo.entity.dto.User1Dto;
import com.example.validateddemo.entity.dto.User2Dto;
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import com.example.validateddemo.utils.ResultUtil;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @author He Changjie on 2020/9/5
 */
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
	
	//不指定分组,即是默认组 或 Default.Class 即对没有进行分组的JSR303 数据进行校验!
    @PostMapping("/insert3")
    public Result validatedDemo3(@Validated @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
    @PostMapping("/insert4")
    public Result validatedDemo4(@Validated(Group1.class) @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
    @PostMapping("/insert5")
    public Result validatedDemo5(@Validated(Group2.class) @RequestBody User2Dto user2Dto){
        return ResultUtil.success(user2Dto);
    }
}
测试:

查看insert4 使用了Group1 的组校验~

查看insert5 使用了Group2 的组校验~

不指定组使用默认组进行校验! 则,没有进行分组的JSR303 注解生效进行校验通过!

总结:

@Validated

  • 注解,可以使用 分组进行校验!
  • 定义分组接口,根据接口来给实体类上的 校验注解进行分组! groups = {组接口.class}
  • Controller 上使用时候可以指定,校验实体的组 不指定即没有组的校验进行校验核对! @Validated(组接口.class)

嵌套验证:@Valid

实体:

在比较两者嵌套验证时,先说明下什么叫做嵌套验证。比如我们现在有个实体叫做Item:

Item带有很多属性,属性里面有属性id,属性值id,属性名和属性值,如下所示:

  • 其中包含一个List类型的数据 或其它引用类型!

Item.Java

代码语言:javascript复制
public class Item {

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

    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "至少要有一个属性")
    private List<Prop> props;
}

Prop.Java

代码语言:javascript复制
public class Prop {

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

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

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

    @NotBlank(message = "vidName不能为空")
    private String vidName;
}
  • Prop 属性 属性这个实体也有自己的验证机制,比如属性和属性值id不能为空,属性名和属性值不能为空等
控制类:

ItemController.Java

代码语言:javascript复制
@RestController
public class ItemController {
    @RequestMapping("/item/add")
    public void addItem(@Validated Item item, BindingResult bindingResult) {
        doSomething();
    }
}
  • 程序校验时候: 如果Item实体的props属性不额外加注释,只有**@NotNull**和**@Size** 无论入参采用 @Validated 还是 @Valid验证 Spring Validation框架只会对Item的id和props做非空和数量验证, 不会对props字段里的Prop实体进行字段验证
  • 也就是@Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证。 也就是说如果传的List中有Prop的pid为空或者是负数,入参验证不会检测出来。
更改:实体:

为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。

  • 由于@Validated不能用在成员属性(字段)上
  • 但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能

由此推断:

  • @Valid加在方法参数时并不能够自动进行嵌套验证
  • 而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated或@Valid来进行嵌套验证

Item.Java

代码语言:javascript复制
public class Item {

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

    @Valid // 嵌套验证必须用@Valid
    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "props至少要有一个自定义属性")
    private List<Prop> props;
}

然后我们在ItemController的addItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。

总结:

嵌套验证:

  • 就是说,注解只能对,实体普通属性进行校验,如果是引用类型,且也是一个对象类型 注解并不会自动的进行,校验内部的元素!
  • @Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证 由于@Validated不能用在成员属性(字段)上 @Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能。
  • 所以,如果校验需要在实现上对象,进行嵌套验证实体内部的对象,可以使用 @Valid 对实体属性进行嵌套校验!

异常处理:

BindingResult

Controller控制层写参数接收的入口

  • 需要注意的是@Valid 和 BindingResult 是一 一对应的, 如果有多个@Valid 那么每个@Valid后面都需要添加BindingResult用于接收bean中的校验信息. 配套使用!

随意一个Controller

代码语言:javascript复制
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<Pesponsibles> testBindingResult(@Valid @RequestBody Parameter parameter,BindingResult bindingResult)
{
	log.info("test start");
	Pesponsibles pesponsibles=new Pesponsibles();
	
	//判断是否存在,校验异常数据!打印日志!
	if(bindingResult.hasErrors()){
		 List<FieldError> fieldErrors = bindingResult.getFieldErrors(); //获取校验异常集合!
		 //遍历 输出日志!
		 fieldErrors.forEach(fieldError -> {
            //日志打印不符合校验的字段名和错误提示
            log.error("error field is : {} ,message is : {}", fieldError.getField(), fieldError.getDefaultMessage());
          });
        //控制台查看!  
		 for(int i=0;i<fieldErrors.size();i  ){
            //控制台打印不符合校验的字段名和错误提示
			System.out.println("error field is :" fieldErrors.get(i).getField() ",message is :" fieldErrors.get(i).getDefaultMessage());
		 }
		//返回前台数据异常!这里就根据自己项目情况而定
		return new ResponseEntity<>(pesponsibles, HttpStatus.BAD_REQUEST);
	}
	
	//没有异常操作...


	

0 人点赞