Spring Web Flux 和 Reactor 中的 Map 与 FlatMap
Map vs FlatMap in Spring Web Flux and Reactor
我一直在使用 Spring Boot 2.0.1 及其 Webflux 库开发示例反应式 Web api。我一直在查看在线示例以尝试构建它,但我对两件事感到困惑。下面是我的两个问题。
1) 如何 return 响应实体的通量,当我尝试时,我收到一条错误消息,指出只能 returned。下面是我当前的代码。
@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));
}
}
HTTP 请求的响应是唯一的。您所能做的就是发送 Flux
或 Mono
作为响应的 body 并使用 Content-Type
header 让客户端知道它可以将其作为流 application/stream+json
或通常的 application/json
.
使用
findById(id)
和 movieRepository.save(existingMovie)
return Mono<Movie>
。如果你映射它,传递给映射的每个事件 Movie
将 return 一个 Mono<Movie>
所以 findById().map(movieRepository.save())
的串联以 Mono<Mono<Movie>>
结束。当您使用平面地图时,您基本上 "merging" 地图中的所有发布者都变成了一个 Mono
.
地图:
@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)
returns 一个 Mono
,如果我不添加 [=16] =],方法 update
最终返回 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);
});
}
flatMap
只是 returns 里面返回的任何东西。
希望以一种非常基本的方式帮助理解它
我一直在使用 Spring Boot 2.0.1 及其 Webflux 库开发示例反应式 Web api。我一直在查看在线示例以尝试构建它,但我对两件事感到困惑。下面是我的两个问题。
1) 如何 return 响应实体的通量,当我尝试时,我收到一条错误消息,指出只能 returned。下面是我当前的代码。
@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));
}
}
HTTP 请求的响应是唯一的。您所能做的就是发送
Flux
或Mono
作为响应的 body 并使用Content-Type
header 让客户端知道它可以将其作为流application/stream+json
或通常的application/json
. 使用
findById(id)
和movieRepository.save(existingMovie)
returnMono<Movie>
。如果你映射它,传递给映射的每个事件Movie
将 return 一个Mono<Movie>
所以findById().map(movieRepository.save())
的串联以Mono<Mono<Movie>>
结束。当您使用平面地图时,您基本上 "merging" 地图中的所有发布者都变成了一个Mono
.
地图:
@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)
returns 一个 Mono
,如果我不添加 [=16] =],方法 update
最终返回 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);
});
}
flatMap
只是 returns 里面返回的任何东西。
希望以一种非常基本的方式帮助理解它