项目架构MVC,DDD学习

news2025/1/21 22:10:02

写在前面

本文一起看下项目架构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模块中提供的仓库具体实现
    @Resource
    private 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 {
    @Resource
    private IUserDao userDao;

    @Override
    public 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就一样了!!!
    @Resource
    private 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学习路线资料!!! 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1576471.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL-主从复制:概述、原理、同步数据一致性问题、搭建流程

主从复制 1. 主从复制概述 1.1 如何提升数据库并发能力 一般应用对数据库而言都是“读多写少”&#xff0c;也就说对数据库读取数据的压力比较大&#xff0c;有一个思路就是采用数据库集群的方案&#xff0c;做主从架构、进行读写分离&#xff0c;这样同样可以提升数据库的并…

mysql结构与sql执行流程

Mysql的大体结构 客户端&#xff1a;用于链接mysql的软件 连接池&#xff1a; sql接口&#xff1a; 查询解析器&#xff1a; MySQL连接层 连接层&#xff1a; 应用程序通过接口&#xff08;如odbc,jdbc&#xff09;来连接mysql&#xff0c;最先连接处理的是连接层。 连接层…

【Linux】达梦数据库安装部署(附详细图文)

目录 一、安装前的准备工作 1.检查操作系统配置 &#xff08;1&#xff09;获取系统位数 getconf LONG_BIT &#xff08;2&#xff09;查看操作系统release信息 cat /etc/system-release &#xff08;3&#xff09;查询系统名称 uname -a &#xff08;4&#xff09;查看操…

基于Spring Boot的网上书城系统(带文档)

主要功能 本次设计任务是要设计一个网上书城管理系统&#xff0c;通过这个系统能够满足网上书城的管理及用户的图书信息管理及购物功能。系统的主要功能包括&#xff1a;首页、个人中心、用户管理、图书类型管理、图书分类管理、图书信息管理、我的收藏管理、系统管理、订单管…

websocket实践

文章目录 背景WebSocket API使用场景优点 实例步骤 1: 设置 WebSocket 服务器步骤 2: 创建客户端 HTML 页面步骤 3: 测试 WebSocket 通信注意事项实际操作 参考资料 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它使得浏览器和服务器只需建立一个连接&#xff0c;…

SWM341系列应用(MPU屏应用)

SWM341系列 MPU屏应用 1、MPU屏写入时序设置&#xff08;设置单位为周期&#xff09;&#xff0c;根据ST7789规格书规定的最小时序要求&#xff0c;建议MPU屏时序按照ST7789手册配置,建议配置的参数注释。例如WRRise_CSRise&#xff0c;时序图要求是最低10ns&#xff0c;根据计…

1.8.3 卷积神经网络近年来在结构设计上的主要发展和变迁——GoogleNet/inception-v1

1.8.3 卷积神经网络近年来在结构设计上的主要发展和变迁——GoogleNet/ inception-v1 前情回顾&#xff1a; 1.8.1 卷积神经网络近年来在结构设计上的主要发展和变迁——AlexNet 1.8.2 卷积神经网络近年来在结构设计上的主要发展和变迁——VGGNet GoogleNet问题 在VGGNet简单堆…

分类预测 | Matlab实现ABC-LSSVM人工蜂群算法优化最小二乘支持向量机数据分类预测

分类预测 | Matlab实现ABC-LSSVM人工蜂群算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现ABC-LSSVM人工蜂群算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现ABC-LSSVM人工蜂群算法优化最小二乘支…

Redis中的Sentinel(六)

Sentinel 选举领头Sentinel. 当一个主服务器被判断为客观下线时&#xff0c;监视这个下线主服务器的各个Sentinel会进行协商&#xff0c;选举出一个领头Sentinel,并由领头 Sentinel对下线主服务器执行故障转移操作。以下是Redis选举领头Sentinel的规则和方法: 1.所有在线的S…

LabVIEW厂房漏水检测监控系统

LabVIEW厂房漏水检测监控系统 随着信息技术和智能制造的快速发展&#xff0c;对于精密仪器和重要物品存放场所的环境监控日益重要&#xff0c;特别是防止漏水带来的潜在风险。漏水不仅可能导致珍贵资料或仪器的损坏&#xff0c;还可能引发安全事故&#xff0c;给企业和研究机构…

在 C++ 中轻松实现字符串与字符数组的相互转换

在 C 中轻松实现字符串与字符数组的相互转换 引言一、将字符串转换为 char 数组1.1、C 中的 c_str()和 strcpy()函数1.2、使用 for 循环中的字符串到字符数组的转换 二、将 char 数组转换为字符串2.1、C 运算符 2.2、C 重载 运算符2.3、C 字符串内置构造函数 三、总结 引言 本…

阿里云服务器可以干嘛 阿里云服务器应用场景有哪些

阿里云服务器可以干嘛&#xff1f;能干啥你还不知道么&#xff01;简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云百科aliyunbaike.com整理阿里云服务器的用途&#xff1a; 阿里云服务器活动 aliyunbaike.com…

qt环境搭建-镜像源安装Qt Creator(5.15.2)以及配置环境变量

前言&#xff1a; 版本&#xff1a;5.15.2 镜像源&#xff1a;ustc与清华 纯小白&#xff0c;找了半天的镜像源安装qtcreator&#xff0c;搞了半天结果安装的是最新的&#xff0c;太新的对小白很不友好&#xff0c;bug比较多&#xff0c;支持的系统也不全&#xff0c;口碑不…

011_C标准库函数之<time.h>

头文件<time.h>中说明了一些用于处理日期和时间的类型和函数。其中的一部分函数用于处理当地时间&#xff0c;因为时区等原因&#xff0c;当地时间与日历时间可能不相同。clock_t和time_t是两个用于表示时间的算术类型&#xff0c;而struct tm则用于存放日历时间的各个成…

配置vscode用于STM32编译,Debug,github上传拉取

配置环境参考&#xff1a; Docs 用cubemx配置工程文件&#xff0c;用VScode打开工程文件。 编译的时候会有如下报错&#xff1a; vscode出现process_begin :CreateProcess failed 系统找不到指定文件 解决方案&#xff1a;在你的makefile中加上SHELLcmd.exe就可以了 参考…

mysql jdbc数据库速成总结

第一步导图jar包 我们下载一个jar 按照我的习惯是把这个jar包放在桌面上 方便后续操作 然后对这个jar包ctrl c复制 接着我们在idea里面创建一个目录 我们命名为lib 然后在这个lib安ctrl V进行粘贴 然后右键这个lib 找到添加为库 我的idea好像没有选择 只有添加为模块 点…

【LeetCode: 455. 分发饼干 + 贪心】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

2024/4/1—力扣—最小高度树

代码实现&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ struct TreeNode* buildTree(int *nums, int l, int r) {if (l > r) {return NULL; // 递归出口}struct…

【AI】ubuntu 22.04 本地搭建Qwen-VL 支持图片识别的大语言模型 AI视觉 【2】 4060ti 16G 也顶不住

接上篇 【AI】ubuntu 22.04 本地搭建Qwen-VL 支持图片识别的大语言模型 AI视觉-CSDN博客 迁移到4060ti 16G 环境下&#xff0c;仍然报错&#xff0c;显存不足&#xff01;

一切皆是为了交流-DDD通用语言

通用语言是什么&#xff1f; 通用语言是一种在特定领域内的沟通方式&#xff0c;可以由文字、语言、手势、图像等一切与达到沟通目的的元素组成。 比如&#xff0c;在中国内&#xff0c;方言是闽南的小王与方言是粤语的小张进行交流&#xff0c;那么&#xff0c;普通话是他们…