doc: 阅读webflux文档
This commit is contained in:
@@ -41,6 +41,13 @@
|
|||||||
- [Server Request](#server-request)
|
- [Server Request](#server-request)
|
||||||
- [ServerResponse](#serverresponse)
|
- [ServerResponse](#serverresponse)
|
||||||
- [Handler Class](#handler-class)
|
- [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
|
# Spring Webflux
|
||||||
@@ -625,6 +632,155 @@ HandlerFunction<ServerResponse> helloWorld =
|
|||||||
request -> ServerResponse.ok().bodyValue("Hello World");
|
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)`进行组合的。
|
||||||
|
|
||||||
|
在上述示例中,其实也使用到了两个predicates,builder内部使用了`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添加filter,builder支持如下方法:
|
||||||
|
- 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)`方法。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user