点击上方蓝色“程序猿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 函数式编程进阶相关推荐

  1. Python函数式编程进阶

    引言 functools, itertools, operator是Python标准库为我们提供的支持函数式编程的三大模块,合理的使用这三个模块,我们可以写出更加简洁可读的Pythonic代码,接下来 ...

  2. 函数式编程的Java编码实践:利用惰性写出高性能且抽象的代码

    简介: 本文会以惰性加载为例一步步介绍函数式编程中各种概念,所以读者不需要任何函数式编程的基础,只需要对 Java 8 有些许了解即可. 作者 | 悬衡 来源 | 阿里技术公众号 本文会以惰性加载为例 ...

  3. 编程体系结构(08):Spring.Mvc.Boot框架

    本文源码:GitHub·点这里 || GitEE·点这里 一.Spring框架 1.框架概述 Spring是一个开源框架,框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 ...

  4. 3万6千字爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行

    3w6爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行 认识函数式编程 函数相关复习 函数是一等公民 高级函数 函数作为参数 案例 1,模拟 forEach 案例 2, ...

  5. 从 0 开始手写一个 Spring MVC 框架,向高手进阶

    转载自   从 0 开始手写一个 Spring MVC 框架,向高手进阶 Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面.如 ...

  6. 前端基础进阶(七):函数与函数式编程

    纵观JavaScript中所有必须需要掌握的重点知识中,函数是我们在初学的时候最容易忽视的一个知识点.在学习的过程中,可能会有很多人.很多文章告诉你面向对象很重要,原型很重要,可是却很少有人告诉你,面 ...

  7. JavaEE进阶 - Spring MVC 程序开发 - 细节狂魔

    文章目录 什么是 Spring MVC? MVC 定义 MVC 和 Spring MVC 的关系 总结 为什么要学 Spring MVC? Spring MVC 项目的创建 学习 Spring MVC ...

  8. Python进阶【第五篇】函数式编程及某些特殊函数

    一.函数式编程--Functional Programming 函数式=编程语言定义的函数+数学意义的函数 在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语 ...

  9. Python 进阶_函数式编程

    目录 目录 函数式编程 Python 函数式编程的特点 高阶函数 匿名函数 lambda 函数式编程相关的内置函数 filter 序列对象过滤器 map reduce 折叠 自定义的排序函数 最后 函 ...

最新文章

  1. requests 返回的cookies为空_Requests库(七)重定向和超时
  2. JAVA秒杀mysql层实现_Java高并发秒杀API之web层
  3. 【数据结构(C语言版)系列一】 线性表
  4. 写一个 panic blame 机器人
  5. 用vscode可以开发php,【编程开发工具】vscode能够编写php吗
  6. 架构设计 | 基于Seata中间件,微服务模式下事务管理
  7. activity 点击后传递数据给fragment_【磨叽教程】Android进阶之Fragment的管理以及事务执行...
  8. commons-lang3-RandomUtils
  9. Rock8247 bsp-Tornado-VXWorks Build up
  10. python画圆填色橙色_基于TPC-C基准的Python ORM的性能测试详解
  11. Python 学习博客地址
  12. Android界面全屏显示,隐藏状态栏,可下拉显示状态栏
  13. Greedy 贪心算法
  14. TSP_旅行商问题 - 模拟退火算法(三)
  15. unreal world 皮革_Unreal World猎鹿记
  16. 三国杀服务器改名 插图修改,三国杀7年前老版灵雎焚心到底多恶心?换身份让官方被迫修改...
  17. linux常用免杀,【kali linux】详细分析两个免杀远控 了解远控和免杀原理
  18. Android实现第三方登录并获取到头像、名字
  19. 在一个js文件中引入另一个js文件
  20. 转: include android instant app support 是什么?

热门文章

  1. python3 decode encode 字符串 字节 互转
  2. linux 定时任务 crontab 报错 service command not found 解决方法
  3. php 一句话木马简介
  4. golang beego框架对运行异常的处理
  5. python3 zipfile模块 zip压缩解压
  6. Python-decorator装饰器小结
  7. Windows窗口风格
  8. Android--GridView实现动态文字排版
  9. python import from区别_python import 与 from .... import ...区别-阿里云开发者社区
  10. Design Pattern - Observer(C#)