项目架构MVC,DDD学习
写在前面
本文一起看下项目架构DDD,MVC相关的内容。
1:MVC
不管我们做什么项目,自己想想其实只是做了三件事,如下:
其实,这三件事完全在一个类中做完也可以可以正常把项目完成的,就像下面这样:
@RequestMapping("/xxx")
public void XxxHttp {private String userId;private String username;public Response queryUerById(String userId) {queryFromDb(userId);Response res = assembleRes();return res;}// 查询数据public void queryFromDb(String userId) {// 查询数据库的操作,获取username等信息}// 组装响应public Response assembleRes() {}
}
试想下,如果所有的东西全部都塞到一个类里去,那么这个后期项目的可维护性和可扩展性几乎为0。针对这个问题,系统架构就应运而生了,而MVC就是系统架构的一种,当然DDD也是,本文后边部分也会学习到。这里,先来只看MVC相关的内容,MVC通过分层的思想来解耦程序,增加可维护性和可扩展性,把不同的属性分配到不同类型的对象中,把方法进行更细粒度的划分,大概如下图:
对每部分功能进行细分后,MVC同样会将其划分到不同的层,即文件夹中,从而使得结构更加的清晰,基本上如下图:
为了对MVC有一个更加清晰的认识,以springboot的方式来看一个实际的项目例子:
为了方便学习,我录制了一个视频放在这里:
项目架构MVC
视频中MVC系统架构用到的关键层所对应的文件夹都已经创建完毕了。详细的参考下源码 。
再来看下最后的效果:
- 通过单元测试测试
- 访问接口
这样,一个典型的MVC项目我们就完成了!
接着继续来看DDD项目又是咋回事。
2:DDD
源码 。
DDD全称,domain-driven design,即领域驱动设计,是一种系统架构设计的思想,根据这种思想我们可以通过不同的模块来组织我们的项目结构,其中一种可能的组织方式如下:
注意:默认使用spring boot。
app:定义项目全局内容,如启动类,AOP配置,dockerfile,启动脚本等。
types:定义公用的常量类,枚举类,响应结果类,带分页的类等。
api:定义需要对外暴漏的类和接口,如dubbbo的服务描述接口,以及请求和响应中需要用到的类。
domain:最关键的模块,定义出不同业务模块的仓储接口,服务类(给出具体的实现),model(聚合类,entity,valobjs)。
infrastructure:对domain的仓储接口给出具体的实现,以及定义映射数据库表的PO类。
trigger:触发模块,作为触发程序执行的模块,如接收http接口的controller,接收rpc请求的provider,消费消息的消费者,以及自动定时执行的job等。
本文也会按照这种组织方式来共同进行学习。
2.1:app
定义app之前先来看下app模块中写啥东西:
全局的配置可以写在这里,比如:
1:项目级的AOP配置
2:项目级的config配置(比如配置redis的序列化方式等)
3:打包镜像,启动脚本(start.sh等)
2.2:types
定义types之前来看下types模块中写啥东西:
来定义一些通用的类型,比如常量类Constants,接口响应用到的公共对象,
比如定义了响应状态码和data数据ReponseEntity(当然不一定非得是这个名字)对象。
当然其他的只要是各个业务模块都可用用到的公共的类都可以定义在这里,但注意一定要是公用的哟!!!
- 一个可能的常量类
// 你们都甭继承我!!!
public final class Constants {public static final String ERROR_MSG = "你干哈,都给我搞出错了!!!";
}
- 一个可能的封装相应信息的公共类
@Builder
public class ResEntity<T> {private T data;private int code;
}
其他的可根据具体情况定义在这里。
2.3:api
定义api之前来看下api模块中写啥东西:
如外部需要用到的rpc描述文件(需要打成jar包,提供出来),以及描述文件中需要用到的相关类,
如入参以及返回的对象等。需要对外暴漏的类的和接口(如dubbo服务描述接口)
因此,一般该模块是提供出去给外部使用的,当然自己也会使用到。
- 定义可能的dubbo接口
/*** dubbo的某个对外服务接口*/
public interface DubboXxxInterface {DubboReqObj querySth(DubboReqObj dubboReqObj);
}
- 入参和出参可能的用到的类
/*** dubbo的某入参对象(使用者需要知道)*/
public class DubboReqObj {
}/*** dubbo的某出参对象(使用者需要知道)*/
public class DubboResObj {
}
2.4:domain
定义domain之前来看下domain模块中写啥东西:
首先按照业务模块,一个业务模块一个文件夹。在每个文件夹下分别定义的信息如下:
model:同MVC系统架构的domain层定义的内容aggregates:组合valobjs,因为某个业务可能需要多种VO组合在一起才能满足需求,当然也可以聚合entity,所以该类对象就是用来聚合entity和valobjs,从而满足业务对数据需求的的一类对象entity:一般和数据库实体对象是1v1的关系,但是相比与数据库实体PO,只包含其中业务相关的信息,比如id啊,创建时间啊,删除状态啊这些是不需要的,po的一些有限状态的字段在entity中使用枚举来表示,po的逗号分隔的信息在entity使用list形式来表示,总是呢,其实就是将po转换为更加符合业务需要的方式,这种更加符合业务需要的方式就是entity了,比如有PO,信息是private int id, private int status(1代表xxx 2代表xxx), private varchar hobbies(逗号分割),转换为entity就是 private StatusEnum status(1代表xxx 2代表xxx), private List hobbiesList,大概这种!哦,对,entity还有另一个作用对po做防腐,意思就是不要你随便糟蹋,嚯嚯PO同学。valobjs:应该就是VO,给UI使用的
repository: 定义数据库操作的接口,infrastructure会通过依赖倒置的方式来提供具体的实现
service:具体服务代码的实现,同MVC系统架构的service,不过只定义本业务模块的相关服务类,相比于MVC的service范围更小,即是其子集,需要注意名字不一定非得是xxxService,也可以是xxxEgine,xxxFilter,xxxProcessor,xxxHandler等这种,当然为了能够更加清晰也可以再创建对应的engine,filter等子文件夹
- 可能的model信息(聚合对象,entity,valobjs)
- 可能的仓储接口
/*** 用户仓库类*/
public interface IUserRepository {UserAggregates queryUserByIds(List<String> userIdList);
}
- 具体服务类
public interface IUserService {
}public class UserServiceImpl implements IUserService {// 通过spring容器注入在infrastructure模块中提供的仓库具体实现@Resourceprivate IUserRepository userRepository;
}
以上private IUserRepository userRepository
我们会在infrastructure基础设施模块提供具体实现,并交给spring管理。
2.6:infrastructure
定义infrastructure之前来看下infrastructure模块中写啥东西:
1:基于domain层提供数据库操作的具体实现(在domain层中我们定义了数据库操作的接口了不是),与domain是一种依赖倒置的关系
2:和数据库表对应的PO也在这里写
3:对domain定义的仓库接口提供具体实现,因此需要依赖于domain模块,但注意domain模块不能依赖于infrastructure模块,但domain又需要具体的数据库接口实现的dao,咋办呢?通过spring 容器注入即可。
- user表PO
/*** 数据库表user的映射(注意,需要做防腐处理,避免最重要的数据查询出现问题!!!)*/
public class UserPO {/** 用户ID */private Long id;/** 用户名称 */private String userId;/** 用户昵称 */private String userNickname;/** 用户头像 */private String userHead;/** 账号密码 */private String userPassword;/** 创建时间 */private Date createTime;/** 修改时间 */private Date updateTime;}
- dao
@Mapper
public interface IUserDao {List<UserPO> queryUserList();}
- 仓储实现
@Component
public class UserRepository implements IUserRepository {@Resourceprivate IUserDao userDao;@Overridepublic UserAggregates queryUserByIds(List<String> userIdList) {List<UserPO> userPOS = userDao.queryUserList();UserAggregates userAggregates = new UserAggregates();// TODO userPOS -> userAggregates 略!for (UserPO userPO : userPOS) {System.out.println(userPO);}return userAggregates;}
}
2.7:trigger
定义trigger之前来看下trigger模块中写啥东西:
写触发程序执行的相关内容,如
1:接收http请求的controller
2:接收mq消息的消费者
3:rpc调用的server(如dubbo server)
4:定时任务(如自己定义的timer,或者是等待xxx-job等分布式任务调度框架执行的代码)
5;其他等
- http
@RestController
public class Controller {// 注入domain的service实现类就可以编写具体的处理逻辑了,这和常规的mvc就一样了!!!@Resourceprivate IUserService userService;@RequestMapping("/user")public ResEntity<String> queryUser() {// TODO 使用 userService写具体的逻辑,略!!!return ResEntity.<String>builder().data("cccccc").build();}
}
- rpc
/*** 某dubbo的provider*/
public class XxxDubboProvider {
}
- timer
/*** 某定时执行的任务*/
public class SomeXxxJob {
}
为了更好的帮助你理解DDD的内容,我录制了一个视频,放在这里:
项目架构DDD,手把手从零搭建一个落地的DDD项目,没有枯燥的理论,就是写代码!!!
写在后面
参考文章列表
架构的本质之MVC架构 —— Java简明教程,一套简单、清晰、明了的Java学习路线资料!!! 。
相关文章:
项目架构MVC,DDD学习
写在前面 本文一起看下项目架构DDD,MVC相关的内容。 1:MVC 不管我们做什么项目,自己想想其实只是做了三件事,如下: 其实,这三件事完全在一个类中做完也可以可以正常把项目完成的,就像下面这…...
SQLite的PRAGMA 声明
PRAGMA 语句是特定于 SQLite 的 SQL 扩展,用于 修改 SQLite 库的操作或查询 SQLite 库 内部(非表)数据。PRAGMA声明使用相同的 接口作为其他 SQLite 命令(例如 SELECT、INSERT)但 在以下重要方面有所不同: …...
使用ArrayList.removeAll(List list)导致的机器重启
背景 先说一下背景,博主所在的业务组有一个核心系统,需要同步两个不同数据源给过来的数据到redis中,但是每次同步之前需要过滤掉一部分数据,只存储剩下的数据。每次同步的数据与需要过滤掉的数据量级大概在0-100w的数据不等。 由…...
如何在项目中使用uni-ui组件库
1、安装uni-ui npm i dcloudio/uni-ui 2、组件自动引用 配置easycom 使用 npm 安装好 uni-ui 之后,需要配置 easycom 规则,让 npm 安装的组件支持 easycom 打开项目根目录下的 pages.json 并添加 easycom 节点: // pages.json {"e…...
redis的过期策略和内存淘汰机制(redis篇)
分享并学习一下redis的过期策略和内存淘汰机制 在平时的工作或者学习中,即便自己没有实打实的用过redis。但是能有对这方面的思考,再结合一些实际场景和理论,那么我相信自己或者你都会越来越厉害的。 首先,我们需要认清为啥redis要…...
Java中Runnable和Callable有什么不同?(企业真题)
Java中Runnable和Callable有什么不同? 与之前的方式的对比:与Runnable方式的对比的好处 call()可以有返回值,更灵活 call()可以使用throws的方式处理异常,更灵活 Callable使用了泛型参数,可以指明具体的call()的返回值…...
图机器学习导论
图:描述关系数据的通用语言,起源于哥尼斯堡七桥问题 传统的机器学习:数据样本之间独立同分布,简单拟合数据边界,在传统的机器学习中,每个数据样本彼此无关。传统的神经网络,只能处理简单的表格、…...
地推网推拉新平台哪家强?一文清楚告诉你
在当今这个充满副业的时代,地推网推拉新平台的寻找与对接成为了许多人关注的焦点。那么,我们应该如何找到那些既靠谱又有潜力的拉新项目呢? 经过深入研究和全网检索,我为大家盘点了5个值得一试地推网推拉新平台。 尤其是“聚小推…...
Day:004(4) | Python爬虫:高效数据抓取的编程技术(数据解析)
XPath工具 浏览器-元素-CtrlF 浏览器-控制台- $x(表达式) Xpath helper (安装包需要科学上网) 问题 使用离线安装包 出现 程序包无效 解决方案 使用修改安装包的后缀名为 rar,解压文件到一个文件夹,再用 加载文件夹的方式安装即可 安装 python若使用…...
(80) 只出现一次的数字(81)反转字符串
文章目录 1. 每日一言2. (80) 只出现一次的数字2.1 解题思路2.2 代码 3. (81)反转字符串3.1 解题思路3.2 代码 4. 结语 1. 每日一言 生活是一场即兴表演,值得庆幸的是我们总是有所感受,并且将一直感受下去。 2. (80) 只出现一次的数字 题目链接&#x…...
基于拉格朗日分布算法的电动汽车充放电调度MATLAB程序
微❤关注“电气仔推送”获得资料(专享优惠) 程序简介 该模型主要做的是基于拉格朗日分布算法的电动汽车充放电调度模型。利用蒙特卡洛模拟法模拟出电动汽车负荷曲线,并求解出无序充电功率曲线和有序充电曲线,该模型在电动汽车个…...
【Linux 学习】进程优先级和命令行参数!
1. 什么是优先级? 指定进程获取某种资源(CPU)的先后顺序; Linux 中优先级数字越小,优先级越高; 1.1 优先级和权限的区别? 权限 : 能不能做 优先级: 已经能了,但是获…...
Git删除未跟踪的文件Untracked files
在 Git 中,要删除未跟踪的文件(Untracked files),你可以使用 git clean 命令。请注意,这个命令会从你的工作目录中永久删除这些文件,因此在执行之前请确保你不再需要这些文件或已经妥善备份。 以下是如何使…...
S7-1200PLC控制V90伺服通过FB284实现位置控制的方法
S7-1200PLC控制V90伺服通过FB284实现位置控制的方法 通过西门子报文111和FB284功能块 在V-ASSISTANT中将V90 PN设置控制模式为"基本位置控制(EPOS)" V90 PN与PLC采用PROFINET RT通信方式并使用西门子报文111。 在博途中V90 PN的设备视图中更改报文为:报文111 安装…...
2024年阿里云优惠券领取和使用方法
阿里云优惠代金券领取入口,阿里云服务器优惠代金券、域名代金券,在领券中心可以领取当前最新可用的满减代金券,阿里云百科aliyunbaike.com分享阿里云服务器代金券、领券中心、域名代金券领取、代金券查询及使用方法: 阿里云优惠券…...
工业项目中你连PLM系统都没见过?
什么是 PLM 软件? PLM 软件是用于管理全球供应链中产品或服务全生命周期环节的解决方案。它包括从物料、零部件、产品、文档、规定、工程变更单到质量工作流的数据管理。 PLM 的发展历史 从最初的产品设计管理到如今的数字化转型和智能化生产,PLM 在不断…...
【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬浮按钮弹出对话框
往期回顾: 【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客 【QT入门】Qt自定义控件与样式设计之QPushButton常用qss-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬…...
C盘变红怎么办?免费的系统C盘清理方法,C盘空间占用克星
百夫说:分享免费又好用的工具,是一件快乐的事情。 正文: 起因:C盘报警,系统变慢 立即下载XX系统清理大师,搜索出垃圾数据近30G,开心的点击“一键清理”,结果提示要收费:…...
简述VPS 与 Apache 搭建网站方式对比:新手科普指南
在互联网时代,拥有一个网站对于个人、企业以及组织来说已经成为了必备的一项资源。然而,对于新手来说,如何搭建一个网站可能是一个挑战。在这篇文章中,我将探讨两种常见的搭建网站的方式:使用虚拟专用服务器࿰…...
js获取年月份
一、date 如何使用、如何获取年月日时分秒、时间戳、如何获取指定日期的时间戳或周几 1..Date 对象用于处理日期和时间。 创建 Date 对象的语法: var myDatenew Date() 获取年月日时分秒: // 格式化日对象 const getNowDate () > {let date new …...
Promise常用方法及区别
一、实例方法 let _fun new Promise((resolve, reject) > {reject("失败!"); }); /* resolve:异步操作成功时调用的回调函数。 reject:异步操作失败时调用的回调函数。 */ _fun.then(res > { // 成功console.log(res: , re…...
pyqt 标题栏设置
在PyQt中,可以通过QWidget或其子类(如QMainWindow或QDialog)的setWindowTitle()方法来设置窗口的标题栏。以下是一个简单的例子,展示了如何为应用程序的主窗口设置标题: import sys from PyQt5.QtWidgets import QApp…...
关于可视化大屏适配
一、目前市场上适配方案有两种; vw、vh方案: 原理:按照设计稿的尺寸,将px按比例计算转为vw和vh; 优点:不会存在失真情况、可以动态计算图表的宽高,字体等,灵活性较高,…...
如何用composer来安装和配置LAMP环境?
LAMP环境是一个开发和运行Web应用程序的常见环境,它由Linux、Apache、MySQL和PHP组成。Composer是一个用于管理PHP依赖关系的工具,可以方便地安装和配置LAMP环境中的各种软件包。下面是使用Composer安装和配置LAMP环境的步骤: 安装Composer&a…...
题目:学习使用按位取反~。
题目:学习使用按位取反~。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leav…...
vue3第十六节(keep-alive 内置组件)
keep-alive 1、目的 在使用组件时,有时我们需要将组件进行缓存,而不是重新渲染,用以提高性能,避免重复加载DOM,提升用户的体验; keep-alive 组件可以做到这一点,它允许你缓存组件实例…...
跨域和跨域解决方案
跨域 制定HTML规则时,出于安全的考虑,一个源的网站不允许与另一个源的资源进行交互,浏览器制定此规则为同源策略。 同源即指的网站具有相同的域,即 协议(protocol)、主机(host)、端口号(port) 相同。 跨域资源嵌入是允许的&am…...
数学基础:矩阵
来自: https://www.shuxuele.com/algebra/matrix-determinant.html 一、矩阵的行列式 二、矩阵简单知识 三、矩阵乘法 四、单位矩阵 五、逆矩阵一:简单2阶矩阵求法 六、逆矩阵二:3、4阶逆矩阵求法 6.1 求余子式矩阵 6.2 求代数余子式矩阵 6.3 求伴随矩阵…...
Windows完全卸载MySQL后再下载安装(附安装包)
目录 友情提醒第一章:如何完全卸载干净mysql教程(三个步骤完全卸载)1)步骤一:卸载程序2)步骤二:删除文件3)步骤三:删除注册表信息 第二章:下载软件两种方式1&…...
【央国企专场】——国家电网
国家电网目录 一、电网介绍1、核心业务2、电网组成 二、公司待遇三、公司招聘1、招聘平台2、考试安排2.3 考试内容 一、电网介绍 1、核心业务 国家电网公司(State Grid Corporation of China,简称SGCC)是中国最大的国有企业之一,…...
网站建设郑州/百度seo优化分析
https://blog.csdn.net/u013032340/article/details/53608790 sign一下以备用 第一种方法: 一般的XP安装光盘里都带破解管理员密码 找张安装盘进入修改一下管理员密码就可以了 第二种方法: 1.xp启动按F8 出现选项后选择“带命令的安全模式” 2.1分钟左右…...
b2b电子商务网站调研报告word文档形式/海外网站
extends可以理解为全盘继承了父类的功能implements可以理解为为这个类附加一些额外的功能举个例子,Animal是一个父类,cat,dog,bird,insect都extends了Animal,但是cat,dog,bird还可以…...
网页设计公司网站/福州seo建站
为什么80%的码农都做不了架构师?>>> 故障界面 有些服务器的 rc.local 里有些奇怪的东西。比如sleep 600,然后启动的时候就: 这个 no limit 实际上是可配置的 /lib/systemd/system/rc.local.service:[Unit] Descriptio…...
网站开发前台开发/小程序拉新推广平台
项目介绍 随着人们生活水平的逐步提高,旅游成了大家必不可少放松项目,每当笔者走到一个美丽的景点,就会忍不住拿起数码相机照上几张留做回忆。虽然照片最后会存入到自己的电脑里,但是时间一长、照片一多,这些有着勾起…...
网站开发工具 mac/如何在百度提交网站
一时间不知道怎么开头了,直接上图吧! 本人技术不高,正在学习中, 要是有 喜欢 .Net,觉得酷的,欢迎来 QQ群 316497348 交流分享! 转载于:https://www.cnblogs.com/Hangle/p/4208147.html...
上海崇明网站建设/企业建站用什么好
一、Struts1.x 1.<html:link action"/action">不用关心Web应用程序的路径和ActionServlet的映射关系。 可以自动附加sessionid参数进行url重写。 可以对参数信息进行url编码。 备注:<c:url>标准标签也有<html:link>标签的后两个功能。 …...