一个注解干翻所有Controller
点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 10:33 更新文章,每天掉亿点点头发...
源码精品专栏
1. 概览
日常开发中,最繁琐的便是编写 Controller。很多公司都制定了规范:Controller 不能存在任何的业务逻辑,主要完成参数解析和结果转换。
不过查看项目源码,你会发现 Controller 中存在了大量不该存在的逻辑,对此,你有什么好的方法?依赖 Code Review?从我角度,我觉得 Controller 根本就不需要存在。
1.1. 背景
之前对 CommandService
和 QueryService 进行封装,通过定义接口的方式快速搭建应用服务,大大提升了开发效率和代码质量,在有了应用服务之后,便是在其基础之上编写 Controller,把能力暴露出去。这是一个非常繁琐且没有技术含量的重复工作。而对于枯燥的重复工作,我的策略一直都是“交由框架完成”。
1.2. 目标
简单的说,我们的目标便是不写Controller,但还要保留 Controller 的效果。
不需要编写 Controller 代码,将 CommandService
和 QueryService 直接暴露为 Web 接口;完成与 Swagger 框架的集成,动态生成 api doc,方便前端接入;
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/
2. 快速入门
2.1. 环境准备
首先,在 pom 中增加 lego-starter,具体如下:
<dependency>
<groupId>com.geekhalo.lego</groupId>
<artifactId>lego-starter</artifactId>
<version>0.1.11-rest-SNAPSHOT</version>
</dependency>
其次,增加 swagger 相关依赖,具体如下:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>3.0.0</version>
</dependency>
最后,新建 SpringFoxConfiguration
,启用 Swagger 具体如下:
@Configuration
@EnableSwagger2
public class SpringFoxConfiguration {
}
2.2. 初识统一控制器
打开浏览器,输入 http://127.0.0.1:8080/swagger-ui/
打开 swagger 界面,会发现新增两个 Controller:
command-dispatcher-controller
是对 CommanderService
的Web暴露,主要用于执行写入和更新等业务操作,两个接入点包括:
RequestBody 接入。以 json 作为入参,适用于复杂的参数结构; RequestParam 接入。以 param 作为参数,适用于简单场景;
query-dispatcher-controller
是对 QueryService 的Web暴露,主要用于执行业务的查询操作,同样支持 RequestBody 和 RequestParam 两种接入方式。与 command-dispatcher-controller
唯一区别是提供了对 Get 方法支持。
但在展开方法后,有点让人绝望。
serviceName 和 method 两个参数从哪获取?nativeRequest 和 nativeResponse 又是什么东西?这两个接口怎么使用?
看不明白也正常,因为我们不会直接使用这两个处理器。
2.3. Command 控制器
2.3.1. 启用 Command 控制器
在 OrderCommandService
接口上增加 @AutoRegisterWebController
注解,将其对外暴露为 Web 端口。
@CommandServiceDefinition(
domainClass = Order.class,
idClass = Long.class,
repositoryClass = OrderRepository.class)
@AutoRegisterWebController(name = "order")
public interface OrderCommandService{
void cancel(Long orderId);
Long create(CreateOrderCommand command);
void paySuccess(PaySuccessCommand command);
}
2.3.2. 使用 Order Command 控制器
输入 http://127.0.0.1:8080/swagger-ui/
访问 swagger 界面,发现新增一组 Controller。
OrderCommandService
服务中的所有方法全部出现在 Controller 中。
首先,展开 CommandByBody
中的 create 方法,可见:
然后,展开 CommandByParam
中的 create 方法,具体如下:
整体结构和手写 Controller 基本一致,所暴露的功能也全部相同。
2.4. Query 控制器
2.4.1. 启用 Query 控制器
在 OrderQueryService
接口上增加 @AutoRegisterWebController
注解,将其对外暴露为 Web 端口。
@QueryServiceDefinition(domainClass = Order.class,
repositoryClass = OrderQueryRepository.class)
@Validated
@AutoRegisterWebController(name = "order")
public interface OrderQueryService {
OrderDetail getById(@Valid @NotNull(message = "订单号不能为null") Long id);
Page<OrderDetail> pageByUserId(@Valid @NotNull(message = "查询参数不能为 null") PageByUserId query);
List<OrderDetail> getByUserId(@Valid @NotNull(message = "查询参数不能为 null") GetByUserId getByUserId);
Long countByUser(@Valid @NotNull(message = "查询参数不能为 null") CountByUserId countByUserId);
List<OrderDetail> getPaidByUserId(Long id);
}
2.3.2. 使用 Order Query 控制器
输入 http://127.0.0.1:8080/swagger-ui/
访问 swagger 界面,发现新增一组 Controller。
OrderQueryService
服务中的所有方法全部出现在 Controller。
首先,展开 QueryByBody 中的 pageByUserId
方法,可见:
然后,展开 QueryByParam 中的 pageByUserId 方法,具体如下:
入参与返回值结构非常清晰,整体结构和手写 Controller 基本一致,所暴露的功能也全部相同。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/
3. 设计&扩展
整个设计分为两部分:
提供统一的Controller,作为所有请求的转发器; 提供插件与 Swagger 进行集成,提供完整的 api doc;
3.1. 统一 Controller
提供 QueryDispatcherController
作为所有查询请求的入口,核心架构如下:
初始化流程如下:
Spring 对所有的 QueryService 进行实例化; 完成实例化的 QueryService Bean
自动注册到QueryServicesRegistry
;QueryMethodRegistry
从QueryServicesRegistry
中获取服务实例,对 QueryMethod 进行解析,并完成注册;
执行流程如下:
客户端向服务器发起请求; 服务器将请求 路由到 QueryDispatcherController
的相关方法;QueryDispatcherController
根据 serviceName 和 methodName 从QueryMethodRegistry
中获取 QueryMethod,执行业务方法,最后返回最终结果;
3.2. 与 Swagger 集成
提供 QueryServicesProvider
与 Swagger 进行集成,提供完整的 api doc,整体设计如下:
QueryServiceProvider
与 QueryDispatcherController
一致,同样依赖于 QueryMethodRegistry
中的 QueryMethod 信息。
核心流程如下:
QueryServicesProvider
从QueryMethodRegistry
中获取 QueryMethod 信息;解析 QueryMethod 信息生成 RequestHander
,并注册到 Swagger ;用户请求 Swagger 时,将 RequestHander
转化为 api doc进行返回;
4. 项目信息
项目仓库地址:https://gitee.com/litao851025/lego 项目文档地址:https://gitee.com/litao851025/lego/wikis/support/web
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
微信扫码关注该文公众号作者