这个方案并不是我在系统设计方面的最早一次尝试。但它在提高开发效率方面,是效果最为显著的一个方案。
简介
“六神”框架提供了一套简单而通用的、从Web层到数据库操作(增加单个数据、删除单个数据、修改单个数据、查询单个数据、查分页列表、查不分页列表,六个操作,因此名为“六神”)的基础组件。并且,它为复杂的数据库操作留下了扩展点。
在当时的技术背景下,这套框架使用Struts2.0+Spring+myBatis来实现。但是它的设计思路是可以适用于其它技术的。接口设计方面也为SpringMVC或Hibernate预留了扩展点
在应用了这套框架之后,我们那个系统在一个月时间上线14个功能模块,效率提升了近三倍。
背景
当时我们接下的项目是一个近似于OA系统的稽核系统。这个系统的主要功能有两类:一是各种数据、信息的增删改查;一是各种审批流程。审批流程的设计按下不表,“六神”就是为增删改查功能而开发的。
思路
在完成了几个增删改查的页面功能之后,我发现它们非常相似。
功能上,它们都是打开页面时查询一个分页列表;然后新建一条数据;按id查询出一条数据,并展示在弹出窗口上;弹出窗口上可以修改某些字段的值;某些页面上还需要提供删除数据的功能;部分配置数据、基础数据需要提供查询不分页列表的功能。
流程上,则几乎都是页面提交一个http请求,Struts 2.0的action从中解析出参数;service层调用对应的mapper;myBatis生成并执行SQL,将操作结果返回给service;service直接将参数交还action;action将返回值转为json字符串写入http响应中。
而它们之间的差异性,基本是入参和出参的封装类型、以及数据库操作的SQL上。
流程图
上述六个操作,都可以用下面这张流程图来描述。而不同的操作、不同的业务需求之间,基本上只有object以及SQL有所不同。
类图
“六神”的主要类图中,以接口定义居多。其中的BasicDbAction和BasicDbMapper,是当时Struts2.0和MyBatis框架中的两个实现类。
controller
原先的类结构上,Controller层只有一个Struts 2.0的action;Dao层只有一个myBatis的Mapper。两个接口都是后来提取出来,计划扩展到SpringMVC和Hibernate的。
Strust2.0一般会为每个HttpRequest创建一个action实例,并将HttpRequest中的参数根据action的setters/getters方法封装到action中。这就需要action在实例化的时候,同时生成一个参数容器、即类图中param: I的一个实例。然而,根据泛型参数无法直接做实例化。因此,需要为action配置一个参数claz并在Spring IoC中将它注入为I的具体类型。这样才能保证action初始化的同时实例化参数param,并成功读取到HttpRequest中的请求。
service
Service层上分出来了六个接口。这是为了保持接口的隔离性。但是默认类实现了全部接口,只是所有方法都直接抛出异常。实际上就只是提供了一个Adapter而已。
dao
Dao层同样有六个接口,但不提供默认实现。需要使用时针对myBatis或者Hibernate,分别写自己的实现类。
MyBatis一般会使用Mapper的类名+执行方法名作为需要执行的SQL-id,并据此id从xml文件中找到、生成实际的SQL。但是,如果直接注入、使用框架提供的MyBatis默认实现类,那么每一个查询请求都会按照“xxx.BasicDbMapper.select”这个id去查找SQL,因而也无法找到正确的SQL。为了避免这个问题,BasicDbMapper中使用了入参param的类名+执行方法名作为SQL-id。这样,对“xx.ParamA”的查询请求就会使用“xx.ParamA.select”这个id了。
另外,除了Controller之外,计划扩展到Jms Listener。不过异步消息只有增删改三个操作,就算“半神”吧。
代码
https://github.com/winters1224/blogs/tree/master/code/src/main/java/net/loyintean/blog/sixgod
小结
这个小框架功能非常简单,设计上也非常简单。因为它太简单,少有开发团队愿意在这上面耗费资源。但是,这个框架能够把简单、重复的工作抽取出来,让团队把资源投放在更加复杂的工作中去。
另一方面,随着REST、微服务等概念的深入,我认为,每个系统中的每项资源都应该提供CURD的基本API。这个小框架,能够方便快捷的提供对应的Web API,也能为微服务的快速落地提供方便。