doc: 阅读webflux文档

This commit is contained in:
asahi
2025-03-14 01:23:59 +08:00
parent be52af362d
commit 79c4982792

View File

@@ -41,6 +41,13 @@
- [Server Request](#server-request)
- [ServerResponse](#serverresponse)
- [Handler Class](#handler-class)
- [Validation](#validation)
- [RouterFunction](#routerfunction)
- [Predicates](#predicates)
- [Routes](#routes)
- [Nested Routes](#nested-routes)
- [Resource Redirect](#resource-redirect)
- [Filter Handler Functions](#filter-handler-functions)
# Spring Webflux
@@ -625,6 +632,155 @@ HandlerFunction<ServerResponse> helloWorld =
request -> ServerResponse.ok().bodyValue("Hello World");
```
### Validation
如果想要对请求体进行校验,可以使用如下逻辑:
```java
public class PersonHandler {
private final Validator validator = new PersonValidator();
// ...
public Mono<ServerResponse> createPerson(ServerRequest request) {
Mono<Person> person = request.bodyToMono(Person.class).doOnNext(this::validate);
return ok().build(repository.savePerson(person));
}
private void validate(Person person) {
Errors errors = new BeanPropertyBindingResult(person, "person");
validator.validate(person, errors);
if (errors.hasErrors()) {
throw new ServerWebInputException(errors.toString());
}
}
}
```
### RouterFunction
RouterFunction用于将请求路由到对应的HandlerFunction通常情况下都通过`RouterFunctions`工具类来创建router。
`RouterFunctions.route()`方法提供了许多快捷创建router的方法例如`GET(String, HandlerFunction)`等。
除了基于HTTP method进行映射外router builder还提供了引入额外Predicates来进行请求路由的机制对于每个基于http method进行路由的方法都存在一个重载方法用于接收predicates。
#### Predicates
使用者可以编写自己的RequestPredicate但是`RequestPredicates`工具提供了常用的实现可以基于request path、http method、content-type等进行判断。
在如下示例中,展示了通过`Accept` header进行判断的示例
```java
RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/hello-world", accept(MediaType.TEXT_PLAIN),
request -> ServerResponse.ok().bodyValue("Hello World")).build();
```
如果想要对多个predicates进行逻辑运算可以使用如下方法
- `RequestPredicate.and(RequestPredicate)`:两者都满足
- `RequestPredicate.or(RequestPredicate)`:两者任一满足
predicates中许多都是组合的例如`equestPredicates.GET(String)`是由`RequestPredicates.method(HttpMethod)``RequestPredicates.path(String)`进行组合的。
在上述示例中其实也使用到了两个predicatesbuilder内部使用了`RequestPredicates.GET`,调用方则指定了`accept`
#### Routes
Router function将会按顺序被调用如果前一个route没有匹配将会调用下一个route。
在使用router function builder时所有定义的routes都被整合在一个`RouterFunction`中,并且通过`build`方法进行返回。
除了使用router builder之外还可以将多个router function整合在一起
- 调用`RouterFunctions.route()`中的`add(RouterFunction)`方法
- `RouterFunction.and(RouterFunction)`方法
- and方法代表前面的方法没有匹配时后调用后面的RouterFunction
- `RouterFunction.andRoute(RequestPredicate, HandlerFunction)`方法
使用示例如下所示:
```java
PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);
RouterFunction<ServerResponse> otherRoute = ...
RouterFunction<ServerResponse> route = route()
.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
.GET("/person", accept(APPLICATION_JSON), handler::listPeople)
.POST("/person", handler::createPerson)
.add(otherRoute)
.build();
```
#### Nested Routes
通常情况下很有可能许多路由都包含相同的predicate例如共享路径。
如下示例展示了3个routes共用`/preson`路径的场景:
```java
RouterFunction<ServerResponse> route = route()
.path("/person", builder -> builder
.GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
.GET(accept(APPLICATION_JSON), handler::listPeople)
.POST(handler::createPerson))
.build();
```
在上述示例中route1和route2都接收json格式参数故而还能继续嵌套示例如下
```java
RouterFunction<ServerResponse> route = route()
.path("/person", b1 -> b1
.nest(accept(APPLICATION_JSON), b2 -> b2
.GET("/{id}", handler::getPerson)
.GET(handler::listPeople))
.POST(handler::createPerson))
.build();
```
#### Resource Redirect
RounterFunction的Builder支持对resource进行重定向示例如下
```java
Resource location = new FileUrlResource("public-resources/");
RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
```
### Filter Handler Functions
可以针对routing function builder添加filterbuilder支持如下方法
- before
- after
- filter
对builder添加的filter会应用到buidler中所有的routes示例如下所示
```java
RouterFunction<ServerResponse> route = route()
.path("/person", b1 -> b1
.nest(accept(APPLICATION_JSON), b2 -> b2
.GET("/{id}", handler::getPerson)
.GET(handler::listPeople)
.before(request -> ServerRequest.from(request)
.header("X-RequestHeader", "Value")
.build()))
.POST(handler::createPerson))
.after((request, response) -> logResponse(response))
.build();
```
上述示例中filter的范围如下
- `before`before只会应用到GET请求
- `after`after会应用到所有请求包括nested routes
对于`builder.filter`方法,其接收`HandlerFilterFunction`类型的参数,使用示例如下:
```java
SecurityManager securityManager = ...
RouterFunction<ServerResponse> route = route()
.path("/person", b1 -> b1
.nest(accept(APPLICATION_JSON), b2 -> b2
.GET("/{id}", handler::getPerson)
.GET(handler::listPeople))
.POST(handler::createPerson))
.filter((request, next) -> {
if (securityManager.allowAccessTo(request.path())) {
return next.handle(request);
}
else {
return ServerResponse.status(UNAUTHORIZED).build();
}
})
.build();
```
除了可以向builder添加filter外还可以向已经存在的router function中添加filter通过`RouterFunction.filter(HandlerFilterFunction)`方法。