1. 前言

通常我们编写 Spring MVC 接口的范式是这样的:

@RestController
@RequestMapping("/v1/userinfo")
public class UserInfoController { @GetMapping("/foo")
public String foo() {
return "felord.cn";
}
}

这种我都写吐了,今天换个口味,使用 Spring 5 新引入的函数式端点(Functional Endpoints)来耍耍。 这种方式同样支持 Spring Webflux

请注意可使用该特性的 Spring 版本不低于 Spring 5.2

2. 依赖

为了演示,这里极简化只引入 Spring MVCstarter :

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

3. RouterFunction

在函数式端点的写法中,传统的请求映射(@RequestMapping)被路由函数(RouterFunction)所代替。上面的写法等同于:

    @Bean
public RouterFunction<ServerResponse> fooFunction() {
return RouterFunctions.route()
.GET("/v1/userinfo/foo", request -> ServerResponse.ok()
.body("felord.cn"))
.build();
}

在该示例中,我使用了 RouterFunctions.route() 创建了一个RouterFunction,然后RouterFunction 提供了从请求到响应的细节操作。

4. ServerRequest/ServerResponse

ServerRequest 是对服务器端的HTTP请求的抽象,你可以通过该抽象获取请求的细节。对应的,ServerResponse 是对服务器端响应的抽象,你也可以通过该抽象构建响应的细节。这两个概念由下面的 HandlerFunction 接口进行 请求→ 响应 处理。

5. HandlerFunction

HandlerFunction 是一个函数式接口,它提供了从请求( ServerRequest)到响应(ServerResponse)的函数映射抽象。通常你的业务逻辑由该接口进行实现。从 ServerRequest 中获取请求的细节,然后根据业务构建一个 ServerResponse 响应。

HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().body("felord.cn");

6. RequestPredicate

RequestPredicate 可以让你根据请求的一些细节,比如 请求方法请求头请求参数等等进行断言以决定是否路由。

这里举一个例子,假如我们希望请求接口/v1/userinfo/predicate时根据不同的参数处理不同的业务,当携带参数 plan时才能进行处理。我们可以这么写:

    @Bean
public RouterFunction<ServerResponse> predicateFunction() {
return RouterFunctions.route()
.GET("/v1/userinfo/predicate",
request -> request.param("plan").isPresent(),
request -> ServerResponse.ok().body("felord.cn"))
.build();
}

然后我们测试一下:

当携带参数 plan时:

GET http://localhost:8080/v1/userinfo/predicate?plan=

HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 9
Date: Thu, 14 May 2020 07:57:35 GMT
Keep-Alive: timeout=60
Connection: keep-alive felord.cn

不携带参数plan时:

GET http://localhost:8080/v1/userinfo/predicate

HTTP/1.1 404
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 14 May 2020 08:00:15 GMT
Keep-Alive: timeout=60
Connection: keep-alive {
"timestamp": "2020-05-14T08:00:15.659+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/v1/userinfo/predicate"
}

7. 小结

函数式端点是 Spring 5 提供的一个新的接口范式风格,对于 Spring MVC 来说 Spring 5.2 才进行了支持。也是顺应函数式编程的一个未来趋势。由于篇幅原因这里仅仅对其中的关键概念进行了讲解。下一篇我们会对这种接口范式进行进一步的讲解和实际使用。敬请关注:码农小胖哥

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

换一种方式编写 Spring MVC 接口的更多相关文章

  1. Java方式配置Spring MVC

    概述 使用Java方式配置Spring MVC,以及回顾一下Spring MVC的各种用法. Spring MVC简述 关于Spring MVC的介绍网上有很多,这里就不再赘述了,只是要说一下,Spr ...

  2. Mock测试你的Spring MVC接口

    1. 前言 在Java开发中接触的开发者大多数不太注重对接口的测试,结果在联调对接中出现各种问题.也有的使用Postman等工具进行测试,虽然在使用上没有什么问题,如果接口增加了权限测试起来就比较恶心 ...

  3. Java创建线程的第二种方式:实现runable接口

    /*需求:简单的卖票程序多个窗口买票 创建线程的第二种方式:实现runable接口 *//*步骤1.定义类实现Runable接口2.覆盖Runable接口中的run方法    将线程要运行的代码存放在 ...

  4. Android 反射-换一种方式编程

    Android 反射-换一种方式编程 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/59109933 本文出自[赵彦军的博客] 上一 ...

  5. Spring MVC接口实例

    概述 前文记录了MVC模式和Spring MVC的初步认识,现在记录创建一个项目,配置Spring MVC,编写接口程序. 创建项目 打开IntelliJ IDEA,点击"File-> ...

  6. Spring事务配置的五种方式和spring里面事务的传播属性和事务隔离级别

    转: http://blog.csdn.net/it_man/article/details/5074371 Spring事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之 ...

  7. Spring mvc 接口枚举类型数据格式化处理

    一.背景简述 首先,我们都知道枚举实例有两个默认属性,name 和 ordinal,可通过 name()和ordinal()方法分别获得.其中 name 为枚举字面量(如 MALE,FEMALE),o ...

  8. 51、多线程创建的三种方式之实现Callable接口

    实现Callable接口创建线程 Callable接口是在jdk5版本中加入的,这个接口在java.util.concurrent包下面,与其他两种方式不同的地方在于使用Callable接口创建的线程 ...

  9. @Autowired注解和启动自动扫描的三种方式(spring bean配置自动扫描功能的三种方式)

    前言: @Autowired注解代码定义 @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, Elemen ...

随机推荐

  1. vue2.x学习笔记(十八)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12629705.html. 处理边界情况 这里记录的都是和处理边界情况有关的功能,即一些需要对vue的规则做一些小调 ...

  2. C++基础 学习笔记五:重载之运算符重载

    C++基础 学习笔记五:重载之运算符重载 什么是运算符重载 用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载.运算符重载是静态多态性的体现. 运算符重载的规则 重载公式 ...

  3. CVE-2018-12613 的一些思考

    复现 CVE-2018-12613 的一些思考,关于文件包含路径的问题 漏洞 /index.php 第 55 行 $target_blacklist = array ( 'import.php', ' ...

  4. EF-相关查询(逐渐完善)

    linq查询方式 多条件查询 内连接 左连接 可以执行sql含事务

  5. 【AspNetCore源码】设计模式 - 提供者模式

    AspNetCore源代码发现日志模块的设计模式(提供者模式),特此记录 学习设计模式的好处是,我们可以容易扩展它达到我们要求,除了要知道如何扩展它,还应该在其他地方应用它 类图 & 分析 角 ...

  6. curl的$post传递多维数组

    php curl传数组的话只能传一维数组,如果想传多维数组:两个方法: 1.转换成json在传输 2. //通过curl模拟post的请求: function SendDataByCurl($url, ...

  7. 消息中间件metaq

    消息中间件metaq安装并注册到zookper集群 项目地址 https://github.com/killme2008/Metamorphosis Memorphosis是一个消息中间件,它是lin ...

  8. 走 进 java 的 四 个 基 本 特 性

    赶上明天就还是五一c小长假了,准备在这几天写几篇原创文章,供大家一起学习. 首先今天就来好好地唠一唠,到底java的那几个特性都是什么呢?到底怎么用呢?相信一定有一些小白对此会有些懊恼,没关系的,谁还 ...

  9. 用数据说话,R语言有哪七种可视化应用?

    今天,随着数据量的不断增加,数据可视化成为将数字变成可用的信息的一个重要方式.R语言提供了一系列的已有函数和可调用的库,通过建立可视化的方式进行数据的呈现.在使用技术的方式实现可视化之前,我们可以先和 ...

  10. RMI原理揭秘之远程对象

    讨论开始之前,我们先看看网上的一个例子,这个例子我腾抄了一分,没有用链接的方式,只是为了让大家看得方便,如有侵权,我立马***. 定义远程接口: 1 2 3 4 5 6 package com.guo ...