WebFlux-Functional_Endpoints


title: WebFlux-Functional_Endpoints
date: 2019-01-15 10:59:53
tags: Spring
categories: Spring


Overview

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,通过内置服务器适配器安装它

HandlerFunction

ServerRequestServerResponse是不可变接口,提供给JDK8 对HTTP请求和响应的友好访问

ServerRequest

ServerRequest提供了访问HTTP方法,URL,头部信息和查询参数的方法,访问body中的内容可以通过body方法进行访问

将请求体抽出来放到Mono<String>

Mono<String> string = request.bodyToMono(String.class);

将请求体封装到Flux<Person>

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

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();

RouterFunction

作用: 将请求转到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();

简单的小栗子

目的: 实现查询所有用户信息,显示在浏览器中

整个的目录架构

WebFlux-Functional_Endpoints

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);

    }

}

运行结果

WebFlux-Functional_Endpoints