问题再现
背景
公司新成立了一个项目,但在已有项目的支持下引入了一批原始的依赖,就这样,坑来了…
复现
- 通过Maven工具引入java注解相关依赖.
仅展示与@NotNull和@NotBlank相关的依赖,方便后续作说明.
<!--注解校验类-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<!--<version>2.0.1.Final</version>-->
</dependency>
<!--以下注解校验实现类-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!--以上注解校验实现类-->
- 代码实现(涉及公司机密,因此仅展示Demo)
2.1 请求Request
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
//校验实体类
@Data
public class SSS {
@NotEmpty(message = "名称不能为空!")
private String name;
@NotNull(message = "年龄不能为空!")
@Min(message = "年龄不能小于123岁!", value = 123)
private Integer age;
}
2.2 请求Controller
@RestController
@RequestMapping("/test")
public class InfoController {
@PostMapping("/demo")
public String ss( @Valid @RequestBody SSS request) {
System.out.println(request.toString());
return "测试成功";
}
}
错误提示
- java: The annotation @NotEmpty is disallowed for this data type.
解决
查找问题过程
通过错误提示[is disallowed for this data type.]对代码的全局搜索后,发现【hibernate-validator】依赖的【ValidationProcessorMessages.properties】中存在【NOT_SUPPORTED_TYPE=The annotation @{0} is disallowed for this data type.】,再通过引用方式点击进入【TypeCheck.java】类中才发现该依赖会对属性在编译时期就进行类型匹配的校验,且其并未完全参照@NotEmpty等注解的支持形式进行类型判断,因此会提示该错误;
例:@NotEmpty与本注解会支持下列属性
CharSequence (length of character sequence is evaluated)
Collection (collection size is evaluated)
Map (map size is evaluated)
Array (array length is evaluated)
上述描述如图 1.1、1.2所示.
图1.1 ValidationProcessorMessages.properties部分消息展示
图1.2 TypeCheck.java校验逻辑
解决方案
既然原有的【hibernate-validator】并不满足@NotEmpty和@NotBlank等方式编译期校验,即可以再寻找替换的方案;而Spring提供的【spring-boot-starter-validation】依赖经测试可以满足,原因很简单,就是它实现了上述注解的适用范围.直接使用【spring-boot-starter-validation】替换maven依赖的【hibernate-validator】和【hibernate-validator-annotation-processor】即可。
替换依赖如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
这样即可解决题目中出现的错误了
PS
1.其实springboot的校验实现基类都是以【HibernateValidatorFactory.java】进行校验逻辑对象的调用,无非是笔者最先引入的依赖多了一个TypeCheck的校验罢了。
2.附上笔者亲测的@NotEmpty这一系列的注解最终的处理方式。
…
1.通过BindingResult进行校验结果处理;(其实可以使用切面进行处理,至于实现就靠各位了.)
@PostMapping("/test")
public String ss( @RequestAttribute SSS request, BindingResult rs ) {
//此处处理校验结果.
if(rs.hasErrors()){
//每次仅取一次校验结果返回.
return rs.getFieldError().getDefaultMessage();
}
System.out.println(request.toString());
return "dafds";
}
2.通过@Valid注解抛出校验异常,再用@RestControllerAdvice结合@ExceptionHandler进行统一异常处理,Demo如下.
@PostMapping("/test")
public String ss(@Valid @RequestAttribute SSS request) {
//此处处理校验结果.
if(rs.hasErrors()){
//每次仅取一次校验结果返回.
return rs.getFieldError().getDefaultMessage();
}
System.out.println(request.toString());
return "dafds";
}
//统一异常处理类
@RestControllerAdvice
public class BaseExceptionHandler {
/**
* 业务手动异常
*/
@ExceptionHandler(value = Exception.class)
public String exceptionRest(Exception e) {
return e.getMessage();
}
先就这样吧。