SpringBoot项目,DDD与传统的三层架构详细目录结构

在Spring Boot项目中,采用不同的架构模式会直接体现在项目的目录结构上。下面我将结合一个常见的订单系统案例,为你详细对比领域驱动设计(DDD)和传统三层架构的目录结构、设计思想与代码实现。

🏗️ 架构核心区别一览

在深入目录细节前,了解两者的核心差异至关重要。传统三层架构是技术导向 的,以数据流为中心进行技术分层;而DDD是业务导向的,以领域模型为核心进行设计。

对比维度 传统三层架构 (Technology-Driven) DDD四层架构 (Business-Driven)
设计出发点 技术分层,关注"如何实现"数据流 领域建模,关注"业务是什么"
核心模型 贫血模型​:实体主要是数据载体,行为分散在Service中 充血模型​:实体包含数据和行为,业务逻辑内聚
代码组织核心 技术职责 (Controller, Service, Repository) 业务领域 (如Order, Product子域)
适合场景 业务简单、以CRUD为主的管理系统 业务复杂、需要长期演进的核心系统(如电商、金融)

📁 项目目录结构详解

以下是一个基于Spring Boot的订单管理系统,分别以两种架构模式组织的目录结构。

传统三层架构目录结构

这种结构按技术职责横向切割,简单直接,适合CRUD应用。

bash 复制代码
src/main/java/com/example/orderapp/
├── controller/                 # 表现层:处理HTTP请求和响应
│   ├── OrderController.java    # 订单相关的REST接口
│   └── ProductController.java  # 商品相关的REST接口
├── service/                    # 业务逻辑层:承载核心业务逻辑
│   ├── OrderService.java       # 订单业务服务接口
│   ├── OrderServiceImpl.java   # 订单业务服务实现
│   ├── ProductService.java     # 商品业务服务接口
│   └── ProductServiceImpl.java # 商品业务服务实现
├── dao/                        # 数据访问层(或称持久层)
│   ├── OrderRepository.java    # 订单数据访问接口(继承JpaRepository)
│   └── ProductRepository.java # 商品数据访问接口
├── entity/                     # 实体类(贫血模型,通常与数据库表对应)
│   ├── Order.java
│   └── Product.java
└── dto/                        # 数据传输对象,用于前后端数据交互
    ├── OrderDTO.java
    └── ProductDTO.java

关键代码示例(贫血模型)​​:

在传统三层架构中,实体类通常是只有数据和getter/setter的"贫血模型",业务逻辑集中在Service中。

less 复制代码
// entity/Order.java (贫血模型)
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private BigDecimal amount;
    private String status;
    // ... 只有getter和setter方法,没有业务行为
}

// service/OrderServiceImpl.java (业务逻辑分散在Service)
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderRepository orderRepository;
    
    @Override
    @Transactional
    public void createOrder(OrderDTO orderDTO) {
        // 1. 参数校验逻辑在Service
        if (orderDTO.getAmount() == null || orderDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("金额必须大于0");
        }
        // 2. 创建订单实体(只是数据载体)
        Order order = new Order();
        order.setAmount(orderDTO.getAmount());
        order.setStatus("CREATED");
        // 3. 保存到数据库
        orderRepository.save(order);
    }
}

DDD四层架构目录结构

DDD按业务域纵向划分,强调领域模型的核心地位,结构更复杂但业务内聚性更高。

bash 复制代码
src/main/java/com/example/orderapp/
├── interfaces/                 # 用户接口层(或称表现层)
│   ├── assembler/             # 装配器:负责DTO与领域模型的互相转换
│   │   └── OrderAssembler.java
│   ├── dto/                   # 数据传输对象(DTO),接收请求和返回响应
│   │   ├── request/
│   │   │   └── OrderCreateRequest.java
│   │   └── response/
│   │       └── OrderResponse.java
│   └── controller/
│       └── OrderController.java # 更薄,主要负责协议处理
├── application/                # 应用层:薄层,负责用例编排、事务控制等
│   ├── service/
│   │   └── OrderApplicationService.java # 应用服务,协调多个领域对象
│   └── command/               # (可选)命令对象,如CreateOrderCommand
│       └── CreateOrderCommand.java
├── domain/                    # 领域层(核心):包含丰富的业务逻辑
│   ├── model/                 # 领域模型
│   │   ├── aggregate/         # 聚合
│   │   │   └── Order.java     # 聚合根(充血模型,包含数据和行为)
│   │   ├── valueobject/       # 值对象
│   │   │   └── Money.java     # 例如金额值对象(含货币单位和金额)
│   │   └── entity/            # 实体(当不是聚合根时)
│   │       └── OrderItem.java # 订单项
│   ├── service/               # 领域服务:处理不适合放在实体内的业务逻辑
│   │   └── OrderDomainService.java # 例如处理跨聚合的逻辑
│   ├── repository/            # 仓储接口:定义持久化操作,面向领域
│   │   └── OrderRepository.java
│   └── event/                 # 领域事件
│       └── OrderCreatedEvent.java
└── infrastructure/           # 基础设施层:为上层提供技术实现
    ├── persistence/          # 持久化实现
    │   ├── dao/             # 数据访问对象(如JPA Entity)
    │   │   └── OrderPO.java # 持久化对象(与数据库表结构映射)
    │   ├── repository/
    │   │   └── OrderRepositoryImpl.java # 仓储接口的实现
    │   └── converter/
    │       └── OrderConverter.java # 负责领域对象与持久化对象的转换
    ├── client/               # 外部服务适配器(如调用其他微服务)
    ├── config/               # 配置类
    └── common/               # 通用技术组件(如工具类)

关键代码示例(充血模型与分层协作)​​:

DDD的领域层使用"充血模型",业务逻辑封装在领域对象内部。

java 复制代码
// domain/model/aggregate/Order.java (聚合根,充血模型)
public class Order {
    private OrderId id; // 使用值对象ID,而非基本类型
    private Money totalAmount; // 使用值对象
    private OrderStatus status;
    private List<OrderItem> items;

    // 核心业务行为封装在实体内部
    public static Order create(CreateOrderCommand command, Product product) {
        // 业务规则校验
        if (!product.hasEnoughStock(command.getQuantity())) {
            throw new DomainException("库存不足");
        }
        Order order = new Order();
        order.id = OrderId.nextId();
        order.status = OrderStatus.CREATED;
        order.items = Arrays.asList(new OrderItem(product.getId(), command.getQuantity()));
        order.calculateTotal(); // 计算总价
        // 发布领域事件
        order.registerEvent(new OrderCreatedEvent(order.getId()));
        return order;
    }

    private void calculateTotal() {
        this.totalAmount = items.stream()
                .map(OrderItem::getSubtotal)
                .reduce(Money.ZERO, Money::add);
    }

    // 其他业务方法,如 order.confirm()、order.cancel() 等
}

// application/service/OrderApplicationService.java (应用服务,薄层)
@Service
public class OrderApplicationService {
    // 依赖的是领域层的接口
    private final OrderRepository orderRepository;
    private final ProductService productService; // 假设是领域服务

    @Transactional
    public OrderResponse createOrder(CreateOrderCommand command) {
        // 1. 获取依赖的领域对象(如商品)
        Product product = productService.findProduct(command.getProductId());
        // 2. 调用领域模型执行核心业务逻辑
        Order newOrder = Order.create(command, product);
        // 3. 持久化(基础设施层实现)
        orderRepository.save(newOrder);
        // 4. 返回结果(通过装配器转换为DTO)
        return OrderAssembler.toResponse(newOrder);
    }
}

// interfaces/controller/OrderController.java (薄薄的控制器)
@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderApplicationService orderAppService;

    public OrderController(OrderApplicationService orderAppService) {
        this.orderAppService = orderAppService;
    }

    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(@RequestBody @Valid OrderCreateRequest request) {
        // 1. 将请求DTO转换为应用层需要的Command/Query
        CreateOrderCommand command = OrderAssembler.toCommand(request);
        // 2. 调用应用服务
        OrderResponse response = orderAppService.createOrder(command);
        // 3. 返回响应
        return ResponseEntity.ok(response);
    }
}

💡 如何选择适合的架构

  • 选择传统三层架构 :如果您的项目业务相对简单,主要是增删改查(CRUD)操作,且后期不会变得非常复杂。例如,很多后台管理系统、数据报表系统或简单的REST API服务。这种架构上手快,开发效率高。
  • 选择DDD架构 :如果您的系统业务逻辑复杂,包含大量核心规则和状态流转,且需要长期演进的系统。例如,电商交易核心、风控系统、结算系统等。虽然前期设计和建模成本较高,但能有效应对业务复杂性,提升代码的可维护性和扩展性。
相关推荐
bcbnb3 小时前
iOS 文件管理全攻略,多工具协同实现高效调试、数据导出与应用分析
后端
tung tung tung sahur3 小时前
领略 Rust 抽象之美:自定义迭代器实现全解析
开发语言·后端·rust
用户3074596982073 小时前
容器(Container)—— 对象的“智能工厂+调度官”
后端·thinkphp
程序猿小蒜4 小时前
基于springboot的校园社团信息管理系统开发与设计
java·前端·spring boot·后端·spring
申阳4 小时前
Day 4:02. 基于Nuxt开发博客项目-整合 Inspira UI
前端·后端·程序员
Mos_x4 小时前
28.<Spring博客系统⑤(部署的整个过程
java·后端
爱淋雨的鼬先生4 小时前
SpringBoot 概述
java·spring boot·后端
血小溅4 小时前
Spring Boot 整合 Spring AI:接入 DeepSeek 与 Ollama 调用大模型
后端·ollama·deepseek
李慕婉学姐4 小时前
Springboot的民宿管理系统的设计与实现29rhm9uh(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端