Карта против FlatMap в Spring Web Flux и Reactor - PullRequest
0 голосов
/ 28 апреля 2018

Я работал над образцом реактивного веб-API с использованием Spring Boot 2.0.1 и его библиотеки Webflux. Я искал примеры из интернета, чтобы попытаться создать его, но я нахожусь в тупике на две вещи. Ниже приведены два вопроса, которые у меня есть.

1) Как вернуть поток объектов ответа, когда я пытаюсь получить сообщение о том, что может быть возвращен только один объект ответа. Ниже мой текущий код.

@Service
public class MovieServiceImpl implements MovieService {

    @Autowired
    private MovieRepository movieRepository;

    @Override
    public Flux<Movie> list(){
        return movieRepository.findAll();
    }
}

@RestController
public class MovieRestController {

    @Autowired
    private MovieService movieService;

    @GetMapping(value = "/movies")
    public Flux<Movie> list() {

        return movieService.list();
    }
}

2) Когда я обновляю объект, я использую flatMap для обновления объекта, сохраненного в Mongo, а затем карту, чтобы превратить его в объект ответа. У меня вопрос, почему я использую здесь FlatMap вместо карты? Я получил этот код из онлайн-примеров, но ни один пример не объяснил использование flatMap. Я хотел бы понять, почему это используется здесь. Ниже приведен код.

@Service
public class MovieServiceImpl implements MovieService {

    @Autowired
    private MovieRepository movieRepository;

    @Override
    public Mono<Movie> update(String id, MovieRequest movieRequest) {

       return movieRepository.findById(id).flatMap(existingMovie -> {

           if(movieRequest.getDescription() != null){
               existingMovie.setDescription(movieRequest.getDescription());
           }
           if(movieRequest.getRating() != null){
               existingMovie.setRating(movieRequest.getRating());
           }
           if(movieRequest.getTitle() != null) {
               existingMovie.setTitle(movieRequest.getTitle());
           }

           return movieRepository.save(existingMovie);

       });
    }
}

@RestController
public class MovieRestController {

    @Autowired
    private MovieService movieService;

    @PutMapping("/movies/{movieId}")
    public Mono<ResponseEntity<Movie>> update(
            @PathVariable("movieId") final String movieId,
            @RequestBody final MovieRequest movieRequest) {

        return movieService.update(movieId, movieRequest)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));

    }
}

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

карта:

@PutMapping(path="/update/{id}", consumes=MediaType.APPLICATION_JSON_VALUE)
public Mono<Account> update(@PathVariable Long id, @RequestBody Account account) {
    Mono<Account> accFound = accountRepository.findById(id);
    return accFound.map(acc -> {
        acc.setAccountBalance(account.getAccountBalance());
        return accountRepository.save(acc).block();
        });

}

map добавляет Mono к тому, что возвращается внутри, обратите внимание, здесь accountRepository.save(acc) возвращает Mono, и если я не добавлю block(), метод update в конечном итоге возвращает Mono<Mono<Account>> - ошибка компиляции в этом случае.

flatMap:

@PutMapping(path="/update/{id}", consumes=MediaType.APPLICATION_JSON_VALUE)
public Mono<Account> update(@PathVariable Long id, @RequestBody Account account) {
    Mono<Account> accFound = accountRepository.findById(id);
    return accFound.flatMap(acc -> {
        acc.setAccountBalance(account.getAccountBalance());
        return accountRepository.save(acc);
        });

}

flatMap просто возвращает все, что возвращается внутрь.

Надеюсь, это поможет понять это очень просто

0 голосов
/ 29 апреля 2018
  1. Ответ HTTP-запроса является уникальным. Все, что вы можете сделать, это отправить Flux или Mono в качестве тела ответа и использовать заголовок Content-Type, чтобы сообщить клиенту, что он может быть использован как поток application/stream+json или как обычный * 1007. *.

  2. Оба findById(id) и movieRepository.save(existingMovie) возвращают Mono<Movie>. Если вы отобразите его, каждое событие Movie, переданное на карту, вернет Mono<Movie>, поэтому конкатенация findById().map(movieRepository.save()) заканчивается Mono<Mono<Movie>>. Когда вы отображаете плоскую карту, вы в основном «объединяете» всех издателей с карты в один Mono.

...