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架构。

相关推荐
Uopiasd1234oo1 小时前
MetaFormer架构改进YOLOv26自适应稀疏注意力与卷积门控双重突破
yolo·架构
easy_coder2 小时前
Agent:原理、架构与工程实践(中篇)
架构·云计算
OtIo TALL2 小时前
redis7 for windows的安装教程
java
uNke DEPH2 小时前
Spring Boot的项目结构
java·spring boot·后端
xixingzhe22 小时前
idea启动vue项目
java·vue.js·intellij-idea
码以致用3 小时前
DeerFlow Memory架构
人工智能·ai·架构·agent
wzl202612133 小时前
企业微信定时群发技术实现与实操指南(原生接口+工具落地)
java·运维·前端·企业微信
凌波粒3 小时前
Java 8 “新”特性详解:Lambda、函数式接口、Stream、Optional 与方法引用
java·开发语言·idea
2603_954708313 小时前
如何确保微电网标准化架构设计流程的完整性?
网络·人工智能·物联网·架构·系统架构
曹牧3 小时前
Eclipse:悬停提示(Hover)
java·ide·eclipse