Closed stick-i closed 2 months ago
由于校验过程中抛出的任何异常,都会被更上层的校验器(hibernate-validator)所捕获,并且转换成 javax.validation.ValidationException 再继续抛出。
比如这样的场景:
public static ExampleEnum getByCode(Integer code) {
if (code == null) {
throw new IllegalArgumentException("code can not be null");
}
for (ExampleEnum value : values()) {
if (value.code.equals(code)) {
return value;
}
}
return null;
}
@Data
@SpelValid
public class ParamTestBean {
/**
* 枚举值校验
* <p>
* 通过静态方法调用,校验枚举值是否存在
*/
@SpelAssert(assertTrue = " T(cn.sticki.validator.spel.enums.ExampleEnum).getByCode(#this.testEnum) != null ", message = "枚举值不合法")
private Integer testEnum;
}
ParamTestBean bean = new ParamTestBean();
bean.setTestEnum(null);
当使用如上面bean
的对象去进行校验时,我们希望得到一个IllegalArgumentException,但实际上会得到一个ValidationException:
要从框架层面去解决这个问题,只能够脱离 javax.validation 的规范和 hibernate 的执行器来独自进行校验,目前看来这样做的成本比较大,且会带来一些其他的影响,暂时不考虑这样做。
还有一种解决方案,需要使用框架的开发者进行一点特殊处理。当捕获到 ValidationException e 时,首先判断下 e.getCause() 的类型是不是自己项目中的业务异常基类,如果是业务异常的类型,就丢给对应的方法去处理,像这样:
@ExceptionHandler({BusinessException.class})
public Resp<Void> handleServiceException(BusinessException ex) {
return new Resp<>(ex.getCode(), ex.getMessage());
}
@ExceptionHandler({ValidationException.class})
public Resp<Void> handleValidationException(ValidationException ex) {
if (ex.getCause() instanceof BusinessException) {
return handleBindException((BindException) ex.getCause());
}
return new Resp<>(500, "system error");
}
这种方案也有缺点,如果没有一个合适的基类,那么需要将多种不同的异常类型都进行特殊处理,比较麻烦。
目前决定还是先采用这种方案,后续有机会再做独立吧。