第六章:综合项目实战——SmartBook
这部分内容是地基,确保学生在进入 AI 环节前,先搭建好一个稳固的、支持事务的 Java 业务系统。
1. 章节导读 (chapter06/index.md)
| ---
title: 第六章:综合项目实战——SmartBook 二手书交易智能体
---
# 第六章:综合项目实战——SmartBook 二手书交易智能体
!!! quote "本章目标"
还记得我们在实验 3 和 4 中写的“图书管理系统”吗?那时候它只是个简单的增删改查玩具。
**今天,我们要让它“长大”了。**
我们将引入**用户**和**订单**的概念,把它升级为一个真正的 **C2C (个人对个人) 二手书交易平台**。更酷的是,我们将接入 AI,让交易不再需要点击繁琐的表单,而是像聊天一样自然。
---
## 🗺️ 项目蓝图
**项目名称**:SmartBook(智慧书摊)
**核心理念**:让二手交易像聊天一样简单。
**场景演示**:
* **场景 A (我是卖家)**:
* 同学说:“我有一本《算法导论》想卖 25 块钱,九成新。”
* **AI 助手**:自动提取书名、价格、成色,自动上架到数据库。
* **场景 B (我是买家)**:
* 同学说:“帮我找找有没有便宜的 Java 书?最好是 20 块以下的。”
* **AI 助手**:自动搜索数据库,列出符合条件的书,并问:“要下单吗?”
---
## 🏗️ 架构设计
我们将严格遵循企业级开发流程,而不是上来就写代码:
```mermaid
graph TD
User((用户)) -- 自然语言指令 --> Agent["🤖 AI 智能体<br/>(Controller + DeepSeek)"]
subgraph "核心业务层 (Spring Boot)"
Agent -- "1. 意图识别" --> Tools["🛠️ Tools (工具箱)"]
Tools -- "2. 调用" --> Service["Business Service<br/>(事务管理)"]
Service -- "3. 读写" --> Mapper["MyBatis Mapper"]
end
subgraph "数据存储层 (信创)"
Mapper -- SQL --> DB[("openGauss 数据库")]
end
style Agent fill:#e1f5fe,stroke:#01579b
style Service fill:#fff9c4,stroke:#fbc02d
style DB fill:#e8f5e9,stroke:#2e7d32
|
📚 课程目录
开始第一步:需求分析与建模
| ---
### 2. 需求分析与建模 (`chapter06/01-design.md`)
```markdown
# 01. 需求分析与建模 (AI 辅助设计)
在开始写代码之前,我们需要用 **ER 图** 来理清业务逻辑。不要一上来就打开 IDEA 写代码,那是“码农”的做法,架构师都是先画图的。
## 🏢 第一步:需求分析
我们要实现一个 C2C 交易模型,核心实体有三个:
1. **用户 (User)**:包含余额、姓名。在本项目中,一个用户既可以是买家,也可以是卖家。
2. **图书 (Book)**:核心商品。需要增加字段:`seller_id` (谁卖的)、`status` (在售/已售)、`price`。
3. **交易订单 (Transaction)**:记录谁买了哪本书,成交价是多少,防止赖账。
## 📊 第二步:业务建模 (ER 图)
!!! question "让 AI 设计数据库模型"
**Prompt**:
> "我正在设计一个校园二手书交易系统。请帮我设计数据库 ER 图。
> 包含实体:
> 1. User (id, name, balance)
> 2. Book (id, title, author, price, status[ON_SALE, SOLD], seller_id)
> 3. Transaction (id, buyer_id, book_id, deal_price, create_time)
>
> **关系逻辑**:
> - 一个用户可以发布多本书 (User 1:N Book)。
> - 一个用户可以购买多本书 (User 1:N Transaction)。
> - 一本书只能对应一笔交易 (Book 1:1 Transaction)。
>
> 请输出 **Mermaid Class Diagram** 代码。"
**系统架构图:**
```mermaid
classDiagram
class User {
+Long id
+String username
+BigDecimal balance
}
class Book {
+Long id
+String title
+String author
+BigDecimal price
+String status
+Long seller_id
}
class Transaction {
+Long id
+Long buyer_id
+Long book_id
+BigDecimal deal_price
+DateTime create_time
}
User "1" --> "N" Book : sells (发布)
User "1" --> "N" Transaction : buys (购买)
Book "1" --> "1" Transaction : sold_in (成交)
|
💾 第三步:数据库落地 (openGauss)
请连接你的 openGauss 数据库,执行以下初始化脚本。
openGauss 对标准 SQL 的支持非常好。这里的 SERIAL 关键字用于自增主键,DECIMAL 用于金额(千万别用 double 存钱!)。
| -- 1. 用户表
CREATE TABLE t_user (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
balance DECIMAL(10, 2) DEFAULT 0.00 -- 初始余额
);
-- 2. 图书表
CREATE TABLE t_book (
id SERIAL PRIMARY KEY,
title VARCHAR(100) NOT NULL,
author VARCHAR(50),
price DECIMAL(10, 2) NOT NULL,
status VARCHAR(20) DEFAULT 'ON_SALE', -- ON_SALE, SOLD
seller_id INT NOT NULL,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 3. 交易订单表
CREATE TABLE t_transaction (
id SERIAL PRIMARY KEY,
buyer_id INT NOT NULL,
book_id INT NOT NULL,
deal_price DECIMAL(10, 2) NOT NULL,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 初始化测试数据
-- 张三有 100 块,卖一本《Java编程思想》
-- 李四有 500 块,是土豪买家
INSERT INTO t_user (username, balance) VALUES ('zhangsan', 100.00), ('lisi', 500.00);
INSERT INTO t_book (title, author, price, seller_id) VALUES ('Java编程思想', 'Bruce Eckel', 50.00, 1);
|
下一步:
数据库准备好了,接下来我们要用 Java 来操作它。
特别是 “买书” 这个操作,涉及扣钱、改状态、记账,必须保证事务安全。
下一节:核心业务开发
| ---
### 3. 核心业务开发 (`chapter06/02-implementation.md`)
```markdown
# 02. 核心业务开发 (AI 辅助编码)
AI 再聪明,也需要有“手”才能干活。
本节我们将编写 Service 层代码,为 AI 提供两个核心能力(Tools):**发布图书** 和 **购买图书**。
## 🔨 第一步:生成基础代码
请使用 **MyBatisX 插件** 或 AI,根据数据库表反向生成 `User`, `Book`, `Transaction` 的实体类及 Mapper 接口。
*(这一步在第 4 章练过多次,此处省略重复步骤,请确保 Mapper XML 能正常工作)*
## 🔧 第二步:编写 TradeService (核心)
我们要实现一个 `TradeService`,它包含两个核心方法。
### 1. 发布图书 (publishBook)
逻辑很简单:就是往 `t_book` 表插一条数据。
```java
@Service
public class TradeService {
@Autowired
private BookMapper bookMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private TransactionMapper transactionMapper;
/**
* 工具 1: 发布图书
*/
public Book publishBook(String sellerName, String title, BigDecimal price) {
// 1. 根据名字找用户 (简化逻辑,实际应从 Session 获取)
User seller = userMapper.findByName(sellerName);
if (seller == null) throw new RuntimeException("卖家不存在");
// 2. 构建图书对象
Book book = new Book();
book.setTitle(title);
book.setPrice(price);
book.setSellerId(seller.getId());
book.setStatus("ON_SALE");
// 3. 插入数据库
bookMapper.insert(book);
return book;
}
}
|
2. 购买图书 (buyBook) —— 事务实战
逻辑很复杂:买家扣钱 -> 卖家加钱(可选) -> 图书下架 -> 生成订单。
只要中间任何一步报错(比如买家钱不够),所有操作必须全部回滚。必须加上 @Transactional。
| /**
* 工具 2: 购买图书
* @param buyerName 买家名字
* @param bookId 图书ID
*/
@Transactional(rollbackFor = Exception.class) // 👈 事务开关
public Transaction buyBook(String buyerName, Long bookId) {
// 1. 检查图书
Book book = bookMapper.selectById(bookId);
if (book == null || !"ON_SALE".equals(book.getStatus())) {
throw new RuntimeException("图书不存在或已售出");
}
// 2. 检查买家
User buyer = userMapper.findByName(buyerName);
if (buyer.getBalance().compareTo(book.getPrice()) < 0) {
throw new RuntimeException("余额不足,交易失败");
}
// 3. 执行交易 (原子操作)
// 3.1 扣买家的钱
buyer.setBalance(buyer.getBalance().subtract(book.getPrice()));
userMapper.update(buyer);
// 3.2 下架图书
book.setStatus("SOLD");
bookMapper.update(book);
// 3.3 生成订单
Transaction tx = new Transaction();
tx.setBuyerId(buyer.getId());
tx.setBookId(book.getId());
tx.setDealPrice(book.getPrice());
transactionMapper.insert(tx);
return tx;
}
|
🧪 第三步:自动化测试 (JUnit 5)
AI 只能调用代码,不能帮你调试代码。必须先确保 Service 本身是无 Bug 的。
| @SpringBootTest
class TradeServiceTest {
@Autowired TradeService tradeService;
@Test
void testBuyBook_NotEnoughMoney() {
// 场景:李四想买一本 10000 块的书(余额只有 500)
// 断言:必须抛出异常
assertThrows(RuntimeException.class, () -> {
tradeService.buyBook("lisi", 9999L);
});
}
@Test
void testBuyBook_Success() {
// 场景:李四买张三的《Java编程思想》(50元)
tradeService.buyBook("lisi", 1L);
// 这里的验证逻辑可以查数据库确认状态是否变更
}
}
|
下一步:
现在我们的 Java 系统已经具备了完美的交易能力。
但是,用户还需要通过代码或者复杂的 UI 才能调用它。
下一节,我们将接入 DeepSeek,让 AI 替用户按按钮。
下一节:智能体集成 (Tool Calling)
| ---
陈老师,前三份文档(导读、设计、核心实现)已完成。
接下来的一步是重头戏:**`03-agent-integration.md` (智能体集成)** 和 **`lab6.md` (实验任务书)**。我将重点把 **ChatController** 的代码写得尽量简单、可复制,确保学生能看懂。
**需要我继续生成剩下的这两份文档吗?**
|