Skip to content

Latest commit

 

History

History

README.md

说明

项目描述

  • 这是一个实际的项目例子,基于SpringBoot框架,按照DDD思想搭建,适合互联网场景下的轻量级应用。
  • 保证代码结构清晰,充分运营设计模式
  • 既满足功能需要,又不过度开发,而是具备一定的扩展性

Java语言DDD目录结构

java-web/
│── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── com
│   │   │   │   └── microwind            # 组织名
│   │   │   │   │   └── knife            # 项目名,若项目较大,可以再建立模块目录
│   │   │   │   │        ├── application/          # 应用层(协调领域逻辑,处理业务用例)
│   │   │   │   │        │   ├── services/         # 服务层,业务逻辑目录
│   │   │   │   │        │   │   ├── order/               # 订单应用服务
│   │   │   │   │        │   │   │   └── OrderService.java   # 订单应用服务
│   │   │   │   │        │   │   ├── sign/                # 签名应用服务
│   │   │   │   │        │   │   │   ├── SignService.java         # 签名核心服务
│   │   │   │   │        │   │   │   ├── SignValidationService.java # 签名验证服务
│   │   │   │   │        │   │   │   ├── DynamicSaltService.java    # 动态盐值服务
│   │   │   │   │        │   │   │   └── strategy/                  # 签名策略模式
│   │   │   │   │        │   │   │       ├── secretkey/             # 密钥获取策略
│   │   │   │   │        │   │   │       ├── dynamicsalt/           # 动态盐值策略
│   │   │   │   │        │   │   │       └── interfacesalt/         # 接口盐值策略
│   │   │   │   │        │   │   └── user/                # 用户应用服务
│   │   │   │   │        │   ├── dto/              # 数据传输对象(DTO)
│   │   │   │   │        │   │   ├── order/               # 订单数据交换对象
│   │   │   │   │        │   │   │   └── OrderDTO.java
│   │   │   │   │        │   │   ├── sign/                # 签名数据交换对象
│   │   │   │   │        │   │   │   ├── SignDTO.java         # 签名DTO
│   │   │   │   │        │   │   │   ├── DynamicSaltDTO.java  # 动态盐值DTO
│   │   │   │   │        │   │   │   └── SignMapper.java      # 签名对象映射器
│   │   │   │   │        │   │   └── user/                # 用户数据交换对象
│   │   │   │   │        │   └── config/            # 应用配置
│   │   │   │   │        │       ├── SignConfig.java      # 签名配置类
│   │   │   │   │        │       └── ApiAuthConfig.java   # API认证配置
│   │   │   │   │        ├── domain/               # 领域层(核心业务逻辑和接口定义)
│   │   │   │   │        │   ├── order/            # 订单聚合(聚合根和业务逻辑)
│   │   │   │   │        │   │   └── Order.java    # 订单实体(聚合根),包含核心业务逻辑
│   │   │   │   │        │   ├── sign/             # 签名领域
│   │   │   │   │        │   │   ├── Sign.java            # 签名领域对象
│   │   │   │   │        │   │   ├── SignUserAuth.java    # 签名用户授权
│   │   │   │   │        │   │   ├── SignUserInfo.java    # 签名用户信息
│   │   │   │   │        │   │   ├── DynamicSalt.java     # 动态盐值领域对象
│   │   │   │   │        │   │   └── SignDomainService.java # 签名领域服务
│   │   │   │   │        │   ├── user/             # 用户聚合
│   │   │   │   │        │   └── repository/       # 仓库接口
│   │   │   │   │        │       ├── Repository.java         # [可选]仓库通用接口
│   │   │   │   │        │       ├── OrderRepository.java    # 订单仓储接口
│   │   │   │   │        │       ├── SignRepository.java     # 签名仓储接口
│   │   │   │   │        │       └── apiauth/                # API认证仓储接口
│   │   │   │   │        ├── infrastructure/       # 基础设施层(实现领域层定义的接口)
│   │   │   │   │        │   ├── repository/       # 仓储实现
│   │   │   │   │        │   │   ├── OrderRepositoryImpl.java # 订单仓储实现
│   │   │   │   │        │   │   └── SignRepositoryImpl.java  # 签名仓储实现
│   │   │   │   │        │   ├── messaging/        # 消息队列实现
│   │   │   │   │        │   └── configuration/    # 基础配置(与外部系统相关)
│   │   │   │   │        │       ├── DatabaseConfig.java         # [可选]数据库配置
│   │   │   │   │        │       └── ApiAuthDataSourceConfig.java # API认证数据源配置
│   │   │   │   │        ├── interfaces/           # 接口层(处理外部请求,如HTTP接口)
│   │   │   │   │        │   ├── controllers/      # RESTful API接口
│   │   │   │   │        │   │   ├── order/               # 订单相关控制器
│   │   │   │   │        │   │   │   └── OrderController.java
│   │   │   │   │        │   │   ├── sign/                # 签名相关控制器
│   │   │   │   │        │   │   │   ├── SignController.java     # 签名API接口
│   │   │   │   │        │   │   │   └── SignPageController.java # 签名页面接口
│   │   │   │   │        │   │   ├── user/                # 用户相关控制器
│   │   │   │   │        │   │   └── apiauth/             # API认证相关控制器
│   │   │   │   │        │   ├── annotation/       # 注解定义
│   │   │   │   │        │   │   ├── RequireSign.java         # 需要签名验证注解
│   │   │   │   │        │   │   ├── IgnoreSignHeader.java    # 忽略签名验证注解
│   │   │   │   │        │   │   └── WithParams.java           # 签名参数模式枚举
│   │   │   │   │        │   ├── advice/            # 切面增强
│   │   │   │   │        │   │   └── SignHeaderAdvice.java    # 签名Header参数绑定
│   │   │   │   │        │   └── vo/                # 视图对象(View Object)
│   │   │   │   │        │       ├── order/               # 订单视图对象
│   │   │   │   │        │       ├── sign/                # 签名视图对象
│   │   │   │   │        │       │   ├── SignRequest.java        # 签名请求VO
│   │   │   │   │        │       │   ├── SignResponse.java       # 签名响应VO
│   │   │   │   │        │       │   ├── SignHeaderRequest.java  # 签名Header请求VO
│   │   │   │   │        │       │   └── DynamicSaltRequest.java # 动态盐值请求VO
│   │   │   │   │        │       └── user/                # 用户视图对象
│   │   │   │   │        ├── middleware/           # 中间件(例如:鉴权、日志、拦截等)
│   │   │   │   │        │   ├── LoggingFilter.java        # 日志中间件
│   │   │   │   │        │   ├── SignatureInterceptor.java # 签名验证拦截器
│   │   │   │   │        │   └── CachedBodyFilter.java     # 请求体缓存过滤器
│   │   │   │   │        ├── common/               # 通用组件(通用的服务类)
│   │   │   │   │        │   └── ApiResponse.java          # 统一响应对象
│   │   │   │   │        ├── config/               # 通用配置(管理服务器和应用信息)
│   │   │   │   │        │   └── WebConfig.java            # 服务通用配置
│   │   │   │   │        ├── utils/                # 实用工具
│   │   │   │   │        │   ├── DataUtils.java            # 日期工具
│   │   │   │   │        │   └── SignatureUtil.java        # 签名工具类
│   │   │   │   │        └── Application.java      # 应用启动类
│   │   │   └── resources/
│   │   │   │   └── application.yml         # 配置文件
│   │   │   └── webapp/                            # [可选]web运行目录,可模拟
│   │   └── test/
│   │        └── java/
│   │            ├── com
│   │            │   └── knife
│   │            │        ├── application/       # 应用层的测试
│   │            │        ├── interfaces/        # 接口层的测试
│   │            │            └── controllers/
│   │            │                └── sign/      # 签名接口测试
│── pom.xml                      # Maven 配置文件(如果使用 Maven)
│── build.gradle                 # Gradle 配置文件(如果使用 Gradle)

目录结构说明

  • 领域模型主要分界面、应用、领域和基础这四层,每个项目都包括这四个部分。
  • 如果项目属于中小型,则不再区分模块目录,相关文件按照层级放在一起,只是domain按模块区分目录。
  • 如果项目较大,则可以按照模块再分别建立目录,每个模块包括这四层。
  • 在微服务理念下,单个项目没有必要太大,过大既影响运行速度也影响开发效率,如果项目太大了,不如进行项目拆分。

Sign 签名验证模块

本项目实现了完整的 API 签名验证机制,用于保护接口安全,防止数据篡改和重放攻击。

核心组件

  • 接口层@RequireSign@IgnoreSignHeader 注解,SignController API 接口
  • 中间件层:SignatureInterceptor 拦截器,CachedBodyFilter 请求体缓存过滤器
  • 应用层:SignService、DynamicSaltService、SignValidationService
  • 策略模式:SecretKeyStrategy、DynamicSaltStrategy、InterfaceSaltStrategy
  • 领域层:Sign、DynamicSalt、SignUserAuth 领域对象
  • 工具类:SignatureUtil 签名工具类(支持 MD5、SHA1、SHA256、SM3)

详细文档:请参考 SIGN.md 了解签名机制的详细说明、配置方式和使用示例。

application

  • service:封装应用业务逻辑,如订单创建、处理。
  • dto:数据传输对象(DTO),用于应用层与外部传递数据。

domain

  • order:订单聚合(包含聚合根、实体、领域事件等)。
  • repository:领域仓储接口,定义持久化操作。

infrastructure

  • repository:基础设施层的仓储实现。
  • messaging:消息队列或事件流的集成。
  • configuration:基础设施配置,如数据库连接、API 密钥等。

interfaces

  • controllers:RESTful API 层,用于处理外部请求。
  • routes:路由配置,映射 API 路径和控制器。

运行

创建schema.sql,导入数据库结构。请提前准备好MySQL

CREATE DATABASE order_db;
use order_db;
-- orders表
CREATE TABLE `orders` (
  `order_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单ID',
  `order_no` VARCHAR(50) NOT NULL COMMENT '订单编号',
  `user_id` BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
  `order_name` VARCHAR(255) NOT NULL COMMENT '订单名称',
  `amount` DECIMAL(10, 2) NOT NULL COMMENT '订单金额',
  `status` VARCHAR(50) NOT NULL COMMENT '订单状态',
  `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`order_id`),
  UNIQUE KEY `idx_order_no` (`order_no`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

-- order_item表
CREATE TABLE `order_item` (
  `order_item_id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `price` double NOT NULL,
  `product` varchar(255) DEFAULT NULL,
  `quantity` int NOT NULL,
  `order_id` bigint unsigned DEFAULT NULL,
  PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
# 本例子依赖 JDK17 Tomcat10、Maven3.8、Lomok1.8、Mapstruct1.6等,详见pom.xml
# 相关版本可以降低或升级,需要同步调整依赖包和个别代码写法。

# 安装
$ mvn clean install -U

# 打包
$ mvn clean package -P prod -DskipTests

# 运行应用
$ java -jar target/spring-boot-order-1.0.0.jar

# 直接运行
$ mvn spring-boot:run
Starting server on http://localhost:8080 successfully.

# 访问验证
$ curl -X GET http://localhost:8080/api/orders
$ curl -X GET http://localhost:8080/api/orders/订单ID

# 运行测试
$ mvn test

Java 语言 DDD(领域驱动设计)特点

1. 关注领域模型

DDD 强调通过聚合(Aggregate)、实体(Entity)和值对象(Value Object)组织业务逻辑。

在 Java 中,使用 class 定义实体和值对象:

// 实体(Entity)
public class Order {
    private int id;
    private String name;
    // getters and setters
}

2. 分层架构

DDD 通常采用 分层架构,通用项目结构如下:

  • 领域层(Domain Layer):核心业务逻辑,如 domain 目录下的实体和聚合。
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ElementCollection
    @CollectionTable(name = "order_items")
    private List<OrderItem> items; // 值对象
    
    // 核心业务方法
    public void addItem(Product product, int quantity) {
        this.items.add(new OrderItem(product, quantity));
    }
}
  • 应用层(Application Layer):用例(Use Cases)和业务流程编排。
@Service
@Transactional
@RequiredArgsConstructor
public class OrderAppService {
    private final OrderRepository orderRepository;
    
    public OrderDTO createOrder(OrderCreateCommand command) {
        Order order = new Order();
        command.getItems().forEach(item -> 
            order.addItem(item.getProduct(), item.getQuantity()));
        order = orderRepository.save(order);
        return OrderDTO.fromDomain(order);
    }
}
  • 基础设施层(Infrastructure Layer):数据库、缓存、外部 API 适配等。
// JPA 仓储实现(依赖 Spring Data JPA)
@Repository
@RequiredArgsConstructor
public class JpaOrderRepository implements OrderRepository {
    private final OrderJpaRepository jpaRepository;
    private final DomainEventPublisher eventPublisher;

    @Override
    public Order save(Order order) {
        Order savedOrder = jpaRepository.save(order);
        order.domainEvents().forEach(eventPublisher::publish);
        return savedOrder;
    }
}
  • 接口层(Interface Layer):提供 HTTP、RPC 或 CLI 接口。
// REST 控制器
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
    private final OrderAppService orderAppService;

    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@Valid @RequestBody OrderRequest request) {
        OrderDTO dto = orderAppService.createOrder(request.toCommand());
        return ResponseEntity.created(URI.create("/orders/" + dto.getId())).body(dto);
    }
}

3. 依赖倒置(Dependency Inversion)

领域层不应直接依赖基础设施,而是通过 接口(Interface) 进行依赖倒置。例如: OrderRepository 是领域层定义的接口,OrderRepositoryImpl 是基础设施层的具体实现。

// 领域层接口
public interface OrderRepository {
    Order save(Order order);
    Optional<Order> findById(int id);
}
// 基础设施层实现
@Repository
public class OrderRepositoryImpl implements OrderRepository {
    private final JpaRepository<Order, Integer> jpaRepository;

    @Override
    public Order save(Order order) {
        return jpaRepository.save(order);
    }

    @Override
    public Optional<Order> findById(int id) {
        return jpaRepository.findById(id);
    }
}

4. 聚合(Aggregate)管理

聚合根(Aggregate Root)管理整个聚合的生命周期:

例如,Order 是聚合根,OrderItem 是子聚合。Order 聚合控制子聚合 OrderItem 的生命周期并确保业务一致性。

// 订单实体(聚合根)
public class Order {
    private int id;
    private List<OrderItem> items;
    private final String status;
    private final LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    public Order(int id, List<OrderItem> items) {
        this.id = id;
        this.items = items;
        this.status = "PENDING";
        this.createdAt = LocalDateTime.now();
    }

    public void addItem(OrderItem item) {
        this.items.add(item);
    }

    // 其他业务逻辑方法
}

订单项是 OrderItem,可以视为子聚合:

public class OrderItem {
    private int id;
    private String productName;
    private int quantity;
    private BigDecimal price;

    // 构造方法和其他方法
}

5. 应用服务(Application Service)

应用服务封装领域逻辑,避免外部直接操作领域对象:

// 业务流程处理
@Service
public class OrderService {
    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public Order createOrder(int orderId, List<OrderItem> items) {
        Order order = new Order(orderId, items, "Pending");
        return orderRepository.save(order);
    }
}

6. 事件驱动(Event-Driven)

使用 领域事件(Domain Events) 进行解耦,在 Java 语言中可通过 ChannelPub/Sub 实现:

public class OrderCreatedEvent {
    private final int orderId;

    public OrderCreatedEvent(int orderId) {
        this.orderId = orderId;
    }

    // getters
}

@Service
public class EventPublisher {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void publish(OrderCreatedEvent event) {
        eventPublisher.publishEvent(event);
    }
}

7. 结合 CQRS(命令查询职责分离)

DDD 可结合 CQRS(Command Query Responsibility Segregation),在 Java 中可用 命令(Command) 处理变更操作,用 查询(Query) 处理数据读取:

public class CreateOrderCommand {
    private final int orderId;
    private final List<OrderItem> items;

    public CreateOrderCommand(int orderId, List<OrderItem> items) {
        this.orderId = orderId;
        this.items = items;
    }

    // getters
}

总结

Java DDD 实践强调:

  1. 使用 class 作为领域模型(Entity、Value Object、Aggregate)
  2. 依赖倒置,通过接口定义领域层,不直接依赖基础设施
  3. 使用应用服务(Service)封装业务逻辑,避免外部直接操作领域对象
  4. 事件驱动,通过 ApplicationEventPublisher 进行解耦
  5. 结合 CQRS,实现命令和查询分离,提高可扩展性