天画-codeMaker低代码平台设计与实现(下)
一、背景最近没有再更新DDD相关的技术文章了,因为到了实战环节需要大量的代码demo,由于精力和时间有限,因此便希望借助代码生成来解决一些模板化的工作内容。之前已经在代码生成领域做了一些尝试,这里便希望花一些时间专门做几次迭代来满足DDD项目工程实战的问题。二、需求2.1 支持dubbo框架的代码生成需要生成的代码元素包括facade,impl,dto,service,serviceimpl,bo
一、背景
最近没有再更新DDD相关的技术文章了,因为到了实战环节需要大量的代码demo,由于精力和时间有限,因此便希望借助代码生成来解决一些模板化的工作内容。之前已经在代码生成领域做了一些尝试,这里便希望花一些时间专门做几次迭代来满足DDD项目工程实战的问题。
二、需求
2.1 支持dubbo框架的代码生成
需要生成的代码元素包括facade,impl,dto,service,serviceimpl,bo,do,convert,mapper,mapperxml
2.2 支持基于plantUML类图的代码生成(动态DDD)
需要生成的代码元素包括bo,acladapter,enum,factory,gataway,repository,
2.3 支持cola应用架构的代码生成
需要生成的代码元素包括bo,dto,vo,do,convert,facade,controller,vo,facadeimpl,mapper,mapperxml,service,serviceimpl,acladapter,factory,repository,gataway等。
三、迭代计划
本文背景中已经点名了迭代的需求背景,因此就要按部就班的实现,为了尽快达成目标。这里分为三步走的方式。
第一版实现支持dubbo框架的代码生成
第二版实现动态DDD代码的生成
第三版支持cola框架代码生成
四、设计与实现
4.1 支持dubbo框架的代码生成
4.1.1 工程设计
这里参考下codeMaker早期的设计理念,就是生成的代码第一不跟着真正的项目工程目录走,第二不放在codeMaker核心工程里,而是创建与codeMaker-core模块平级的工程,基于此工程来检查并使用生成的代码。
因此这里创建了maven多模块父子工程。
父级工程:codemaker-dubbo
子工程:
dubbo-api:定位是dubbo consumer或者client接口,存放facade,dto.
dubbo-common:定位是项目工程的持久化层,存放do(也可以是entity),mapper接口,mapperxml,这个工程里的代码也可以合并到dubbo-core里,根据使用者的设计进行调整。
dubbo-core:定位是dubbo provider或者server端,存放facadeimpl,bo,convert,serviceimpl,service等。
4.1.2 模型设计
之前的模型只涉及到tableBean,columnBean来表示数据库的元数据,为了支持一套接口生成dubbo或者springboot框架的代码需要重构代码元素生成入口,因此增加了一个bean模型(ClassContentBean):
另外需要根据配置的框架名称来动态切换因此需要定义一些顶层接口和实现,部分UML类图如下:
4.1.3 代码生成配置
这里参考了基于springboot框架生成代码的思路,为dubbo应用框架的代码生成单独配了一个配置文件,叫projecttemplate-dubbo.properties,内容如下:
#目标工程根包名称
dubbo.global.package=com.lightsnail.snailapp.usercrm
#作者
dubbo.global.author=fanchunshuai
#数据库名称
dubbo.global.dbName=snail_app_user_crm
dubbo.global.applicationName=snailapp-usercrm
#目标工程输出目录,这里填写对应的codemaker-web工程的绝对路径
dubbo.code.outpath.dubbbo-common=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-dubbo\\dubbbo-common
dubbo.code.outpath.dubbbo-api=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-dubbo\\dubbo-api
dubbo.code.outpath.dubbbo-core=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-dubbo\\dubbo-core
4.1.4 代码模板配置
在之前的介绍中代码生成依赖的核心模板是freemarker模板,并且针对极简模式和极速模式分别做了定制,在dubbo框架层面依然做了一些定制化的代码模板文件,这些目标文件包括:
dto.ftl,facade.ftl,facadeimpl.ftl,service.ftl,serviceimpl.ftl,test.ftl,mapper.ftl,mapperxml.ftl,bo.ftl
4.1.5 发布版本和详情
版本号:1.0.3-SNAPSHOT
发布分支: dubbo-arch
发布内容:
- 重构代码生成逻辑核心服务,引入应用层,支持多应用类型代码生成架构
- 支持一套api操作接口生成dubbo,springboot应用代码
- 增加dubbo应用的代码模板,支持maven多模块
- 引入bo,facade,facadeimpl,aop,dto等代码类生成模板
- dubbo项目支持facade层和service层双服务层业务架构
- application.properties增加application.type属性,值为springboot,dubbo,cola
- 增加projecttemplate-dubbo.properties属性文件,支持dubbo项目代码生成
- 原有配置文件projecttemplate.properties改名为projecttemplate-springboot.properties
- 修复若干其他bug
4.2 支持动态DDD的代码生成
4.2.0 设计概要
在决定进行这一轮迭代的时候并没有立刻去做,而是想了两天,DDD代码生成本身跟传统的代码生成有一定的区别,最根本的一点就是DDD的代码模型很灵活,没有固定的模式。这就导致了基于数据库或者基于接口文档等的形式去做根本无法覆盖DDD的基础模式,反而跟基于数据库的极简模式和极速模式生成的代码一样,比较死板,分层较少。在后期迭代中代码生成器基本上无法提供帮助了,类似于一次性使用产品。那么就需要找一个媒介或者一个容器来更容易的表达DDD可以表现的东西,在我看来DDD的最核心的东西莫过于实体,值对象,接口,枚举,服务类等元素。另外一方面这个媒介或者容器最好可以是文档类的软件或者模板。
之前已经做过了通过数据库的元数据来生成e-r图,生成的e-r图是基于plantUML的。由于plantUML本身支持很多场景的类图,流程图文档设计。因此便对plantUML做了一些调研。发现这个软件结合编辑器的插件和语雀文档等平台可以发挥设计文档类的作用。另外一个优势就是plantUML的类图结构完全兼容DDD的一些概念模式和文档样例,这刚好契合了动态DDD的需求。这也就意味着基于plantUML的类图作出的DDD文档可以方便的转换为具体的实现类。所以只要有plantUML类图就可以生成基本模式的代码,也方便后续迭代新模块或者调整重构,可谓DDD代码生成落地的一大上等神兵利器。
后面就顺着这个思路做了一些调研,打算找一款java 的plantUML类图解析工具发现没有,但是plantUML类图的读写也不是很难,因此这个难点可忽略,自己实现一个简单的也可以。
那话不多说,下面看一下设计过程。
4.2.1 工程设计
我们参考dubbo,springboot框架的代码生成同样在codemaker-core工程的平级目录下创建一个工程名为codemaker-dynamicddd。
该工程跟springboot工程一样是一个单模块工程,其定位是基于plantUML类图生成的代码会单独存放在这个模块,同时这个模块的定位是模块级的应用。另外一方面我也把springboot,dubbo,cola认为是应用级的应用。
如果plantUML类图本身是比较规范的文档,那么生成的代码也会比较规范,同时可以在这个工程里查看生成的代码大概长什么样子,需要怎么样的调整。这也为开发者提供了一种代码预览的可能,避免直接上手开放,如果设计不当可以及时发现问题。
4.2.2 模型设计
同样的,在本轮迭代中也对模型进行了一些扩展,把诸如mapper,controller,dto,bo,factory,valueobject等的代码当作代码元素来看待,然后让解析出的plantUML文件内容转换到这些代码元素中。这轮迭代将模型分为分为两类,一类是解析plantUML类图进行定义的模型,如类,接口,枚举,方法,属性。另一类是DDD的代码元素,比如bo(busniess object),enum,gataway,repository,factory这种的。
这些代码元素是从plantUML类图文档里解析出来的,因此需要先定义plantUML类图中的代码元素,这里做了简单的抽象,下面看一下当前的模型类图:
4.2.3 代码生成配置
这里同样参考dubbo的应用代码生成配置单独创建一个配置文件,名为projecttemplate-dynamicddd.properties
,内容如下:
#目标工程根包名称
dynamicddd.global.package=com.lightsnail.snailapp.usercrm
#作者
dynamicddd.global.author=fanchunshuai
#目标工程输出目录,这里填写对应的codemaker-dynamicddd工程的绝对路径
dynamicddd.code.outpath=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-dynamicddd
#领域plantUML 类图
dynamicddd.domain.plantuml=CommonAuth.puml
4.2.4 代码模板配置
根据动态DDD代码元素的内容,我们定义如下代码模板:
abstractexe.ftl,acl.ftl,bo.ftl,enum.ftl,exeimpl.ftl,factory.ftl,gataway.flt,msgbody.ftl,valueobject.ftl
4.2.5 发布版本和详情
发布版本号:1.0.4-SNAPSHOT
发布分支:dynamic-domain
发布内容:
- 基于plantUML文档生成代码,基于ddd思想和模式生成模块级的代码内容
- 增加makeddd接口,支持生成dynamicddd模块的代码
- 引入支持ddd代码生成的配置(projecttemplate-dynamicddd.properties)和代码模板(template/dynamicddd)
- codemaker-core模块resources目录增加ddd-plantuml目录存放plantUML类图
- 支持ddd的一些模式代码生成:实体模式,值对象模式,聚合根模式,工厂模式,仓库模式,防腐层模式,服务模式,模块模式,CQE模式,领域网关
- 产出部分公共代码生成服务方法
- 优化代码生成核心链路代码模型,针对ddd代码生成做了分层处理
- 修复若干其他bug
4.3 支持cola应用架构的代码生成
4.3.0 设计概要
之前的公众号文章已经介绍了cola应用架构的相关内容,这里通过codeMaker来辅助生成基于cola应用架构模块的代码生成。在上一轮迭代中已经基本实现了动态DDD的代码生成功能了,因此这里尝试一下借助动态DDD代码生成的能力融合cola的应用模块。
4.3.1 工程设计
这里跟codemaker-dubbo类似,新建一个父子类的项目工程,名为codemaker-cola,子工程列表如下:
cola-adapter:定位是cola的适配器模块,或者也叫端口适配层,前身名为cola-controller.所以这里主要存储controller,vo,voboconvert的代码元素。
cola-client:定位是cola的sdk模块,如果融合rpc框架如dubbo,那么这个子模块相当于dubbo-api或者dubbo-consumer.这里主要存储facade,dto的代码元素。
cola-app:定位是cola的应用层,在应用层中主要包括消息的处理,facade的实现,dtobo的转换,以及CQRS模式的应用。所以这里主要存储facadeimpl,dtoboconvert,command,executor。
cola-domain:定位是cola的领域层,在领域层中主要包括bo,valueobject,enum,msgbody,factory,gataway,repository。
cola-infrast:定位是cola的基础设施层,这里做了简写。在这一层中主要包括mapper,do,bodoconvert,gatawayimpl,repositoryimpl,acladapter(防腐层或者适配层)
另外完整的cola应用架构会包含一个cola-start的子模块,这里做了简化,因为一些个性化的配置一般在真正的项目中都是不一样的,所以cola-start就不会存放代码了,如果存放也可以,毕竟本身cola-start里面实际上就是一个Application类用来启动项目。
4.3.2 模型设计
在DDD的代码元素中分为两种代码元素,一种就是在dynamic-ddd迭代过程中定义的bo,valueobject,factory这种的原生代码元素,另一种就是派生的代码元素,由于基于plantUML类图+DDD的代码文档,因此文档里应该不会包含controller,facade,dto这些代码元素,因此这些应该需要通过BO或者gataway进行派生。具体的设计包括通过BO类来派生DTO,然后派生dtoboconvert,然后派生facade等。由于facade一般也不会在DDD中体现,包括controller里面的接口因此就从BO类上做了一些扩展,增加了一些扩展key来做派生类的处理。
这么做的一个原因就是COLA架构本身就是支持复杂系统复杂业务下的应用架构,如果太简单或者不是很复杂那么就不需要用COLA来构建工程。因为如果基于数据库表的方式来生成代码那么生成的代码元素放在cola不同的子模块下就显得有点零散而且显得特别少。所以如果基于plantUML+动态DDD的方式来构建的话又少了一些边缘化的代码元素,比如xo2xoconvert,controller。所以如果希望支持复杂业务的代码应用就需要通过原生的代码元素来派生一些plantUML本身不方便表达的代码元素。下面来看一下在本轮迭代过程中的模型变化:
4.3.3 代码生成配置
这里同样参考dubbo的应用代码生成配置单独创建一个配置文件,名为projecttemplate-cola.properties
,内容如下:
#数据库名称
cola.global.dbName=school_manager
cola.global.applicationName=school-manager
#目标工程输出目录,这里填写对应的工程的绝对路径
cola.code.outpath.cola-adapter=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-cola\\cola-adapter
cola.code.outpath.cola-infrast=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-cola\\cola-infrast
cola.code.outpath.cola-app=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-cola\\cola-app
cola.code.outpath.cola-domain=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-cola\\cola-domain
cola.code.outpath.cola-client=E:\\workspace\\tianhua-workspace\\code-maker\\codemaker-cola\\cola-client
#应用服务的plantUML类图文件,不配置则走基于数据表的方式生成代码
cola.domain.plantuml=SchoolManager.puml
4.3.4 代码模板配置
根据cola应用场景+动态ddd的能力,我们定义如下代码模板:
basController.ftl,bo.ftl,controller.ftl,convert.ftl,dto.ftl,enum.ftl,facadeimpl.ftl,gataway.ftl,dto.ftl,dtoddd.ftl,controllerddd.ftl,facadeddd.ftl,facadeimplddd.ftl
4.3.5 发布版本和详情
发布版本:1.1.0-SNAPSHOT
发布分支:cola-arch
发布内容:
- 支持cola应用架构代码生成,增加cola应用的template代码模板
- 增加基于plantuml类图的领域服务代码生成接口
/getproject/valueobject
/getproject/msgbody
/getproject/gataway
/getproject/acladapter
/getproject/command
/getproject/executor
/getproject/factory
/getproject/dtoboconvert
/getproject/voboconvert
/getproject/doboconvert
- 精简不同应用框架的代码生成配置
在每个应用框架配置下增加dubbo.domain.plantuml配置项,配置plantuml类图文件名称,支持基于类图-ddd的代码生成 ,如果不配置则不能借助plantuml类图生成基于领域服务ddd的代码,而是生成基于数据库表的常规代码 去除以下三个配置,
集中到application.properties文件中
*.global.package
*.global.author
*.global.applicationName
- 在springboot,cola,dubbo的代码模板目录下增加ddd元素的tempalte代码模板
- 将dynamic-ddd的代码生成服务整合到springboot,cola,dubbo的代码生成服务中,支持基于DDD思想的代码生成
- 扩展plantuml中类图标签,基于BO派生多个代码生成对象(vo,dto,facade,doboconvert,controller,voboconvert,dtoboconvert)
- 整合底层代码支持一套api,一套服务支撑springboot,cola,dubbo应用级代码生成和dynamic-ddd模块级代码生成
- 修复多个兼容性bug
- 整体上支持基于数据库表结构的代码生成和基于plantUML类图文档的代码生成
4.4 将动态DDD的能力应用到dubbo,cola,springboot应用上
4.4.0 设计概要
在cola-arch分支中已经借助cola应用代码融合了动态DDD的代码能力,因此如果想在功能上更加炫酷风骚,就需要将动态DDD的代码能力融合到dubbo和springboot应用代码上面,同时不能影响dynamic-ddd本身生成动态DDD代码的能力,这样的话就需要将基于数据库表字段的元数据模型向基于plantUML类图的class元数据模型靠拢,同时也要兼容只基于数据库表字段的代码生成模式。那达到的最终效果就是可以使用一套api生成dubbo,cola,springboot+动态ddd的应用工程代码。
4.4.1 模型设计
由于1.0.3之前的版本只支持了springboot应用的代码生成,在一路迭代之后,服务层代码和业务模型都发生了变化,基于数据库表字段的元数据模型需要转换到基于plantUML类图的class元数据模型。
最核心的一点就是TableBean对象需要转换成ClassBean对象,同时这个ClassBean代表的是DO类代码元素。
另外一方面通过plantUML类图中对BO的扩展就可以将DO类与BO进行关联,这样两种模型就可以融为一体。具体可以参考SchoolManager.puml中的BO包,这里我贴出来专门介绍一下:
上图以extend info为分界,以上的内容是BO类本身的数据,比如属性,方法这些。以下则是codeMaker自动扩展的信息。继续看一下:
tableKey:plantuml bo中的特殊属性-标示bo-table的对应关系
facadeKey:plantuml bo中的特殊属性-标示facade接口名称
controllerKey:plantuml bo中的特殊属性-标示controller类名
dtoKeyList:plantuml bo中的特殊属性-标示dto别名
voKeyList:plantuml bo中的特殊属性-标示vo类名
获取学生信息:定制化方法—rpc
分页获取学生信息: 定制化方法–http
上面的五个key在BO类上可以作为BO的派生类来与数据库表模型来进行融合,同时这些别名映射也为了vo,dto上在属性上更贴近这个BO,当然有些BO不需要这些扩展key也没关系,另外一方面可以可以不用这些扩展key和定制化方法声明。
另外在代码写服务上也分了三个服务,分别是:
WriteAppModuleService,WriteDynamicDDDModuleService,WriteFileService
4.4.2 代码生成配置
这里通过整体的设计优化之后,代码生成配置也做了一些简化。三大框架的代码生成配置都做了精简,将通用的都放在核心配置里,暂时用不到的配置全部删掉,理论上不需要用户花太多时间在配置上。另外代码逻辑也做了兼容,比如每个配置文件里都有plantuml的文件名配置,如果没有这个配置也是可以的。
4.4.3 代码模板配置
在cola-arch中做了相对较长时间的开发,就是为了一次性将动态DDD的代码生成能力融合到三大应用框架和架构,所以这里在不同的代码模板目录下增加了统一的与dynamic-ddd相关的代码模板,有些通过数据库实体映射的bo,dto元素会与融合后的元素相互冲突,所以这里通过加后缀来识别,比如template/cola下有bo.ftl,也有boddd.ftl,有facade.ftl,也有facadeddd.ftl。在融合之后cola,springboot,dubbo都具有了生成动态DDD代码的能力。整体上从配置和代码生成服务源码上看虽然显得有点冗余,但是为了兼容不同复杂度的应用项目,同时也为了快速实现和迭代这么做还是有价值的。
4.4.4 发布版本和详情
由于时间和精力有限,也为了尽快将DDD系列完结所以这里不会将动态DDD融合dubbo和springboot做分别的迭代,所以一次性发布了一个稍微大了一点的版本,整体上升级到了1.1.0。
通过上面的介绍可以知道从1.0.3开始到1.0.4再到1.1.0是有个完善的迭代升级的过程,这样对于想二次开发或者直接使用的开发者来说是非常友好的。
4.5 整体架构图
在上一篇文章中可以看到1.0.3之前的架构图还是相当简陋的,只有一些基础的功能,也只支持springboot。到目前为止,经过一系列迭代之后整个架构层面,功能模块设计层面做了一个全面的更新。这里我简单对codemaker-core项目工程的业务逻辑做了如下分层:
4.5.1 接口层
在接口层面依然保留了之前的代码生成模式,同时增加了更多代码元素生成的api。由于在接口层面上做了统一,很多接口都不需要参数就可以直接访问,所以整个接口设计和实现上尽量保持一套api支持三大架构的代码生成。
4.5.2 代码元素层
在代码元素层中代码元素这个概念在1.0.4之前的版本中其实没有突出出来,在动态DDD代码生成版本的迭代之后这个概念被显示的表达出来之后很多东西都变得非常明朗,很多工作也可以围绕这些代码元素展开。在这一层中主要表达在代码生成业务中,核心的模型就是代码元素,针对代码生成就是生成这些代码元素表达的代码。
那么如果我想新增代码元素的话,就可以在这一层进行定制化。如果要二次开发就可以在从这一层开始开始。
4.5.3 应用框架层
应用框架层在1.0.3和1.0.4中被逐步抽象出来作为顶层接口来看,这样的话整个代码生成逻辑会变得非常清晰,通过配置路由到不同的应用代码生成服务中,通过代码模板枚举标示来路由到不同的代码元素写服务中。
应用层目前看其实也比较稳定,如果要二次开发的话针对自己公司的框架进行适配也是非常方便的,因为codemaker-core工程已经提供了多个实现,参考cola,dubbo的实现逻辑二次开发完全 没有问题。
4.5.4 服务层
这里对codemaker整个项目做了一层归纳总结,服务层提供了一些基础能力让上层来使用,比如生成e-r图的,整个能力可以越过应用框架层来独立使用。
五、使用步骤
上面说了这么这么多,那下面来真正演示一遍这个代码生成平台到底怎么用。
- 基础设备:eclipse,idea,maven,mysql,plantUML插件,电脑,网络
- 准备一个数据库,在codemaker-core的resources目录中的application.properties配置文件中配置数据源
- 在application.properties中配置要生成的应用类型,可选值是cola,dubbo,springboot.
- 在对应应用类型的配置里配置要工程目录,数据库名称,plantUML类图文件名,plantUML类图文件存放在codemaker-core的resources/ddd-plantuml目录下。
假设是dubbo类型的应用,配置内容参考如下:
#数据库名称
dubbo.global.dbName=school_manager
#目标工程输出目录,这里填写对应的工程的绝对路径
dubbo.code.outpath.dubbo-common=/Users/sourceSpace/code-maker/codemaker-dubbo/dubbo-common
dubbo.code.outpath.dubbo-api=/Users/sourceSpace/code-maker/codemaker-dubbo/dubbo-api
dubbo.code.outpath.dubbo-core=/Users/sourceSpace/code-maker/codemaker-dubbo/dubbo-core
#应用服务的plantUML类图文件,不配置则走基于数据表的方式生成代码
dubbo.domain.plantuml=SchoolManager.puml
- 启动codemaker-core工程,启动方式参考sprintboot项目。
- 打开浏览器访问127.0.0.1:8099/makeall
- 执行完成之后查看codemaker-dubbo工程下是否已生成对应项目的代码文件。另外一方面如果不配置dubbo.domain.plantuml则只生成基于数据库表字段的代码文件。
- 单独使用dynamic-ddd的代码生成能力则只需要配置projecttemplate-dynamicddd.properties文件,内容参考如下:
#目标工程输出目录,这里填写对应的codemaker-dynamicddd工程的绝对路径
dynamicddd.code.outpath=/Users/sourceSpace/code-maker/codemaker-dynamicddd
#领域plantUML 类图
dynamicddd.domain.plantuml=SchoolManager.puml
- 将SchoolManager.puml文件放在codemaker-core的resources/ddd-plantuml目录下
- 启动codemaker-core工程
- 打开浏览器访问127.0.0.1:8099/makeddd
- 执行完成之后查看codemaker-dynamicddd工程下是否已生成对应plantUML类图的代码文件。
六、结语
代码生成项目到现在可以告一段落了,未来有时间的话可以基于plantUML类图和时序图增加一些新的功能特性,比如:
- 支持多个plantUML类图同时解析生成代码
- 解析plantUML代码调用时序图融入到极速模式中。
希望喜欢的朋友们可以点赞转发哈,欢迎给codeMaker点个star哈,源码链接如下:
https://gitee.com/sky-painting/code-maker
更多推荐
所有评论(0)