如何在使用反应性数据源的WebFlux上编写自定义验证器

时间:2018-07-12 08:09:46

标签: spring spring-data-mongodb spring-webflux project-reactor

在Spring MVC中,我有一个@UniqueEmail自定义休眠验证器(用于在注册时检查电子邮件的唯一性),如下所示:

public class UniqueEmailValidator
implements ConstraintValidator<UniqueEmail, String> {

    private UserRepository userRepository;

    public UniqueEmailValidator(UserRepository userRepository) {

        this.userRepository = userRepository;
    }

    @Override
    public boolean isValid(String email, ConstraintValidatorContext context) {

        return !userRepository.findByEmail(email).isPresent();
    }
}

现在,我要使用反应性MongoDB迁移到WebFlux,代码如下:

public class UniqueEmailValidator
implements ConstraintValidator<UniqueEmail, String> {

    private MongoUserRepository userRepository;

    public UniqueEmailValidator(MongoUserRepository userRepository) {

        this.userRepository = userRepository;
    }

    @Override
    public boolean isValid(String email, ConstraintValidatorContext context) {

        return userRepository.findByEmail(email).block() == null;
    }
}

首先,如上所述使用block看起来并不好。其次,它不起作用,这是错误:

Caused by: java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3

该如何处理?我当然可以使用MongoTemplate阻止方法,但是有没有办法应对这种情况?我可以在服务方法中手动进行操作,但希望将此错误与其他错误(例如“短”密码)一起显示给用户。

2 个答案:

答案 0 :(得分:0)

As of Reactor 3.2.0, using blocking APIs inside a parallel or single Scheduler is forbidden并引发您所看到的异常。因此,当您说它看起来不好时,您就说对了–不仅对您的应用程序真的很不好(它可能阻止对新请求的处理,并使整个过程崩溃),而且如此糟糕,以至于Reactor团队决定认为这是一个错误。

现在的问题是,您想在isValid调用中完成一些与I / O相关的工作。该方法的完整签名是:

boolean isValid(T value, ConstraintValidatorContext context)

签名表明它正在阻塞(它不返回响应类型,也不提供结果作为回调)。因此,您不允许在其中进行与I / O相关的工作或涉及延迟的工作。在这里,您要对照数据库检查条目,该条目恰好属于该类别。

我不认为您可以在此验证合同中做到这一点,而且我不知道有任何其他选择。

答案 1 :(得分:0)

我遇到了同样的问题,最后我决定使用 ConstraintValidator 检查简单的验证,并检查响应式应用程序逻辑中的响应式验证。我不知道是否有其他更好的解决方案,但它可能是一个不错的方法。