WebFlux-Functional_Endpoints

本文介绍Spring WebFlux中的函数式编程模型,利用HandlerFunction和RouterFunction处理HTTP请求,展示了如何使用这些组件构建响应式Web应用,包括路由定义、请求处理及响应构建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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

简单的小栗子

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

整个的目录架构

img

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

    }

}

运行结果

img

### Spring MVC 版本及其特性 #### 1.x 到 2.x 版本 Spring MVC 最初是在 Spring 框架 1.0 中引入的,在早期版本中主要实现了基本的 MVC 设计模式支持,允许开发者更清晰地分离模型、视图和控制器逻辑[^5]。 #### 3.0 版本 (2009 年) 此版本增强了 RESTful Web Services 支持,并改进了数据绑定机制。同时增加了对 JavaConfig 的初步支持,减少了 XML 配置的需求。 #### 3.1 及以上版本 (2011 年之后) 从这个版本开始,Spring MVC 开始提供更加灵活的内容协商管理器(ContentNegotiationManager),使得处理不同类型的数据变得更加容易;另外也加强了异步请求的支持,提高了性能表现[^4]。 #### 4.x 系列 (2013 - 至今) - **4.0**: 增加了 WebSocket 和 SockJS 协议的支持,使实时通信成为可能。 - **4.1**: 引入了新的 @RestController 注解来简化 REST API 的开发工作流。 - **4.2**: 加强了对于 HTML5 表单标签属性的支持以及更好的 CORS 跨域资源共享控制能力。 - **4.3**: 对 HTTP/2 提供了一定程度的支持,优化了响应头压缩等功能。 #### 5.x 系列 (自 2017 年以来) - **5.0**: 正式加入了 Reactive Streams 编程范式的支持,这标志着 Spring 生态系统正式迈入反应式编程时代。 - **5.1**: 进一步完善了对函数式端点(Functional Endpoints)的支持,提升了编写无状态HTTP处理器的能力。 - **5.2**: 主要集中在提升现有特性的稳定性和效率上,比如改善文件上传下载体验等细节方面的工作。 - **5.3**: 推出了全新的 `spring-webflux` 模块作为下一代非阻塞式 web framework的核心部分之一,同时也继续增强传统 spring-mvc 功能集中的各项指标。 ```java // 示例代码展示如何定义一个简单的REST Controller @RestController @RequestMapping("/api/v1/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/{id}") ResponseEntity<User> getUserById(@PathVariable Long id){ User user = userService.findById(id); return new ResponseEntity<>(user, HttpStatus.OK); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值