@Validated和@Valid区别
分组:
定义接口 ,根据接口
将不同的校验规则分给不同的组,在使用时,指定不同的校验规则
接口类
Group1.Java
package com.example.validateddemo.interfaces;
/**
* 校验分组1
* @author He Changjie on 2020/9/5
*/
public interface Group1 {
}
Group2.Java
package com.example.validateddemo.interfaces;
/**
* 校验分组2
* @author He Changjie on 2020/9/5
*/
public interface Group2 {
}
实体类
使用注解时,可以给属性设置多个校验进行分组!
User2Dto.Java
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
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
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
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
@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
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
@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);
}
//没有异常操作...