Как объединить Flux и ResponseEntity в контроллерах Spring Webflux - PullRequest
0 голосов
/ 25 сентября 2018

Я использую Mono s с ResponseEntity s в моих контроллерах Webflux для манипулирования заголовками и другой информацией ответа.Например:

@GetMapping("/{userId}")
fun getOneUser(@PathVariable userId: UserId): Mono<ResponseEntity<UserDto>> {
    return repository.findById(userId)
        .map(User::asDto)
        .map { ResponseEntity.ok(it) }
        .defaultIfEmpty(ResponseEntity.notFound().build())
}

@GetMapping
fun getAllUsers(): Flux<UserDto> {
    return repository.findAllActive().map(User::asDto)
}

оба работают нормально, но есть случаи, когда необходимо иметь ResponseEntity в сочетании с Flux.Каким должен быть тип ответа?Правильно ли использовать ResponseEntity<Flux<T>>?

Например:

@GetMapping("/{userId}/options")
fun getAllUserOptions(@PathVariable userId: UserId): ??? {
    return repository.findById(userId)
        .flatMapIterable{ it.options }
        .map { OptionDto.from(it) }
        // if findById -> empty Mono then:
        //   return ResponseEntity.notFound().build() ?
        // else:
        //   return the result of `.map { OptionDto.from(it) }` ?
}

Поведение, которое я хотел бы достичь, заключается в том, что getAllUserOptions возвращает 404, если repository.findById(userId) является пустым Mono, в противном случае возвращает user.optionsas Flux.

Обновление: репозиторий здесь ReactiveCrudRepository

Ответы [ 2 ]

0 голосов
/ 20 января 2019

Вы можете использовать, возвращая Mono с ResponseEntity

, как это

public Mono<ResponseEntity<?>> oneRawImage(
        @PathVariable String filename) {
        // tag::try-catch[]
        return imageService.findOneImage(filename)
            .map(resource -> {
                try {
                    return ResponseEntity.ok()
                        .contentLength(resource.contentLength())
                        .body(new InputStreamResource(
                            resource.getInputStream()));
                } catch (IOException e) {
                    return ResponseEntity.badRequest()
                        .body("Couldn't find " + filename +
                            " => " + e.getMessage());
                }
            });         
    }

У меня также есть пример, подобный этому

  public ResponseEntity<Mono<?>>  newLive(@Valid @RequestBody Life life) {
        Mono<Life> savedLive = liveRepository.save(life);
        if (savedLive != null) {
            return new ResponseEntity<>(savedLive, HttpStatus.CREATED);
        }
        return new ResponseEntity<>(Mono.just(new Life()), HttpStatus.I_AM_A_TEAPOT);
    }

Мне не нравится функциональное программирование в RESTконтроллеры.

Вот пример ReactiveController .

0 голосов
/ 25 сентября 2018

Используйте switchIfEmpty, чтобы вызвать исключение в случае, если пользователя не существует:

return repository
    .findById(userId)
    .switchIfEmpty(Mono.error(NotFoundException("User not found")))
    .flatMapIterable{ it.options }
    .map { OptionDto.from(it) }

Затем с помощью обработчика исключений преобразовать его в ответ 404.

...