Web工程结构解析:从MVC分层到DDD领域驱动

MVC架构------模型、视图、控制

MVC代表Model-View-Controller(模型-视图-控制器)三个组件的缩写,旨在通过分层设计实现代码解耦,以提升代码的可维护性和复用性。

三个模块的功能分别为:

  • 控制器 Controller :负责接收用户请求,转发到对应的处理模块,调用业务层Service并把结果返回给视图View,不可直接调用Dao
  • 模型 Model :负责处理具体的业务逻辑,包括与数据库的交互,该层在项目结构中的体现为Service业务层,通常聚合Dao持久层;
  • 视图 View :只负责展示数据,不包含任何业务逻辑,项目中通常为htmlftl等标记语言。

整体流程如下图:

教科书中的经典 MVC 架构 认为,模型Model层 应该只包含POJO等用于封装数据的实体类,仅作为数据载体,不承担业务逻辑与数据访问操作;而Service业务层 和 Dao持久层,属于 Spring 项目独有的后端分层架构,不属于经典 MVC 定义。

笔者认为,实际企业级 Spring 项目下的 MVC 架构应理解为:

  1. Controller 用于接收并转发用户请求,聚合Service实例以调用业务逻辑;
  2. Service 负责完成具体逻辑,结合持久层,通常聚合Dao
  3. Dao 负责完成与数据库的交互,方法上注解添加具体sql语句
  4. Pojo 接收中间结果的实体类,简化传递类型
  5. html等前端页面,负责接收并展示数据,同时将用户请求转发到Controller控制层

项目结构通常为:

  • 控制层 Controller:请求处理包Controller
  • 模型层 Model:实例对象Pojo、业务包Service和持久层包Dao
  • 视图层 View:前端展示页面htmlftl等。

简单示例代码如下:

  1. 控制层Controller.java
java 复制代码
public class IndexController {
    @Autowired
    private Service service;

    @GetMapping("/index")
    public String index() {
        // 后续完善页面内容
        return service.findUser().toString();
    }
}
  1. 实例对象Pojo.java
java 复制代码
public class User {
   private int id;
   private String username;
   private String password;
	// 省略get set方法
}
  1. 业务处理Service.java
java 复制代码
@Component
public class Service {
    @Autowired
    private UserDao userDao;

    public List<User> findUser() {
        List<User> users=userDao.findAll();
        return users;
    }

}
  1. 持久层Dao.java
java 复制代码
public interface UserDao {
    @Select("select * from userinfo")
    @Results({
            // 主键映射
            @Result(column = "id",property = "uid",id = true),
            @Result(column = "name",property = "name")
    })
    List<User> findAll();
}
  1. 视图页面index.ftl
html 复制代码
<html>
<head>
    <meta charset="UTF-8">
    <title>Freemarker</title>
</head>
<body>
Hello!
<#list users as user>
    ${user}
</#list>
</body>
</html>

DDD架构------领域驱动设计,Domain-driven Design

MVC架构把所有数据逻辑都堆在Service层,会带来三大问题:

  1. Service 层过度膨胀:所有业务判断、流程、规则全部堆积在此,形成臃肿混乱的 "大泥球代码"。
  2. 出现贫血模型:POJO 实体仅作为纯数据载体,只有字段 + Getter/Setter,无任何业务行为;核心逻辑四散在 Service 中,内聚性极差。
  3. 系统复杂度失控:随着业务迭代,业务规则散落在 Controller、Service、DAO 各处,语义混乱、链路不清,后期维护与迭代成本极高。

在这样的背景下,Eric Evans 在 2003 年提出了Domain-Driven Design(领域驱动设计),其核心思想是:
软件设计应该围绕业务领域进行建模,而不是围绕数据库、CURD等技术实现

DDD的两大核心是领域模型和限界上下文:

  • 领域模型 :某个边界内,对业务核心概念、规则、行为的抽象表达,通常包含实体、聚合根、服务和事件; 实体包含行为方法,即具体的业务逻辑;

    聚合根是相关实体的集合,如Order是聚合根,内部管理多个OrderItem订单项

    领域服务是跨实体或聚合根的处理逻辑,只包含业务逻辑

    领域事件是用于触发后续业务逻辑,标记业务状态转变的方法,可保持上下文之间解耦

  • 限界上下文 :一个词在不同业务内应表达不同含义,即每个领域内都有单独的实体 如在订单上下文中User=联系人、收货地址、电话

    身份认证上下文中User=账号、密码、手机号

    会员上下文中User = 积分、成长值、会员等级

DDD将领域内模型划分为如下四层(上层还有具体的业务领域,如auth(认证)、order(订单)、member(会员)):

  1. 用户接口层(User Interface):处理用户请求,返回响应(对应Controller)。
  2. 应用层(Application):协调领域对象完成业务用例,不包含业务逻辑(只调用方法的Service)。
  3. 领域层(Domain):包含核心业务规则与模型,是系统核心(处理逻辑的Pojo)。
  4. 基础设施层(Infrastructure):提供技术能力(如数据库、消息队列)。

补充:

其实这设计有点微服务的思想:

微服务是把程序拆分成多个可独立运行的服务;

DDD则是关注业务逻辑,把一个高内聚的业务写在一起,避免功能分散;

二者主要是抽象层次不同,DDD关注软件的逻辑结构,而微服务架构则更侧重于系统整体的架构布局

总结

MVC架构关注请求、数据和视图分离,但因为通常使用贫血模型 ,业务逻辑都写在Service层内,实体类Pojo中只有基础属性和getset方法,导致业务逻辑复杂难以维护。

DDD则提倡充血领域实体收拢业务规则 ,设计中只关注业务,而非拘泥于实现方式,使用类似"微服务"的理念,每个业务领域内代码内聚,核心区别是业务逻辑从Service搬到了实体类内。

目前很多设计者可能会因为初期项目简单而选择MVC架构,但随着后续不断迭代发展,项目变得难以维护,而重构为DDD架构的成本又很高,所以除了一锤子买卖,只要需要长期维护的项目都应使用DDD架构。

相关推荐
heimeiyingwang2 小时前
【架构实战】多机房容灾架构设计方案
架构
Code_LT2 小时前
【AIGC】多 Agent 架构 还是 单Agent?Agent Teams vs SubAgent
架构·aigc
2501_933329552 小时前
企业舆情处置技术实践:基于AI的智能监测与申诉系统架构解析
人工智能·分布式·架构·系统架构
东离与糖宝2 小时前
Java 26+Spring Boot 3.5,微服务启动从3秒压到0.8秒
java·人工智能
禹中一只鱼3 小时前
【力扣热题100学习笔记】 - 哈希
java·学习·leetcode·哈希算法
凌波粒3 小时前
LeetCode--349.两个数组的交集(哈希表)
java·算法·leetcode·散列表
于先生吖3 小时前
Java+SpringBoot 无人健身房物联网系统完整源码实现
java·spring boot·物联网
johnrui3 小时前
SpringBoot-JdbcTemplate
java·spring boot·后端
码云社区3 小时前
JAVA二手车交易二手车市场系统源码支持微信小程序+微信公众号+H5+APP
java·开发语言·微信小程序·二手交易·闲置回收