触发"beforeSave"存储库事件处理程序之前的实体验证



弹簧数据rest文档描述了验证实体 的方法:

您只需要向验证器的实例注册 正确的事件

在调用验证器的bean

是否有一种方法可以应用[声明性] JSR-303实体的验证 它们被传递给" beforesave" RepositoryEventHandler s?

从我到目前为止的调试,事实并非如此," beforesave" RepositoryEventHandler s在进行任何验证之前就被解雇了。

我可以直接在处理程序中编写验证呼叫,但这与"验证后"的处理方式有所不同。

顺便说一句。事件处理程序呼叫的顺序似乎在Spring Boot 1.3.8和1.5.1之间发生了变化。过去,验证发生在@HandleBeforeSave处理程序之前。在1.5.1 ValidatingRepositoryEventListener fires 之后 @HandleBeforeSave处理程序。

更新:

如评论中所述,弹簧数据中似乎有一张票,静止jira对此开放。

作为解决方法:

  1. 创建PreflightValidatingRepositoryEventListener,该CC_7扩展ValidatingRepositoryEventListener并用@Order(Ordered.HIGHEST_PRECEDENCE)

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class PreflightValidatingRepositoryEventListener extends ValidatingRepositoryEventListener {
        public PreflightValidatingRepositoryEventListener(ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
            super(persistentEntitiesFactory);
        }
    }
    
  2. 添加与RepositoryEventHandler0

    相同的验证器
    @Configuration
    @Import(RepositoryRestMvcConfiguration.class)
    public class Config extends RepositoryRestConfigurerAdapter {
        @Bean
        @Primary
        public Validator validator() {
            return new LocalValidatorFactoryBean();
        }
        @Autowired
        private PreflightValidatingRepositoryEventListener preflightValidatingRepositoryEventListener;
        @Override
        public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
            Validator validator = validator();
            validatingListener.addValidator("beforeCreate", validator);
            validatingListener.addValidator("beforeSave", validator);
            preflightValidatingRepositoryEventListener.addValidator("beforeCreate", validator);
            preflightValidatingRepositoryEventListener.addValidator("beforeSave", validator);
        }
    }
    

注意:验证将进行两次

作为替代方法,这是基于此示例(次要更改)的完全验证方面。不要忘记添加@EnableAspectJAutoProxy激活该方面并将其放入扫描config的包装中。

@Aspect
@Component
public class RestRepositoryValidationAspect {
    @Autowired
    private Validator validator;
    @Pointcut("@annotation(org.springframework.data.rest.core.annotation.HandleBeforeCreate)")
    private void beforeCreateInvocation() {
    }
    @Pointcut("@annotation(org.springframework.data.rest.core.annotation.HandleBeforeSave)")
    private void beforeSaveInvocation() {
    }

    @Around("beforeCreateInvocation() || beforeSaveInvocation()")
    public Object validateBeforeRepostioryEventHandler(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Annotation[][] argAnnotations = method.getParameterAnnotations();
        String[] argNames = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
          if (hasValidAnnotations(argAnnotations[i])) {
            validateArg(args[i], argNames[i]);
          }
        }
        return joinPoint.proceed(args);
    }
    private boolean hasValidAnnotations(Annotation[] annotations) {
        if (annotations.length < 1) {
            return false;
        }
        for (Annotation annotation : annotations) {
            if (Valid.class.isInstance(annotation)) {
                return true;
            }
        }
        return false;
    }
    private void validateArg(Object arg, String argName) {
        BindingResult result = getBindingResult(arg, argName);
        validator.validate(arg, result);
        if (result.hasErrors()) {
            throw new RepositoryConstraintViolationException(result);
        }
    }
    private BindingResult getBindingResult(Object target, String targetName) {
        return new BeanPropertyBindingResult(target, targetName);
    }
}

必须用@Valid注释标记需要验证的存储库事件处理程序参数,例如

@HandleBeforeSave
public void handleSave(@Valid MyEntity myEntity) {
    ...
}

最新更新