往期精选(欢迎转发~~)
- Java全套学习资料(14W字),耗时半年整理
- 2年经验总结,告诉你如何做好项目管理
- 消息队列:从选型到原理,一文带你全部掌握
- 我肝了三个月,为你写出了GO核心手册
- RPC框架:从原理到选型,一文带你搞懂RPC
- 如何看待程序员35岁职业危机?
- 更多…
实现一个简易版的DDD脚手架,并给出落地的示例。
前言
在前面的《一文带你学习DDD,全是干货!》文章中,里面讲述了一个Demo,虽然有DDD的思想,但是感觉整体很乱,每一层都没有做好隔离,所以我参考小米内部的DDD脚手架,对这个Demo进行了重构,也就诞生了我这个版本,代码已经上传到GitHub中,大家可以自取:github.com/lml20070115…
1 | bash复制代码git clone git@github.com:lml200701158/ddd-framework.git |
项目介绍
- 主要是围绕用户、角色和两者的关系,构建权限分配领域模型。
- 采用DDD 4层架构,包括用户接口层、应用层、领域层和基础服务层。
- 数据通过VO、DTO、DO、PO转换,进行分层隔离。
- 采用SpringBoot + MyBatis Plus框架,存储用MySQL。
项目目录
项目划分为用户接口层、应用层、领域层和基础服务层,每一层的代码结构都非常清晰,包括每一层VO、DTO、DO、PO的数据定义。对于每一层的公共代码,比如常量、接口等,都抽离到ddd-common中。
1 | less复制代码./ddd-application // 应用层 |
项目解读
数据库
包括3张表,分别为用户、角色和用户角色表,一个用户可以拥有多个角色,一个角色可以分配给多个用户。
1 | SQL复制代码create table t_user |
基础服务层
仓储(资源库)介于领域模型和数据模型之间,主要用于聚合的持久化和检索。它隔离了领域模型和数据模型,以便我们关注于领域模型而不需要考虑如何进行持久化。
比如保存用户,需要将用户和角色一起保存,也就是创建用户的同时,需要新建用户的角色权限,这个可以直接全部放到仓储中:
1 | java复制代码public AuthorizeDO save(AuthorizeDO user) { |
仓储对外暴露的接口如下:
1 | java复制代码// 用户领域仓储 |
基础服务层不仅仅包括资源库,与第三方的调用,都需要放到该层,Demo中没有该示例,我们可以看一个小米内部具体的实际项目,他把第三方的调用放到了remote目录中:
领域层
聚合&聚合根
我们有用户和角色两个实体,可以将用户、角色和两者关系进行聚合,然后用户就是聚合根,聚合之后的属性,我们称之为“权限”。
对于地址Address,目前是作为字段属性存储到DB中,如果对地址无需进行检索,可以把地址作为“值对象”进行存储,即把地址序列化为Json存,存储到DB的一个字段中。
1 | java复制代码public class AuthorizeDO { |
领域服务
Demo中的领域服务比较薄,通过单位ID后去获取单位名称,构建单位信息:
1 | java复制代码@Service |
我们其实可以把领域服务再进一步抽象,可以抽象出领域能力,通过这些领域能力去构建应用层逻辑,比如账号相关的领域能力可以包括授权领域能力、身份认证领域能力等,这样每个领域能力相对独立,就不会全部揉到一个文件中,下面是实际项目的领域层截图:
领域事件
领域事件 = 事件发布 + 事件存储 + 事件分发 + 事件处理。
这个Demo中,对领域事件的处理非常简单,还是一个应用内部的领域事件,就是每次执行一次具体的操作时,把行为记录下来。Demo中没有记录事件的库表,事件的分发还是同步的方式,所以Demo中的领域事件还不完善,后面我会再继续完善Demo中的领域事件,通过Java消息机制实现解耦,甚至可以借助消息队列,实现异步。
1 | java复制代码/** |
1 | java复制代码/** |
应用层
应用层就非常好理解了,只负责简单的逻辑编排,比如创建用户授权:
1 | java复制代码@Transactional(rollbackFor = Exception.class) |
查询用户授权信息:
1 | java复制代码@Override |
细心的同学可以发现,我们应用层和领域层,通过DTO和DO进行数据转换。
用户接口层
最后就是提供API接口:
1 | java复制代码@GetMapping("/query") |
数据的交互,包括入参、DTO和VO,都需要对数据进行转换。
项目运行
- 新建库表:通过文件”ddd-interface/ddd-api/src/main/resources/init.sql”新建库表。
- 修改SQL配置:修改”ddd-interface/ddd-api/src/main/resources/application.yml”的数据库配置。
- 启动服务:直接启动服务即可。
- 测试用例:
- 请求URL:http://127.0.0.1:8087/api/user/save
- Post body:{“userName”:”louzai”,”realName”:”楼”,”phone”:13123676844,”password”:”***“,”unitId”:2,”province”:”湖北省”,”city”:”鄂州市”,”county”:”葛店开发区”,”roles”:[{“roleId”:2}]}
结语
这段时间主要是学习DDD如何落地,也一直想写个DDD的Demo,感觉这次学习周期稍微有点长。下一篇文章会将之前文章的重点内容,包括近期对DDD的学习,以及一些自己的理解,再出一篇“理论到实践”相关的文章,算是对自己近一个多月学习的总结。
欢迎大家多多点赞,更多文章,请关注微信公众号“楼仔进阶之路”,点关注,不迷路~~
本文转载自: 掘金