Spring MVC 函数式编程进阶
点击上方蓝色“程序猿DD”,选择“设为星标”
回复“资源”获取独家整理的学习资料!
来源 | 码农小胖哥
1. 前言
上一篇对 Spring MVC 的函数式接口编程进行了简单入门,让很多不知道的同学见识了这种新操作。也有反应这种看起来没有传统写法顺眼,其实大家都一样。但是我们还是要敢于接受和尝试新事物。Java Lambada 刚出来也是被人各种吐槽,现在我在很多项目都见到了它的身影。好了转回正题,本文是对上一篇的延伸,我们继续对 Functional Endpoint 进行一些了解和运用。范式转换其实上一篇已经介绍差不多了,但是一旦你初次接触这种方式往往会面临新的问题。
2. 新的问题
在使用这种风格时我们也会遇到一些新的问题。接下来我们将通过举例来一步步解决这些问题。
2.1 如何异常处理
接口异常处理是必须的。改成函数式风格后异常可以这样处理:
/*** 接口附带异常处理逻辑.** @param userService the user service* @return the user by name with error handle*/public RouterFunction<ServerResponse> withErrorHandle() {return RouterFunctions.route().GET("/userwitherrorhandle/{username}",request -> ServerResponse.ok().body(userService.getByName(request.pathVariable("username"))))// 异常处理.onError(RuntimeException.class,(e, request) -> EntityResponse.fromObject(e.getMessage()).status(HttpStatus.INTERNAL_SERVER_ERROR).build()).build();}
你可以使用上面的 onError
方法及其重载方法进行接口的异常处理。但是传统方法有统一异常处理啊!不要捉急,后面我们也会进行统一异常的处理。
2.2 如何使用过滤器
我还有不少 Spring MVC 在使用过滤器呢,使用这种风格如何编写过滤器,上一篇漏掉了一个处理过滤器的函数式接口HandlerFilterFunction
。我们通过该接口来对请求进行过滤:
/*** 对特定接口指定过滤器.** @param userService the user service* @return the router function*/public RouterFunction<ServerResponse> withFilter() {return RouterFunctions.route().POST("/save",request -> ServerResponse.ok().body(userService.saveUser(request.body(UserInfo.class))))// 执行了一个过滤器逻辑 参数携带了 save 放行 否则返回 bad request 并附带消息.filter((request, next) -> request.param("save").isPresent() ?next.handle(request) :ServerResponse.status(HttpStatus.BAD_REQUEST).body("no save")).build();}
通过 filter
方法我们可以实现日志、安全策略、跨域等功能。
2.3 如何使用拦截器
使用函数式编程风格时并没有提供 Spring MVC 的拦截器 API,但是提供了类似过滤器前置/后置处理机制以达到同样的效果。
public RouterFunction<ServerResponse> getUserByName() {return RouterFunctions.route().GET("/user/{username}",request -> ServerResponse.ok().body(userService.getByName(request.pathVariable("username"))))// 前置处理 打印 path.before(serverRequest -> {log.info(serverRequest.path());return serverRequest;})// 后置处理 如果响应状态为200 则打印 response ok.after(((serverRequest, serverResponse) -> {if (serverResponse.statusCode() == HttpStatus.OK) {log.info("response ok");}return serverResponse;})).build();}
当你请求/user/{username}
时, before
和 after
方法将会分别进行前置和后置处理。
2.4 如何进行统一处理
传统方式我们每个Controller 处理的都是特定单一领域的业务,UserController
处理 User
相关业务,我们会给它添加一个统一的前缀标识 /v1/user
;OrderController
处理 Order
相关业务,给它添加一个统一的前缀标识 /v1/order
。使用函数式编程我们可以通过以下方式实现:
@Bean
RouterFunction<ServerResponse> userEndpoints(UserController userController) {return RouterFunctions.route().path("/v2/user", builder -> builder// /get/{username} -> /v2/user//get/{username}.add(userController.getUserByName()// /del/{username} -> /v2/user//del/{username}.and(userController.delUser()// /save -> /v2/user/save.and(userController.saveUser()// /update -> /v2/user/update.and(userController.updateUser()))))).build();
}
你也可以使用 RouterFunctions.route().nest
相关的方法进行实现。而且对这些路由进行分组聚合之后就可以统一过滤器、拦截器、异常处理。例如2.1提到的统一异常问题:
@Bean
RouterFunction<ServerResponse> nestEndpoints(UserController userController) {return RouterFunctions.route().nest(RequestPredicates.path("/v1/user"),builder -> builder.add(userController.getUserByName()).add(userController.delUser()).add(userController.saveUser()).add(userController.updateUser()))// 对上述路由进行统一的异常处理.onError(RuntimeException.class,(throwable, serverRequest) -> ServerResponse.status(HttpStatus.BAD_REQUEST).body("bad req")).build();
}
3. 总结
本文主要对 Spring MVC 函数式开发和传统开发中等效的特性(过滤器、拦截器、分组聚合等)进行了简单的说明,更加贴合于实际运用。函数式风格开发更加灵活,但是同样让习惯命令式编程的开发者有点不适应,但是目前越来越被普遍的应用。所以如果有志于长期从事编程开发的同学来说,还是需要掌握的。
本文的 demo 可通过关注公众号下方
回复 mvcfun 获取
Spring MVC 函数式编程进阶相关推荐
- Python函数式编程进阶
引言 functools, itertools, operator是Python标准库为我们提供的支持函数式编程的三大模块,合理的使用这三个模块,我们可以写出更加简洁可读的Pythonic代码,接下来 ...
- 函数式编程的Java编码实践:利用惰性写出高性能且抽象的代码
简介: 本文会以惰性加载为例一步步介绍函数式编程中各种概念,所以读者不需要任何函数式编程的基础,只需要对 Java 8 有些许了解即可. 作者 | 悬衡 来源 | 阿里技术公众号 本文会以惰性加载为例 ...
- 编程体系结构(08):Spring.Mvc.Boot框架
本文源码:GitHub·点这里 || GitEE·点这里 一.Spring框架 1.框架概述 Spring是一个开源框架,框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 ...
- 3万6千字爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行
3w6爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行 认识函数式编程 函数相关复习 函数是一等公民 高级函数 函数作为参数 案例 1,模拟 forEach 案例 2, ...
- 从 0 开始手写一个 Spring MVC 框架,向高手进阶
转载自 从 0 开始手写一个 Spring MVC 框架,向高手进阶 Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面.如 ...
- 前端基础进阶(七):函数与函数式编程
纵观JavaScript中所有必须需要掌握的重点知识中,函数是我们在初学的时候最容易忽视的一个知识点.在学习的过程中,可能会有很多人.很多文章告诉你面向对象很重要,原型很重要,可是却很少有人告诉你,面 ...
- JavaEE进阶 - Spring MVC 程序开发 - 细节狂魔
文章目录 什么是 Spring MVC? MVC 定义 MVC 和 Spring MVC 的关系 总结 为什么要学 Spring MVC? Spring MVC 项目的创建 学习 Spring MVC ...
- Python进阶【第五篇】函数式编程及某些特殊函数
一.函数式编程--Functional Programming 函数式=编程语言定义的函数+数学意义的函数 在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语 ...
- Python 进阶_函数式编程
目录 目录 函数式编程 Python 函数式编程的特点 高阶函数 匿名函数 lambda 函数式编程相关的内置函数 filter 序列对象过滤器 map reduce 折叠 自定义的排序函数 最后 函 ...
最新文章
- requests 返回的cookies为空_Requests库(七)重定向和超时
- JAVA秒杀mysql层实现_Java高并发秒杀API之web层
- 【数据结构(C语言版)系列一】 线性表
- 写一个 panic blame 机器人
- 用vscode可以开发php,【编程开发工具】vscode能够编写php吗
- 架构设计 | 基于Seata中间件,微服务模式下事务管理
- activity 点击后传递数据给fragment_【磨叽教程】Android进阶之Fragment的管理以及事务执行...
- commons-lang3-RandomUtils
- Rock8247 bsp-Tornado-VXWorks Build up
- python画圆填色橙色_基于TPC-C基准的Python ORM的性能测试详解
- Python 学习博客地址
- Android界面全屏显示,隐藏状态栏,可下拉显示状态栏
- Greedy 贪心算法
- TSP_旅行商问题 - 模拟退火算法(三)
- unreal world 皮革_Unreal World猎鹿记
- 三国杀服务器改名 插图修改,三国杀7年前老版灵雎焚心到底多恶心?换身份让官方被迫修改...
- linux常用免杀,【kali linux】详细分析两个免杀远控 了解远控和免杀原理
- Android实现第三方登录并获取到头像、名字
- 在一个js文件中引入另一个js文件
- 转: include android instant app support 是什么?
热门文章
- python3 decode encode 字符串 字节 互转
- linux 定时任务 crontab 报错 service command not found 解决方法
- php 一句话木马简介
- golang beego框架对运行异常的处理
- python3 zipfile模块 zip压缩解压
- Python-decorator装饰器小结
- Windows窗口风格
- Android--GridView实现动态文字排版
- python import from区别_python import 与 from .... import ...区别-阿里云开发者社区
- Design Pattern - Observer(C#)