经过上一个范例的练习,也大致上的知道相较於原本Spring MVC
annotation-based,Spring WebFlux
更倾向使用更Functional的Handler
&Route
,难道这样就够了吗?
很显然这样的练习连小专案都不算,所以接下来介绍进阶一点点,开始有了CRUD,常常戏称CRUD工程师,就是要从CRUD学起。
首先下方有一个很基本的RestController
,有GET
、POST
,有PathVariable
、RequestBody
,最上方也有RequestMapping
能够统一路径,这次就来把他改写为Router
+ Handler
模式。
@RestController
@RequestMapping("/mvc/greeting")
@RequiredArgsConstructor
public class GreetingController {
private final GreetingRepository repository;
@GetMapping
public Flux<Greeting> allPeople() {
return this.repository.allGreeting();
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public Mono<Void> saveGreeting(@RequestBody Mono<Greeting> greetingMono) {
return this.repository.saveGreeting(greetingMono);
}
@GetMapping("/{id}")
public Mono<Greeting> getGreeting(@PathVariable int id) {
return this.repository.getGreeting(id);
}
}
第一步先将逻辑的部份抽到Handler
中,因为不能确定何时才会将资料回传,所以回传ServerResponse
都会加上Reactive的Mono
or Flux
,Body里面要提供type class是因为Flux的资料不是马上就会存在,而是随着时间传入,也就是第一时间是没办法知道里面的资料型态,所以我们要提前先指定好传入。
public Mono<ServerResponse> allGreeting(ServerRequest request) {
Flux<Greeting> greetingFlux = this.repository.allGreeting();
return ServerResponse.ok().contentType(APPLICATION_JSON).body(greetingFlux, Greeting.class);
}
这边的bodyToMono
,就是之前spring mvc
中 @RequestBody
直接将Body
转成物件,这边一样预设是透过jackson
。
public Mono<ServerResponse> saveGreeting(ServerRequest request) {
Mono<Greeting> greetingMono = request.bodyToMono(Greeting.class);
return ServerResponse.ok().build(this.repository.saveGreeting(greetingMono));
}
将@PathVariable
取代掉,参考上面的结果很直觉就可以写出下面的程序码,但是当传入一个不存在的ID,仍回传两百,如果想要回传404则须调整作法,也就是现在会有两种ServerResponse
,一种正常回传两百,一种找不到回传404,根据传统的直觉你可就直接if
else
或是三元,但在Reactive的世界中,程序执行的当下很有可能是还没有资料进来的,也就是永远只回传404,如果你停下来等待结果,则又走回了blocking的老路。
public Mono<ServerResponse> getGreeting(ServerRequest request) {
int id = Integer.parseInt(request.pathVariable("id"));
Mono<Greeting> greetingMono = this.repository.getGreeting(id);
//Mono<ServerResponse> build = ServerResponse.notFound().build();
return ServerResponse.ok().contentType(APPLICATION_JSON).body(greetingMono, Greeting.class);
}
这时候Reactor有提供switchIfEmpty
让你可以很灵活很Functional
的判断。
public Mono<ServerResponse> getGreeting(ServerRequest request) {
int id = Integer.parseInt(request.pathVariable("id"));
Mono<Greeting> greetingMono = this.repository.getGreeting(id);
return greetingMono
.flatMap(greeting -> ServerResponse.ok().contentType(APPLICATION_JSON).body(
BodyInserters.fromValue(greeting)))
.switchIfEmpty(ServerResponse.notFound().build());
}
最後成果如下,下一篇来介绍Router
@Component
@RequiredArgsConstructor
public class GreetingHandler {
private final GreetingRepository repository;
public Mono<ServerResponse> hello(ServerRequest request) {
return ServerResponse.ok().contentType(APPLICATION_JSON)
.body(BodyInserters.fromValue(new Greeting("Hello, Spring!")));
}
public Mono<ServerResponse> getGreeting(ServerRequest request) {
int id = Integer.parseInt(request.pathVariable("id"));
Mono<Greeting> greetingMono = this.repository.getGreeting(id);
return greetingMono
.flatMap(greeting -> ServerResponse.ok().contentType(APPLICATION_JSON).body(
BodyInserters.fromValue(greeting)))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> saveGreeting(ServerRequest request) {
Mono<Greeting> greetingMono = request.bodyToMono(Greeting.class);
return ServerResponse.ok().build(this.repository.saveGreeting(greetingMono));
}
public Mono<ServerResponse> allGreeting(ServerRequest request) {
Flux<Greeting> greetingFlux = this.repository.allGreeting();
return ServerResponse.ok().contentType(APPLICATION_JSON).body(greetingFlux, Greeting.class);
}
}
感觉得出来Spring想尽办法降低原本使用Spring Mvc的开发者学习Spring WebFlux的门槛。
<<: [NestJS 带你飞!] DAY22 - MongoDB
API Application Programming Interface的缩写,主要在I,一个接口...
写入档案 写入空文件内 档案很大时分段写入 Shutil模组 档案或目录的复制、移动、更改和删除,...
系统映像是Windows作业系统平稳运行所需的磁碟机副本。如果您的PC的HDD或SSD出现故障,则可...
我们人类是视觉的动物,因此在面对非常大量的资料的时候有一个合适、快速、有效的视觉化方法绝对是非常有必...
今天要学习的是如何新增和删除资料夹,一样是用昨天的 fs modules,不过在新增资料夹之前,先来...