springboot数据格式验证(一)
在springboot中自定义了一个校验注解
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = UniqueProcessInfoValidator.class)
public @interface UniqueProcessInfo {
String message() default "jobName在当前项目中已存在!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
下面是指定的校验逻辑类
//研究发现hibernate验证器拿不到spring bean, processInfoService总是null!!!
@Service
public class UniqueProcessInfoValidator implements ConstraintValidator<UniqueProcessInfo, ProcessInfo> {
@Autowired
private ProcessInfoService processInfoService;
@Override
public boolean isValid(ProcessInfo processInfo, ConstraintValidatorContext constraintValidatorContext) {
boolean exists = processInfoService.existsDuplicateProcess(processInfo);
return !exists;
}
}
经研究发现validator是hibernate维护的,所以在启动的时候拿不到spring中的Bean。
不得已需要用到spring动态装载bean的方式。
改写成下面这种写法
@Slf4j
public class UniqueProcessInfoValidator implements ConstraintValidator<UniqueProcessInfo, ProcessInfo> {
@Override
public boolean isValid(ProcessInfo processInfo, ConstraintValidatorContext constraintValidatorContext) {
ProcessInfoService processInfoService = SpringContextUtil.getBean(ProcessInfoService.class);
boolean exists = processInfoService.existsDuplicateProcess(processInfo);
log.info(String.valueOf(exists));
return !exists;
}
}
然后就可以了!
附录:
验证经验
1.把校验行为从分层中剥离出来,不是在哪一层做,而是在 Bean 上做。
2.要对校验项预置好默认的提示信息,这样当校验不通过时,用户能获得明确的修正提示
3.要把不带业务含义的格式校验注解放到 Bean 的类定义之上,把带业务逻辑的校验放到 Bean 的类定义的外面,
原因是放在类定义中的注解能够自动运行,而放到类外面的业务校验需要像前面的示例代码那样,明确标出注解时才会运行,带业务逻辑的校验,通常就需要外部资源参与执行,这不仅仅是多消耗一点时间和运算资源的问题,因为我们很难保证依赖的每个服务都是幂等的,重复执行校验很可能会带来额外的副作用。因此应该放到外面,让使用者自行判断是否要触发
4.对应校验对象不是bean的情况,请参考下面博文,将校验加在函数参数上