【发布时间】:2020-06-07 10:51:31
【问题描述】:
我在 Internet 上找到了示例,但这并没有让我完全理解。 使用 WebFlux 时的标准 CRUD。
路由器:
@Configuration
public class PersonRouter {
@Bean
public RouterFunction<ServerResponse> route(PersonHandler handler) {
return RouterFunctions
.route(GET("/getAllPersons").and(accept(MediaType.APPLICATION_JSON)), handler::findAll)
.andRoute(GET("/getPerson/{id}").and(accept(MediaType.APPLICATION_STREAM_JSON)), handler::findById)
.andRoute(POST("/createPerson").and(accept(MediaType.APPLICATION_JSON)), handler::save)
.andRoute(DELETE("/deletePerson/{id}").and(accept(MediaType.APPLICATION_JSON)), handler::delete);
}
}
处理程序:
@Component
public class PersonHandler {
private final PersonService personService;
public PersonHandler(PersonService personService) {
this.personService = personService;
}
public Mono<ServerResponse> findById(ServerRequest request) {
String id = request.pathVariable("id");
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(personService.getById(id), Person.class);
}
public Mono<ServerResponse> findAll(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(personService.getAll(), Person.class);
}
public Mono<ServerResponse> save(ServerRequest request) {
final Mono<Person> person = request.bodyToMono(Person.class);
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(fromPublisher(person.flatMap(personService::save), Person.class));
}
public Mono<ServerResponse> delete(ServerRequest request) {
String id = request.pathVariable("id");
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(personService.delete(id), Void.class);
}
}
存储库:
@Repository
public interface PersonRepository extends ReactiveMongoRepository<Person, String> {
}
服务:
@Service
@Transactional
@AllArgsConstructor
public class PersonService {
private final PersonRepository personRepository;
public Flux<Person> getAll() {
return personRepository.findAll().switchIfEmpty(Flux.empty());
}
public Mono<Person> getById(final String id) {
return personRepository.findById(id);
}
public Mono update(final String id, final Person person) {
return personRepository.save(person);
}
public Mono save(final Person person) {
return personRepository.save(person);
}
public Mono delete(final String id) {
final Mono<Person> dbPerson = getById(id);
if (Objects.isNull(dbPerson)) {
return Mono.empty();
}
return getById(id).switchIfEmpty(Mono.empty()).filter(Objects::nonNull).flatMap(personToBeDeleted -> personRepository
.delete(personToBeDeleted).then(Mono.just(personToBeDeleted)));
}
}
我了解除了save 和update 方法之外的所有内容。我不明白为什么我们在这种情况下使用flatMap。
为什么会这样,如何在我的 Handler 中编写 update 方法的实现。
更新
我们看一下Handler中的save()方法
public Mono<ServerResponse> save(ServerRequest request) {
final Mono<Person> person = request.bodyToMono(Person.class);
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(fromPublisher(person.flatMap(personService::save), Person.class));
}
我认为事实是我们已经收到了:
final Mono<Person> person = request.bodyToMono(Person.class);
然后我们做:
personService::save
结果,我们得到 Mono>
flatMap 就像 map 一样,除了它会解包给定的 lambda 的返回值,如果该值本身包含在 Publisher<T> 中。在我们的例子中,personService.save(T) 方法返回一个Mono<T>。如果我们使用 map 而不是flatMap(T),我们将有一个Mono< Mono< T>>,而我们真正想要的是Mono<T>。我们可以使用 flatMap 彻底解决这个问题。
我是对的还是这个说法是错的?
【问题讨论】:
-
您的更新评论完全正确,您可以将其添加为自我回答;)
-
谢谢!请帮助我理解为什么我需要使用 .body(fromPublisher) ?谢谢
-
WebFlux 完全是非阻塞的。它首先发送标头,然后能够发送尚未完全“计算”的主体,通过将块发送到远程客户端,因为相应的数据由您传递给
Publisher的Publisher方法生成和发出/跨度> -
感谢您的回答!也许你可以给我链接来阅读这部分?我的意思是.body(来自Publisher)。谢谢
标签: crud spring-webflux project-reactor reactor spring5