文章目录
@Validated 与 @Valid 区别
- Spring Validation验证框架对参数的验证机制提供了@Validated(Spring的JSR-303规范,是标准JSR-303的一个变种),Javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。
- @Valid 属于Javax.validation包下,是jdk给提供的,是使用Hibernate validation的时候使用(java的JSR303声明了@Valid这类接口,而Hibernate-validator对其进行了实现)
- @Validated 是org.springframework.validation.annotation包下的,是spring提供的,是只用Spring validator校验机制使用
在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:
首先导入POM
<!-- @Validated 字段校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- @Valid 字段校验 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<!-- 6.2.0.Final -->
<version>${hibernate-validator.version}</version>
</dependency>
1.分组
-
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
@Validated会有分组的概念,后面默认是有一个Default.class,当你的@Validated后面没有加任何校验分组信息的时候默认会加Default分组,而对于被校验的对象的属性字段,如果你在属性的校验标签里面没有指定分组会添加到默认分组Default里面。所以如果你的对象里面的每个属性都指定了分组信息,而接口上面并没有添加分组信息会出现@Validated“失效的情况”,实际是因为它校验的是Default分组,而没有字段属于Default分组。上述校验不管加不加@ReqeustBody都能完成校验,但是都不能完成嵌套的校验。
-
@Valid : 作为标准的JSR-303规范,还没有吸收分组的功能
@Valid 由于不支持分组,所以对于所以校验标签里面添加了groups字段的都不会校验会跳过。 @Valid 加不加@RequestBody 基本校验会进行,嵌套校验需要在嵌套的对象上面加@Valid则可以进行嵌套校验,由于没有分组的概念,对于不同情况校验字段不同则需要在业务逻辑里面判断。
2.注解地方
- @Validated:用在类型、方法和方法参数上。但不能用于成员属性
- @Valid:可以用在方法、构造函数、方法参数和成员属性上(所以可以用@Valid实现嵌套验证)
3.常用方法
@Validated -------------------------------------------------------------------------------------------------- @Valid
—
4.使用方式
1.参数级调用 @Validated @Valid
@Validated 和 @Valid 都能用, 可以入参BindingResult获取参数校验结果
// Controller 示例
import org.apache.ibatis.annotations.Insert;
import org.springframework.validation.annotation.Validated;
//bindingResult 是判定参数是否判定成功的返回类,直接入参即可
public ResultData save(@Valid User user,BindingResult bindingResult){
}
//Entity 示例
public class User{
@NotNull(message = "用户名不能为空")
private String userName;
}
2.方法级调用 @Validated @Valid
@Validated 和 @Valid 都能用
public interface UserService{
@Valid
Object getOne(@NotNull(message = "id不能为null") @Max(value = Integer.MAX_VALUE)Integer id);
}
public class UserServiceImpl extends UserService{
@Override
public Object getOne(Integer id){
return null;
}
}
3.属性级调用 @Valid
@Valid 可用
@Validated 不可用
public class User{
@Valid
@NotNull(message = "mcn对象不能为空")
private Mcn mcn;
}
public class Mcn{
@NotNull(message = "mcn名称不能为空")
private String mcnName;
}
public Object save(UserDTO userDTO){
@Valid
User user = JsonUtils.beanToBean(userDTO,User.class);
}
4.类级调用 @Validated @Valid
@Validated 和 @Valid 都能用
@Valid
@Validated
public interface User {
}
5.构造函数级调用 @Valid
@Valid 可用
public class User{
private String name;
@Valid
public User(@NotNull(message = "id不能为null") String name){
this.name = name;
}
}
5.异常
如果入参参数校验失败,并且没有 BindingResult ,则会抛出 ConstraintViolationException 异常,可以进行全局异常处理,可以参考: https://blog.csdn.net/qiwunongqingyin/article/details/127112297
@Component
@ControllerAdvice
@Order(0)
public class CommonExceptionHandler {
/**
* 字段校验错误
* form表单提交bean错误
*
* @param exception
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResultData handleBindException(BindException exception) {
log.error("入参字段绑定错误: ", exception);
List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining("\n"));
return ResultData.error("100002", errorMessage);
}
/**
* 字段校验错误
* 请求体绑定到java bean上,且校验参数失败时抛出 MethodArgumentNotValidException
* 关键词 : @Valid 、 @RequestBody、Java bean 、表单(Content-Type: application/json、Content-Type: application/xml)
*
* @param exception
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResultData handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
log.error("入参字段校验错误: ", exception);
List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining("\n"));
return ResultData.error("100002", errorMessage);
}
/**
* 字段校验错误
* 普通参数(非 java bean)校验出错时抛出
* 关键词 : @Validated 、 非Java bean
*
* @param exception
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResultData handleConstraintViolationException(ConstraintViolationException exception) {
log.error("方法字段校验错误: ", exception);
return ResultData.error("100002", exception.getMessage());
}
}