source

Mono가 비어있는지 확인하는 방법은?

manysource 2023. 10. 17. 20:22

Mono가 비어있는지 확인하는 방법은?

저는 웹 플럭스 프레임워크를 이용하여 스프링부트 2.0과 코틀린이 적용된 앱을 개발하고 있습니다.

트랜잭션을 저장하기 전에 사용자 ID가 종료되는지 확인하고 싶습니다.모노가 비어있는지 확인하는 것 같은 간단한 일에 갇혀있습니다.

fun createTransaction(serverRequest: ServerRequest) : Mono<ServerResponse> {
    val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java))

    transaction.flatMap {
        val user = userRepository.findById(it.userId)
        // If it's empty, return badRequest() 
    } 

    return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }
}

내가 원하는 것을 할 수 있습니까?

다음을 확인할 수 있는 기술은Flux/Mono비어있습니다

연산자 사용.switchIfEmpty/.defaultIfEmpty/Mono.repeatWhenEmpty

위에 언급된 연산자를 사용하면 Stream이 완료되었을 때 어떠한 요소도 방출하지 않고 대응할 수 있습니다.

우선, 운영자들은 다음과 같은.map,.flatMap,.filter그리고 만약 그렇지 않다면 다른 많은 사람들은 전혀 호출되지 않을 것입니다.onNext호출되었습니다.그 말은 당신의 경우엔 다음 코드가

transaction.flatMap {
    val user = userRepository.findById(it.userId)
    // If it's empty, return badRequest() 
} 

return transaction.flatMap { transactionRepository.save(it).then(created(URI.create("/transaction/" + it.id)).build()) }

비어 있으면 전혀 호출되지 않습니다.

흐름이 비어 있을 때 사례를 처리해야 하는 요구 사항이 있는 경우 다음과 같은 연산자를 다음과 같이 고려해야 합니다.

transaction
   .flatMap(it -> {
      val user = userRepository.findById(it.userId)
   })
   .swithIfEmpty(Flux.defer(() -> Flux.just(badRequest())));

실해

또한 메인에서 2개의 서브 플로우를 생성한 것에 주목했습니다.transaction. 실제로 다음 코드는 전혀 실행되지 않습니다.

transaction.flatMap {
    val user = userRepository.findById(it.userId)
    // If it's empty, return badRequest() 
}  

메소드에서 반환되는 마지막 하나만 실행됩니다.오퍼레이터를 사용하여 가입하지 않았기 때문에 발생하는 일입니다..subscribe(...).

두 번째 사항은 동일한 요청 기관을 한 번 이상 구독할 수 없다는 것입니다(일종의 제한 사항).WebClient의 응답).따라서 다음 방법으로 요청 본문을 공유해야 하므로 완료된 예는 다음과 같습니다.

fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
    val transaction = serverRequest.body(BodyExtractors.toMono(Transaction::class.java)).cache()

    transaction
            .flatMap { userRepository.findById(it.userId) }
            .flatMap { transaction.flatMap { transactionRepository.save(it) } }
            .flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
            .switchIfEmpty(transaction.flatMap { ServerResponse.badRequest().syncBody("missed User for transaction " + it.id) })
}

또는 트랜잭션 흐름을 공유하지 않고 다음을 사용하는 보다 간단한 경우Tuple:

fun createTransaction(serverRequest: ServerRequest): Mono<ServerResponse> {
    val emptyUser = !User()
    val transaction = serverRequest.body<Mono<Transaction>>(BodyExtractors.toMono(Transaction::class.java))

    transaction
            .flatMap { t ->
                userRepository.findById(t.userId)
                        .map { Tuples.of(t, it) }
                        .defaultIfEmpty(Tuples.of(t, emptyUser))
            }
            .flatMap {
                if (it.t2 != emptyUser) {
                    transactionRepository.save(it.t1)
                            .flatMap { ServerResponse.created(URI.create("/transaction/" + it.id)).build() }
                } else {
                    ServerResponse.badRequest().syncBody("missed User for transaction " + it.t1.id)
                }
            }
}

Mono에서 제공하는 메서드 hasElement()를 사용하여 확인할 수 있으며, 이는 Optional의 isPresent()와 유사합니다.메소드 정의는 다음과 같습니다.

Mono<Boolean> hasElement()

자세한 사항 확인 : 프로젝트 원자로 문서

이 값을 기준으로 일부 작업을 수행해야 하는 경우 switchIfEmpty()를 사용하여 대체 게시자를 제공할 수 있습니다.

먼저 저는 반응형(자바)과 이 포럼에 대해 초보자라고 말씀드리겠습니다.모노가 나중에 실행될 코드를 나타내기 때문에 모노가 비어 있으면 이 코드를 체크인할 수 없다고 생각합니다. 그래서 이 코드 본문에서는 아직 비어 있는지 여부를 알 수 없습니다.이해 하셨나요?

저는 방금 자바에서 작동하는 것처럼 보이는 비슷한 것을 썼습니다. (그러나 100% 이것이 최선의 접근법은 아닙니다.)

    public Mono<ServerResponse> queryStore(ServerRequest request) { 

        Optional<String> postalCode = request.queryParam("postalCode");                            

        Mono<ServerResponse> badQuery = ServerResponse.badRequest().build();
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();

        if (!postalCode.isPresent()) { return  badQuery; }

        Flux<Store> stores = this.repository
                .getNearByStores(postalCode.get(), 5);

        return ServerResponse.ok().contentType(APPLICATION_JSON)
                .body(stores, Store.class)
                .switchIfEmpty(notFound);
}

옵션과 함께 Mono 사용:

return findExistingUserMono
  .map(Optional::of)
  .defaultIfEmpty(Optional.empty())
  .flatMap(optionalUser -> {
    if(optionalUser.isPresent()) {
      return Mono.error('xxxx');
    }
    return this.userService.create(optionalUser.get());
  });

이렇게 하면 스트림이 끊어지지 않도록 항상 Optional 값을 내보냅니다.

switchIfEmpty 메서드를 사용할 수 있습니다.

아래 예제에서는 사용자가 이메일과 함께 존재하는지 확인한 후 추가합니다.

userRepository.findByEmail(user.getEmail())
                .switchIfEmpty(s -> {
                    user.setStatus("InActive");
                    String encodedPassword = DigestUtils.sha256Hex(user.getPassword());
                    user.setPassword(encodedPassword);
                    userRepository.save(user).subscribe();
                    s.onComplete();
                }).then(Mono.just(user));

언급URL : https://stackoverflow.com/questions/47242335/how-to-check-if-mono-is-empty