Spring Web Flux和Reactor中的Map vs FlatMap

时间:2018-04-28 19:38:51

标签: spring-webflux

我一直在使用Spring Boot 2.0.1及其Webflux库开发示例反应式web api。我一直在寻找网上的例子来尝试构建它,但我对两件事感到难过。以下是我的两个问题。

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中保存的对象,然后使用Map将其转换为响应实体。我的问题是为什么我在这里使用flatMap而不是map?我从在线示例中获取了此代码,但没有示例解释使用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 :(得分:2)

  1. HTTP请求的响应是唯一的。您所能做的就是发送FluxMono作为响应正文,并使用Content-Type标头让客户端知道它可以作为流使用它{{ 1}}或通常的application/stream+json

  2. application/jsonfindById(id)都返回movieRepository.save(existingMovie)。如果您对其进行映射,则传递到地图的每个事件Mono<Movie>都会返回Movie,因此Mono<Movie>的连接最终会以findById().map(movieRepository.save())结尾。当你平面映射你基本上&#34;合并&#34;地图中的所有发布商都只有一个Mono<Mono<Movie>>

答案 1 :(得分:0)

地图:

@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(),则方法{ {1}}最终返回update -在这种情况下会编译错误。

flatMap:

Mono<Mono<Account>>

@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); }); } 仅返回内部返回的任何内容。

希望它有助于以一种非常基本的方式理解它