当前位置: 首页 > 知识库问答 >
问题:

将验证纳入项目反应器的反应链中

谷永贞
2023-03-14

我想组成一个Reactor链,基本上可以做到以下几点:

  1. 验证提交的User属性,例如firstNamelastName的长度或email的有效性。我会使用下面的验证器。
  2. 验证提交的电子邮件是否已被其他人使用。为此,我将使用反应性存储库。
  3. 保存User,如果以上所有验证检查都通过。

用户:

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Id
    private Integer id;
    private String firstName;
    private String lastName;
    private String email;
}

反应性存储库:

public interface UserRepository extends ReactiveCrudRepository<User, Long> {

    @Query("select id, first_name, last_name, email from user u where u.email = :email")
    Mono<User> findByEmail(String email);
}

验证器:

@Component
public class UserValidator implements Validator {

    private final static String EMAIL = "email";
    private static final String FIRST_NAME = "firstName";
    private static final String LAST_NAME = "lastName";

    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        User user = (User) target;

        rejectIfEmptyOrWhitespace(errors, EMAIL, "email.required");
        rejectIfEmptyOrWhitespace(errors, FIRST_NAME, "firstName.required");
        rejectIfEmptyOrWhitespace(errors, LAST_NAME, "lastName.required");

        validateFirstName(errors, user.getFirstName());
        validateLastName(errors, user.getLastName());
        validateEmail(errors, user.getEmail());
    }

    private void validateEmail(Errors errors, String email) {
        EmailValidator emailValidator = EmailValidator.getInstance();
        if (!emailValidator.isValid(email)) {
            errors.rejectValue(EMAIL, "email.invalid");
        }
    }

    private void validateFirstName(Errors errors, String firstName) {
        if (firstName.length() < 2) {
            errors.rejectValue(FIRST_NAME, "firstName.min");
        }
    }

    private void validateLastName(Errors errors, String lastName) {
        if (lastName.length() < 2) {
            errors.rejectValue(LAST_NAME, "lastName.min");
        }
    }
}

处理程序方法:

public Mono<ServerResponse> saveUser(ServerRequest serverRequest) {
    return serverRequest.bodyToMono(User.class)
        // Use validator here
        .flatMap(this::createUserIfEmailNotExists);
}

助手方法:

private Mono<ServerResponse> createUserIfEmailNotExists(User user) {
    return userRepository.findByEmail(user.getEmail())
        .flatMap(existingUser ->
            status(BAD_REQUEST).contentType(APPLICATION_JSON)
                .body(BodyInserters.fromObject("User already exists."))
        )
        .switchIfEmpty(
            userRepository.save(user)
                .flatMap(newUser -> status(CREATED).contentType(APPLICATION_JSON)
                    .body(BodyInserters.fromObject(newUser)))
        );
}

从被动的角度来看,我不确定如何实现这一目标。理想情况下,反应链将有3个步骤映射到上面的点。

这是我尝试过的,但我在方法参数和返回类型破坏序列流方面遇到了问题。。。

private Mono<ServerResponse> validateUser(User user) {
    Errors errors = new BeanPropertyBindingResult(user, User.class.getName());
    userValidator.validate(user, errors);
    if (errors.hasErrors()) {
        return status(BAD_REQUEST).contentType(APPLICATION_JSON)
            .body(BodyInserters.fromObject(errors.getAllErrors()));
    } else {
        return Mono.empty();
    }
}

有人能帮忙吗?

共有1个答案

祖迪
2023-03-14

这样怎么样?

private Mono<ServerResponse> validateUser(User user) {
    return Mono.just(new BeanPropertyBindingResult(user, User.class.getName()))
        .doOnNext(err -> userValidator.validate(user, err))
        .filter(AbstractBindingResult::hasErrors)
        .flatMap(err ->
            status(BAD_REQUEST)
                .contentType(APPLICATION_JSON)
                .body(BodyInserters.fromObject(err.getAllErrors()))
        );
}

private Mono<ServerResponse> createUserIfEmailNotExists(User user) {
    return userRepository.findByEmail(user.getEmail())
        .flatMap(existingUser ->
            status(BAD_REQUEST).contentType(APPLICATION_JSON)
                .body(BodyInserters.fromObject("User already exists."))
        )
        .switchIfEmpty(
            validateUser(user)
                .switchIfEmpty(
                    userRepository.save(user)
                        .flatMap(newUser -> status(CREATED).contentType(APPLICATION_JSON)
                            .body(BodyInserters.fromObject(newUser)))
                )
        );
}
 类似资料:
  • 我本可以使用而不是第二个,因为它不映射任何东西,但我不确定这是否是peek方法的可接受用法。 我也可以在第二个中使用一个有状态映射器来只运行一次,而不是用索引压缩,我想这是可以接受的,因为我已经使用了一个有状态谓词...

  • 我试图用一个自定义验证器将整个设置为无效,这似乎不起作用。。。 下面代码的目标是比较FromGroup的两个实例。 如果它们匹配,则表示未进行任何更改,因此必须无效。 否则它不匹配,这意味着已经进行了更改,所以它必须是有效的 我的变量在我记录时工作正常。它会根据变化变为真或假。 但是我无法使from无效,我已经尝试了很多方法,比如文章和堆栈溢出,这有一个stackblitz,但它似乎也不起作用。

  • 我是一个新的基于项目反应器的反应式框架,比如SpringWebFlux,对此我有一些问题。 问题1: 例1: 例2: 两个示例之间是否存在差异,或者两者都可以接受。 问题二: 例1: 例2: 第二个问题很奇怪,我知道,但我想知道所有的方法都应该返回单声道或通量,或者我可以像问题2/示例1一样使用。

  • 我收到了react-nate-icons的构建错误。我从他们的github站点的安装说明中执行了链接命令。消息说图标已经链接到项目。 ld /Users/rsanchez/Library/Developer/Xcode/DerivedData/NativeStarter-ddtqngxgxoergggtejjrwdqafazh/Build/Products/Debug-iphonesimulato

  • 我在用一个垂直的图书馆。返回项目Reactor类型Mono的x应用程序。 我有一个verticle,它接收这种反应类型,并打算通过事件总线将内容发送到另一个verticle: 这是正确的方法吗?我应该换成垂直吗。在将消息发送到事件总线之前,x事件循环线程池?在一起使用这些库时,有什么我应该注意的吗?

  • 因此,我从文档中了解到,并行通量本质上是将通量元素划分为单独的轨道。(本质上类似于分组)。就线程而言,这将是调度程序的工作。让我们考虑一下这样的情况。所有这些都将在通过runOn()方法提供的同一个调度程序实例上运行。让我们考虑如下情况: 现在让我们打大约100个电话 如果我们使用parailFlux: 因此,如果我的理解是正确的,那么它似乎非常相似。那么,平行磁通相对于磁通的优势是什么?什么时候