響應式編程範式爲開發高性能 Web 應用帶來了新的機會和挑戰。Spring 5 中的 WebFlux 模塊可以作爲開發響應式 Web 應用的基礎。由於 Spring 框架的流行,WebFlux 會成爲開發 Web 應用的重要趨勢之一。
在上一節中我們對WebFlux進行了介紹並且使用WebFlux開發了一個極其簡單的接口,接下來展示更多關於WebFlux 的用法
- 新建一個UserController.java
@RestController
@RequestMapping("/user")
public class UserController {
private final UserService userService;
@Autowired
public UserController(final UserService userService) {
this.userService = userService;
}
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Resource not found")
@ExceptionHandler(ResourceNotFoundException.class)
public void notFound() {
}
@GetMapping("")
public Flux<User> list() {
return this.userService.list();
}
@GetMapping("/{id}")
public Mono<User> getById(@PathVariable("id") final String id) {
return this.userService.getById(id);
}
@PostMapping("")
public Mono<User> create(@RequestBody final User user) {
return this.userService.createOrUpdate(user);
}
@PutMapping("/{id}")
public Mono<User> update(@PathVariable("id") final String id, @RequestBody final User user) {
Objects.requireNonNull(user);
user.setId(id);
return this.userService.createOrUpdate(user);
}
@DeleteMapping("/{id}")
public Mono<User> delete(@PathVariable("id") final String id) {
return this.userService.delete(id);
}
}
- 新建UserService.java
@Service
public class UserService {
private final Map<String, User> data = new ConcurrentHashMap<>();
public Flux<User> list() {
return Flux.fromIterable(this.data.values());
}
public Flux<User> getById(final Flux<String> ids) {
return ids.flatMap(id -> Mono.justOrEmpty(this.data.get(id)));
}
public Mono<User> getById(final String id) {
return Mono.justOrEmpty(this.data.get(id))
.switchIfEmpty(Mono.error(new ResourceNotFoundException()));
}
public Mono<User> createOrUpdate(final User user) {
this.data.put(user.getId(), user);
return Mono.just(user);
}
public Mono<User> delete(final String id) {
return Mono.justOrEmpty(this.data.remove(id));
}
public void fromStream () {
SortedMap<String, Charset> charSetMap = Charset.availableCharsets();
Stream<String> charSetStream = charSetMap.keySet().stream();
Flux<String> charsetFlux = Flux.fromStream(charSetStream);
charsetFlux.subscribe(System.out::println);
}
public void range() {
Flux.range(1, 5).subscribe(System.out::println);
// 溢出
Flux.range(Integer.MAX_VALUE, 5).subscribe(System.out::println);
}
}
以上代碼使用Map完成了關於用戶的增刪改查操作。這也是我們在項目中運用最多的操作。如果只是想要在完成時給出完成信號,就可以使用 Mono<Void>。
接下來對service中用到的一些方法進行講解:
justOrEmpty|just
這個方法比較簡單,直接將參數傳進方法然後返回。justOrEmpty只是比just多了一個判空操作,防止空指針。Flux.fromIterable:fromIteratble方法使用接收到的Iterable對象構造Flux流,數據返回的順序和Iterable的next方法返回數據的順序一致。如下例子中使用fromIteratble構造了JVM支持的字符集的Flux流。
fromSteam方法:
Flux數據流同樣可以使用java.util.stream.Stream對象構造出來,數據返回的順序和Stream.iterator()方法返回的Iterable對象的next方法返回數據的順序一致。如代碼中fromSteam方法使用fromSteam構造了JVM支持的字符集的Flux流。range
range(int start, int count)構造了一個Flux<Integer>流,返回從 [start,start+count) 區間的整數。如果該方法有類似於range(int start, int step,int count)的重載就更完美了。注意,range方法會處理整數溢出的場景,在溢出時拋出異常。empty:方法返回一個沒有任何數據、異常的流。
error:方法返回一個沒有任何數據,只有異常的流程。
never:方法返回一個不會發送任何通知額流程。
以上三個流都會觸發Subscriber的onSubscribe回調,都不會觸發onNext回調。同時empty流會觸發onComplete回調,error流會觸發onError回調。never方法只觸發Subscriber的onSubscribe回調,不會觸發其他任何回調。
當然WebFlux還有更多高級的用法。