DDD领域驱动设计C++实现案例:订单管理系统

一、DDD核心概念简介

领域驱动设计(Domain-Driven Design)是一种软件开发方法论,强调将业务领域的概念和规则融入软件设计中。核心概念包括:

  • 值对象(Value Object): 无唯一标识,基于属性值判断相等性
  • 实体(Entity): 有唯一标识,其生命周期由聚合根管理
  • 聚合根(Aggregate Root): 聚合的根节点,维护聚合内的一致性
  • 领域服务(Domain Service): 处理跨实体的业务逻辑
  • 仓储(Repository): 提供数据持久化接口

二、订单管理系统领域模型设计

2.1 值对象定义

地址值对象

cpp 复制代码
#include <string>
#include <cstdint>
#include <utility>

// 地址值对象 - 无唯一标识,基于属性值相等
class Address {
private:
    std::string province_;  // 省份
    std::string city_;      // 城市
    std::string district_;  // 区/县
    std::string detail_;    // 详细地址
    
public:
    // 构造函数 - 确保值对象不可变
    Address(std::string province, std::string city, std::string district, std::string detail)
        : province_(std::move(province)), city_(std::move(city)), 
          district_(std::move(district)), detail_(std::move(detail)) {}
    
    // 仅提供getter,不提供setter,保证不可变性
    [[nodiscard]] const std::string& GetProvince() const { return province_; }
    [[nodiscard]] const std::string& GetCity() const { return city_; }
    [[nodiscard]] const std::string& GetDistrict() const { return district_; }
    [[nodiscard]] const std::string& GetDetail() const { return detail_; }
    
    // 重写相等运算符 - 基于所有属性值判断相等
    bool operator==(const Address& other) const {
        return province_ == other.province_ &&
               city_ == other.city_ &&
               district_ == other.district_ &&
               detail_ == other.detail_;
    }
};

商品值对象

cpp 复制代码
// 商品值对象 - 无唯一标识,代表商品信息
class Product {
private:
    std::string name_;      // 商品名称
    double price_;          // 商品单价
    std::string sku_;       // 商品唯一编码
    
public:
    Product(std::string name, double price, std::string sku)
        : name_(std::move(name)), price_(price), sku_(std::move(sku)) {}
    
    [[nodiscard]] const std::string& GetName() const { return name_; }
    [[nodiscard]] double GetPrice() const { return price_; }
    [[nodiscard]] const std::string& GetSku() const { return sku_; }
    
    // 基于SKU判断商品是否相同
    bool operator==(const Product& other) const {
        return sku_ == other.sku_;
    }
};

2.2 实体定义

订单项实体

cpp 复制代码
#include <memory>

// 订单项实体 - 有唯一标识,属于Order聚合
class OrderItem {
private:
    uint64_t id_;               // 订单项唯一标识
    std::shared_ptr<Product> product_;  // 商品信息
    int quantity_;              // 商品数量
    double unit_price_;         // 下单时的单价(快照)
    
public:
    OrderItem(uint64_t id, std::shared_ptr<Product> product, int quantity)
        : id_(id), product_(std::move(product)), quantity_(quantity) {
        if (quantity <= 0) {
            throw std::invalid_argument("订单项数量必须大于0");
        }
        unit_price_ = product_->GetPrice();  // 记录下单时的价格快照
    }
    
    [[nodiscard]] uint64_t GetId() const { return id_; }
    [[nodiscard]] const std::shared_ptr<Product>& GetProduct() const { return product_; }
    [[nodiscard]] int GetQuantity() const { return quantity_; }
    [[nodiscard]] double GetUnitPrice() const { return unit_price_; }
    
    // 计算订单项总价
    [[nodiscard]] double CalculateTotal() const {
        return unit_price_ * quantity_;
    }
    
    // 重写相等运算符 - 基于唯一标识判断
    bool operator==(const OrderItem& other) const {
        return id_ == other.id_;
    }
};

2.3 聚合根定义

订单聚合根

cpp 复制代码
#include <vector>
#include <unordered_map>
#include <stdexcept>
#include <algorithm>
#include <chrono>

// 订单状态枚举
enum class OrderStatus {
    CREATED,    // 已创建
    PAID,       // 已支付
    SHIPPED,    // 已发货
    DELIVERED,  // 已送达
    CANCELLED   // 已取消
};

// 订单聚合根 - 维护订单的一致性
class Order {
private:
    uint64_t id_;                     // 订单唯一标识
    std::string customer_id_;         // 客户ID
    std::vector<OrderItem> items_;    // 订单项集合
    Address shipping_address_;        // 配送地址
    OrderStatus status_;              // 订单状态
    std::chrono::system_clock::time_point create_time_;  // 创建时间
    
    // 生成订单项ID的简单实现
    uint64_t GenerateItemId() const {
        return items_.empty() ? 1 : items_.back().GetId() + 1;
    }
    
public:
    Order(uint64_t id, std::string customer_id, Address shipping_address)
        : id_(id), customer_id_(std::move(customer_id)), 
          shipping_address_(std::move(shipping_address)),
          status_(OrderStatus::CREATED),
          create_time_(std::chrono::system_clock::now()) {}
    
    // 添加商品到订单 - 领域行为
    void AddProduct(const std::shared_ptr<Product>& product, int quantity) {
        // 检查订单状态是否允许添加商品
        if (status_ != OrderStatus::CREATED) {
            throw std::logic_error("只有已创建状态的订单可以添加商品");
        }
        
        // 检查数量是否合法
        if (quantity <= 0) {
            throw std::invalid_argument("商品数量必须大于0");
        }
        
        // 检查商品是否已存在,存在则更新数量
        auto it = std::find_if(items_.begin(), items_.end(),
            [&product](const OrderItem& item) {
                return *item.GetProduct() == *product;
            });
            
        if (it != items_.end()) {
            // 在实际实现中,这里应该创建新的OrderItem或提供修改数量的方法
            throw std::logic_error("当前实现不支持修改订单项数量,请先移除再添加");
        } else {
            // 添加新订单项
            items_.emplace_back(GenerateItemId(), product, quantity);
        }
    }
    
    // 移除订单项
    void RemoveItem(uint64_t item_id) {
        if (status_ != OrderStatus::CREATED) {
            throw std::logic_error("只有已创建状态的订单可以移除商品");
        }
        
        auto it = std::remove_if(items_.begin(), items_.end(),
            [item_id](const OrderItem& item) {
                return item.GetId() == item_id;
            });
            
        if (it == items_.end()) {
            throw std::invalid_argument("订单项不存在");
        }
        
        items_.erase(it, items_.end());
    }
    
    // 计算订单总价 - 领域行为
    [[nodiscard]] double CalculateTotalAmount() const {
        double total = 0;
        for (const auto& item : items_) {
            total += item.CalculateTotal();
        }
        return total;
    }
    
    // 订单支付 - 状态转换行为
    void Pay() {
        if (status_ != OrderStatus::CREATED) {
            throw std::logic_error("只有已创建状态的订单可以支付");
        }
        
        if (items_.empty()) {
            throw std::logic_error("空订单不能支付");
        }
        
        status_ = OrderStatus::PAID;
    }
    
    // 订单发货 - 状态转换行为
    void Ship() {
        if (status_ != OrderStatus::PAID) {
            throw std::logic_error("只有已支付状态的订单可以发货");
        }
        
        status_ = OrderStatus::SHIPPED;
    }
    
    // 订单取消 - 状态转换行为
    void Cancel() {
        if (status_ != OrderStatus::CREATED && status_ != OrderStatus::PAID) {
            throw std::logic_error("只有已创建或已支付状态的订单可以取消");
        }
        
        status_ = OrderStatus::CANCELLED;
    }
    
    // 获取订单信息的getter方法
    [[nodiscard]] uint64_t GetId() const { return id_; }
    [[nodiscard]] const std::string& GetCustomerId() const { return customer_id_; }
    [[nodiscard]] const std::vector<OrderItem>& GetItems() const { return items_; }
    [[nodiscard]] const Address& GetShippingAddress() const { return shipping_address_; }
    [[nodiscard]] OrderStatus GetStatus() const { return status_; }
    [[nodiscard]] const std::chrono::system_clock::time_point& GetCreateTime() const { return create_time_; }
};

2.4 领域服务定义

订单领域服务

cpp 复制代码
#include <unordered_map>

// 订单领域服务 - 处理跨聚合的业务逻辑
class OrderService {
public:
    // 合并订单 - 跨聚合根操作
    std::shared_ptr<Order> MergeOrders(
        const std::shared_ptr<Order>& order1, 
        const std::shared_ptr<Order>& order2) {
        
        // 检查两个订单是否属于同一客户
        if (order1->GetCustomerId() != order2->GetCustomerId()) {
            throw std::invalid_argument("只能合并同一客户的订单");
        }
        
        // 检查订单状态
        if (order1->GetStatus() != OrderStatus::CREATED || 
            order2->GetStatus() != OrderStatus::CREATED) {
            throw std::invalid_argument("只能合并已创建状态的订单");
        }
        
        // 创建新订单(实际应用中ID通常由仓储生成)
        auto merged_order = std::make_shared<Order>(
            0,  // 临时ID,实际应用中由仓储生成
            order1->GetCustomerId(),
            order1->GetShippingAddress()  // 使用第一个订单的配送地址
        );
        
        // 添加第一个订单的商品
        for (const auto& item : order1->GetItems()) {
            merged_order->AddProduct(item.GetProduct(), item.GetQuantity());
        }
        
        // 添加第二个订单的商品
        for (const auto& item : order2->GetItems()) {
            merged_order->AddProduct(item.GetProduct(), item.GetQuantity());
        }
        
        return merged_order;
    }
    
    // 计算客户订单总金额
    double CalculateCustomerTotalOrders(
        const std::vector<std::shared_ptr<Order>>& orders) {
        
        double total = 0;
        for (const auto& order : orders) {
            // 只计算已支付和已发货的订单
            if (order->GetStatus() == OrderStatus::PAID || 
                order->GetStatus() == OrderStatus::SHIPPED ||
                order->GetStatus() == OrderStatus::DELIVERED) {
                total += order->CalculateTotalAmount();
            }
        }
        return total;
    }
};

2.5 仓储接口定义

订单仓储接口

cpp 复制代码
// 订单仓储接口 - 定义持久化操作
class OrderRepository {
public:
    virtual ~OrderRepository() = default;
    
    // 保存订单
    virtual void Save(const std::shared_ptr<Order>& order) = 0;
    
    // 根据ID获取订单
    virtual std::shared_ptr<Order> GetById(uint64_t id) = 0;
    
    // 获取客户的所有订单
    virtual std::vector<std::shared_ptr<Order>> GetByCustomerId(const std::string& customer_id) = 0;
    
    // 更新订单
    virtual void Update(const std::shared_ptr<Order>& order) = 0;
    
    // 删除订单
    virtual void Delete(uint64_t id) = 0;
};

2.6 仓储实现示例

cpp 复制代码
#include <unordered_map>
#include <mutex>

// 内存订单仓储实现 - 实际应用中可能是数据库实现
class InMemoryOrderRepository : public OrderRepository {
private:
    std::unordered_map<uint64_t, std::shared_ptr<Order>> orders_;
    uint64_t next_id_ = 1;
    std::mutex mutex_;
    
public:
    void Save(const std::shared_ptr<Order>& order) override {
        std::lock_guard<std::mutex> lock(mutex_);
        
        // 如果是新订单,分配ID
        if (order->GetId() == 0) {
            // 在实际应用中,这里应该通过反射或工厂方法创建新订单对象
            // 为简化示例,我们假设可以修改订单ID
            // 注意:在纯正的DDD中,聚合根的ID通常在创建时确定
            auto new_order = std::make_shared<Order>(
                next_id_++,
                order->GetCustomerId(),
                order->GetShippingAddress()
            );
            
            for (const auto& item : order->GetItems()) {
                new_order->AddProduct(item.GetProduct(), item.GetQuantity());
            }
            
            orders_[new_order->GetId()] = new_order;
        } else {
            orders_[order->GetId()] = order;
        }
    }
    
    std::shared_ptr<Order> GetById(uint64_t id) override {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = orders_.find(id);
        if (it != orders_.end()) {
            return it->second;
        }
        return nullptr;
    }
    
    std::vector<std::shared_ptr<Order>> GetByCustomerId(const std::string& customer_id) override {
        std::lock_guard<std::mutex> lock(mutex_);
        std::vector<std::shared_ptr<Order>> result;
        
        for (const auto& pair : orders_) {
            if (pair.second->GetCustomerId() == customer_id) {
                result.push_back(pair.second);
            }
        }
        
        return result;
    }
    
    void Update(const std::shared_ptr<Order>& order) override {
        Save(order);  // 对于内存仓储,Save和Update可以实现为同一操作
    }
    
    void Delete(uint64_t id) override {
        std::lock_guard<std::mutex> lock(mutex_);
        orders_.erase(id);
    }
};

2.7 应用服务定义

cpp 复制代码
// 订单应用服务 - 协调领域对象完成业务功能
class OrderAppService {
private:
    std::unique_ptr<OrderRepository> order_repository_;
    OrderService order_service_;
    
public:
    explicit OrderAppService(std::unique_ptr<OrderRepository> repository)
        : order_repository_(std::move(repository)) {}
    
    // 创建订单
    uint64_t CreateOrder(const std::string& customer_id, const Address& shipping_address) {
        auto order = std::make_shared<Order>(0, customer_id, shipping_address);
        order_repository_->Save(order);
        return order->GetId();
    }
    
    // 添加商品到订单
    void AddProductToOrder(uint64_t order_id, const std::shared_ptr<Product>& product, int quantity) {
        auto order = order_repository_->GetById(order_id);
        if (!order) {
            throw std::invalid_argument("订单不存在");
        }
        
        order->AddProduct(product, quantity);
        order_repository_->Update(order);
    }
    
    // 提交订单(支付)
    void PayOrder(uint64_t order_id) {
        auto order = order_repository_->GetById(order_id);
        if (!order) {
            throw std::invalid_argument("订单不存在");
        }
        
        order->Pay();
        order_repository_->Update(order);
    }
    
    // 合并客户的两个订单
    uint64_t MergeCustomerOrders(uint64_t order_id1, uint64_t order_id2) {
        auto order1 = order_repository_->GetById(order_id1);
        auto order2 = order_repository_->GetById(order_id2);
        
        if (!order1 || !order2) {
            throw std::invalid_argument("订单不存在");
        }
        
        auto merged_order = order_service_.MergeOrders(order1, order2);
        order_repository_->Save(merged_order);
        
        // 删除原订单
        order_repository_->Delete(order_id1);
        order_repository_->Delete(order_id2);
        
        return merged_order->GetId();
    }
    
    // 获取客户订单总金额
    double GetCustomerTotalSpent(const std::string& customer_id) {
        auto orders = order_repository_->GetByCustomerId(customer_id);
        return order_service_.CalculateCustomerTotalOrders(orders);
    }
};

三、客户端使用示例

cpp 复制代码
#include <iostream>

void RunExample() {
    // 创建仓储
    auto repository = std::make_unique<InMemoryOrderRepository>();
    OrderAppService app_service(std::move(repository));
    
    // 创建地址
    Address shipping_address("广东省", "深圳市", "南山区", "科技园路100号");
    
    // 创建订单
    uint64_t order_id = app_service.CreateOrder("customer_123", shipping_address);
    std::cout << "创建订单成功,订单ID: " << order_id << std::endl;
    
    // 创建商品
    auto product1 = std::make_shared<Product>("C++编程思想", 89.0, "book_001");
    auto product2 = std::make_shared<Product>("DDD实战", 79.0, "book_002");
    
    // 添加商品到订单
    app_service.AddProductToOrder(order_id, product1, 1);
    app_service.AddProductToOrder(order_id, product2, 2);
    std::cout << "添加商品到订单成功" << std::endl;
    
    // 支付订单
    app_service.PayOrder(order_id);
    std::cout << "订单支付成功" << std::endl;
    
    // 查询客户总消费
    double total = app_service.GetCustomerTotalSpent("customer_123");
    std::cout << "客户总消费金额: " << total << "元" << std::endl;
}

int main() {
    try {
        RunExample();
    } catch (const std::exception& e) {
        std::cerr << "发生错误: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

四、DDD概念在案例中的体现

  1. 限界上下文(Bounded Context): 整个订单管理系统构成一个限界上下文,包含了订单相关的所有领域对象

  2. 值对象(Value Object):

    • Address: 表示地址信息,无唯一标识,基于内容判断相等
    • Product: 表示商品信息,基于SKU判断相等性,是不可变对象
  3. 实体(Entity):

    • OrderItem: 有唯一ID,生命周期由Order聚合根管理
    • 实体的标识在整个系统中唯一,不受属性变化影响
  4. 聚合根(Aggregate Root):

    • Order: 作为聚合根,维护订单项集合的一致性
    • 提供了添加/移除商品、支付、发货等领域行为
    • 确保订单状态转换的业务规则得到遵守
  5. 领域服务(Domain Service):

    • OrderService: 处理跨聚合的业务逻辑(订单合并)
    • 包含领域知识,但不适合放在单个聚合根中的操作
  6. 仓储(Repository):

    • OrderRepository: 抽象订单的持久化操作
    • InMemoryOrderRepository: 具体实现,隔离领域层与数据访问层
  7. 领域事件(Domain Event): 案例中未直接实现,但可以扩展添加,如订单支付后发布OrderPaid事件

五、总结

本案例通过一个简单的订单管理系统展示了DDD的核心概念和设计思想:

1.** 以领域为中心 : 设计围绕订单业务领域的概念和规则展开 2. 面向对象设计 : 将业务行为封装在领域对象中,而非过程式的服务中 3. 关注业务规则 : 通过聚合根确保业务规则(如订单状态转换)得到遵守 4. 分层架构 : 领域层、应用层、基础设施层清晰分离 5. 隔离技术细节 **: 通过仓储接口隔离领域层与数据访问技术

在实际项目中,DDD的应用往往更加复杂,可能还会涉及领域事件、事件溯源、CQRS等模式,但本案例展示的核心概念是DDD的基础。通过将业务领域模型化,团队可以更好地与领域专家沟通,构建出更符合业务需求、更易维护的软件系统。## 六、DDD架构设计

6.1 DDD分层架构

DDD推荐采用分层架构,将系统划分为不同职责的层次,各层之间通过明确的接口交互。以下是典型的DDD四层架构:

各层职责:

  • 表示层(Presentation Layer):处理用户交互和请求响应,如API接口、UI界面
  • 应用层(Application Layer):协调领域对象执行业务操作,不包含业务逻辑
  • 领域层(Domain Layer):核心层,包含业务模型、规则和逻辑
  • 基础设施层(Infrastructure Layer):提供技术支持,如数据库访问、消息队列等

在我们的订单管理系统中:

  • 表示层:未直接实现,可对应API控制器或UI界面
  • 应用层:OrderAppService类,协调领域对象完成业务功能
  • 领域层:OrderOrderItemProduct等领域对象和OrderService领域服务
  • 基础设施层:OrderRepository接口及InMemoryOrderRepository实现

6.2 领域事件

领域事件是DDD中一个重要概念,用于捕获领域中发生的重要事件并通知其他组件。例如:

cpp 复制代码
// 订单支付事件示例
class OrderPaidEvent {
private:
    uint64_t order_id_;
    std::string customer_id_;
    double amount_;
    std::chrono::system_clock::time_point paid_time_;
    
public:
    OrderPaidEvent(uint64_t order_id, std::string customer_id, double amount)
        : order_id_(order_id), customer_id_(std::move(customer_id)), 
          amount_(amount), paid_time_(std::chrono::system_clock::now()) {}
    
    // Getter方法...
};

// 在Order类的Pay方法中发布事件
void Pay() {
    // ... 现有支付逻辑 ...
    
    // 发布订单支付事件
    DomainEventPublisher::Publish(std::make_shared<OrderPaidEvent>(
        id_, customer_id_, CalculateTotalAmount()
    ));
}

领域事件可用于实现跨聚合通信、集成其他系统(如支付系统、物流系统)等,提高系统的解耦度。

七、使用DDD的优化点

7.1 业务与技术分离

DDD将业务逻辑集中在领域层,与技术实现分离。在订单管理系统中,订单的状态转换、价格计算等核心业务规则封装在Order类中,不依赖于数据库访问、UI框架等技术细节。

优势:

  • 业务逻辑更清晰,易于理解和维护
  • 技术变更(如更换数据库)不影响领域模型
  • 领域模型可独立测试,无需依赖外部系统

7.2 领域知识显性化

DDD鼓励创建与业务语言一致的模型,使领域知识直接体现在代码中。例如:

  • Order::Pay()方法对应"订单支付"业务动作
  • OrderStatus枚举反映业务中的订单状态流转
  • OrderService::MergeOrders()实现"合并订单"业务场景

这种显性化使开发人员和领域专家能使用共同语言沟通,减少理解偏差。

7.3 维护数据一致性

聚合根模式确保了数据的一致性。Order作为聚合根,控制着订单项的添加、移除和订单状态的转换,防止出现无效状态(如空订单支付、已发货订单添加商品等)。

7.4 提高代码复用性

领域模型抽象了业务概念,可在不同场景中复用。例如Product值对象可用于订单系统、库存系统、购物车系统等多个模块。

7.5 更好的可扩展性

DDD的分层架构和领域模型设计使系统更易于扩展:

  • 新增业务功能时,只需扩展领域模型或添加新的领域服务
  • 通过限界上下文隔离不同业务模块,减少相互影响
  • 领域事件机制支持松耦合的扩展

八、不使用DDD的问题

8.1 业务逻辑分散

传统开发中,业务逻辑常分散在服务层、控制器甚至UI层,形成"贫血模型"。例如:

cpp 复制代码
// 传统方式:业务逻辑分散在服务中
class OrderService {
public:
    double CalculateTotal(OrderDTO order) {
        double total = 0;
        for (auto& item : order.items) {
            total += item.price * item.quantity;
        }
        return total;
    }
    
    void PayOrder(uint64_t order_id) {
        // 查询订单、更新状态等逻辑
    }
    
    // 更多业务方法...
};

这种方式导致业务规则难以追踪和维护,需求变更时需修改多个地方。

8.2 技术驱动设计

缺乏领域模型时,开发往往以数据库表结构为中心(数据库驱动设计),导致代码与业务脱节。例如,为了适应数据库关系而设计的类结构,可能无法反映真实业务概念。

8.3 难以应对复杂业务

对于复杂业务规则,没有领域模型的支撑会导致代码变得混乱:

  • 条件判断嵌套复杂
  • 业务规则隐藏在过程式代码中
  • 难以进行单元测试
  • 团队协作困难,代码冲突频繁

8.4 系统刚性

传统架构缺乏明确边界,模块间依赖紧密,一处修改可能引发多处问题。例如,修改订单状态字段可能影响到订单查询、统计、报表等多个功能。

九、DDD适用场景与注意事项

9.1 适合DDD的场景

  • 复杂业务领域:如金融、电商、物流等业务规则复杂的系统
  • 长期演进系统:需要持续迭代、扩展的大型应用
  • 团队协作开发:多团队、多角色参与的项目
  • 业务价值优先:业务逻辑对系统成功至关重要的项目

9.2 DDD的局限性

  • 学习曲线陡峭:需要团队理解领域驱动设计的概念和原则
  • 前期投入大:领域建模需要与领域专家深入沟通
  • 不适合简单系统:对于CRUD为主的简单应用,可能增加不必要的复杂度
  • 需要持续重构:领域模型需要随业务发展不断优化

9.3 实施建议

  1. 从小处着手:选择核心业务模块先行实施DDD
  2. 领域专家参与:确保开发人员与领域专家密切合作
  3. 持续建模:通过事件风暴、示例驱动等方法不断完善模型
  4. 避免过度设计:根据业务复杂度调整DDD实践的深度
  5. 自动化测试:为领域模型编写全面的单元测试

十、总结与扩展

本案例通过订单管理系统展示了DDD的核心概念和实践方法。从值对象、实体到聚合根,从领域服务到仓储,每个组件都有其明确的职责和设计意图。DDD不是银弹,但在复杂业务系统中,它提供了一套有效的方法论,帮助团队构建出更符合业务需求、更易维护的软件。

扩展方向

  1. 事件溯源(Event Sourcing):通过记录领域事件来重建对象状态,适合审计、溯源需求
  2. CQRS:命令查询职责分离,优化读写性能
  3. 微服务与DDD:结合限界上下文设计微服务边界
  4. 领域驱动设计工具:使用事件风暴工具、领域模型可视化工具等提升建模效率

要真正掌握DDD,需要在实践中不断学习和调整。建议结合具体业务场景,逐步应用DDD原则,而非教条式地套用所有模式。

相关推荐
Microsoft Word1 小时前
用户中心项目实战(springboot+vue快速开发管理系统)
vue.js·spring boot·后端
不写八个3 小时前
GoLang教程005:switch分支
开发语言·后端·golang
追逐时光者5 小时前
推荐 7 款开源、免费、美观的 .NET Blazor UI 组件库
后端·.net
叫我:松哥5 小时前
基于python django深度学习的中文文本检测+识别,可以前端上传图片和后台管理图片
图像处理·人工智能·后端·python·深度学习·数据挖掘·django
程序员岳焱5 小时前
从 0 到 1:Spring Boot 与 Spring AI 打造智能客服系统(基于DeepSeek)
人工智能·后端·deepseek
mldong5 小时前
GoFrame中间件注册竟然还能这样玩?团队开发效率提升200%!
后端·架构·go
艾醒6 小时前
使用服务器训练模型详解
后端
别来无恙1496 小时前
Spring Boot自动装配原理深度解析:从核心注解到实现机制
java·spring boot·后端
愿你天黑有灯下雨有伞7 小时前
Spring Boot+Redis Zset:三步构建高可靠延迟队列系统
spring boot·redis·后端
bobz9657 小时前
交换机上的DMZ的优先级比ACL的限制的优先级更高么
后端