title: WebFlux-Functional_Endpoints
date: 2019-01-15 10:59:53
tags: Spring
categories: Spring
Spring WebFlux包含了WebFlux.fn,它是一个轻量级的函数式编程模型,其中函数用于路由和处理请求和契约,旨在实现不变性
在WebFlux.fn中一个http请求被一个HandlerFunction
处理,HandlerFunction
消费ServerRequest
然后返回延迟的ServerResponse
,它等价于基于注解的编程模型中的@RequestMapping
方法体里面的内容
路由处理由一个RouterFunction
处理,它花费一个ServerRequest
然后返回一个延迟的HandlerFunction
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);
RouterFunction<ServerResponse> route = route()
.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
.GET("/person", accept(APPLICATION_JSON), handler::listPeople)
.POST("/person", handler::createPerson)
.build();
public class PersonHandler {
// ...
public Mono<ServerResponse> listPeople(ServerRequest request) {
// ...
}
public Mono<ServerResponse> createPerson(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getPerson(ServerRequest request) {
// ...
}
}
运行RouterFunction
需要将它转变为HttpHandler
,通过内置服务器适配器安装它
ServerRequest
和ServerResponse
是不可变接口,提供给JDK8 对HTTP请求和响应的友好访问
ServerRequest
提供了访问HTTP方法,URL,头部信息和查询参数的方法,访问body中的内容可以通过body
方法进行访问
将请求体抽出来放到Mono
中
Mono<String> string = request.bodyToMono(String.class);
将请求体封装到Flux
中
Flux<Person> people = request.bodyToFlux(Person.class);
上边等价于
Mono<String> string = request.body(BodyExtractors.toMono(String.class));
Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class));
访问表单数据
Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData());
访问多部分数据
Mono<MultiValueMap<String, Part> map = request.body(BodyExtractors.toMultipartData());
访问多部分数据,将他们封装成一个整体
Flux<Part> parts = request.body(BodyExtractos.toParts());
ServerResponse
提供了访问HTTP响应的方法,因为它是不可变的,可以使用build
来创建它
Mono<Person> person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);
下面这个: build了一个201响应,带有Location
的头部信息,没有body
URI location = ...
ServerResponse.created(location).build();
作用: 将请求转到HandlerFunction
去处理,类似于基于注解的开发@GetMapping
,@PostMapping
注解的作用
RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/hello-world", accept(MediaType.TEXT_PLAIN),
request -> Response.ok().body(fromObject("Hello World")));
router
函数: 创建一个新的路由GET
限制请求方式为get方式,url为/hello-word
accept
限制请求头Response.ok()
表示响应头为200,响应体由body
给出最简单的路由
RouterFunction<ServerResponse> route = route()
.path("/person", builder -> builder
.GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
.GET("", accept(APPLICATION_JSON), handler::listPeople)
.POST("/person", handler::createPerson))
.build();
嵌套路由通过使用netst
函数实现
RouterFunction<ServerResponse> route = route()
.path("/person", b1 -> b1
.nest(accept(APPLICATION_JSON), b2 -> b2
.GET("/{id}", handler::getPerson)
.GET("", handler::listPeople))
.POST("/person", handler::createPerson))
.build();
目的: 实现查询所有用户信息,显示在浏览器中
整个的目录架构
User.java
package com.yoke.webfluxlab.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Author Yoke
* @Date 2019/01/19 上午11:40
*/
@Data //使用lambok
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1755498148611901176L;
private Integer id;
private String name;
}
UserCommonHandler.java
package com.yoke.webfluxlab.handler;
import com.yoke.webfluxlab.pojo.User;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
/**
* @Author Yoke
* @Date 2019/01/19 上午11:41
*/
@Component
public class UserCommonHandler {
public Mono<ServerResponse> getAll(ServerRequest request) {
List<User> users = new ArrayList<User>() {{
add(new User(1, "yoke"));
add(new User(2, "xiaoli"));
}};
return ok().contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(users), List.class);
}
}
UserRouterConfig
package com.yoke.webfluxlab.router;
import com.yoke.webfluxlab.handler.UserCommonHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
/**
* @Author Yoke
* @Date 2019/01/19 上午11:48
*/
@Configuration
public class UserRouterConfig {
private final UserCommonHandler userHandler;
@Autowired
public UserRouterConfig(UserCommonHandler userHandler) {
this.userHandler = userHandler;
}
@Bean
public RouterFunction<ServerResponse> userHandler() {
return route(GET("/user"), userHandler::getAll);
}
}
WebfluxApplication
package com.yoke.webfluxlab;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebfluxApplication {
public static void main(String[] args) {
SpringApplication.run(WebfluxApplication.class, args);
}
}
运行结果