# 校园二手书交易系统 — 详细设计文档 ## 1. 引言 ### 1.1 项目背景 校园内二手教材流转需求旺盛,但缺乏统一的线上交易平台。本项目旨在构建一个 C/S 架构的校园二手书交易系统,为学生提供便捷的书籍买卖渠道,为管理员提供数据监控与统计能力。 ### 1.2 项目目标 - 实现学生用户的注册、登录、浏览、搜索、购买书籍及订单管理 - 支持卖家用户上架、编辑、下架书籍及查看销售记录 - 提供管理员后台进行用户管理、商品管理、交易管理和数据统计 - 预留 AI 分析扩展能力(固定流程 + LLM 调用) ### 1.3 适用范围 本系统面向高校在校学生与管理人员,部署于校园局域网环境。 ### 1.4 术语与缩略语 | 术语 | 说明 | |------|------| | Buyer | 买家/普通学生用户 | | Seller | 卖家(买家身份的权限扩展) | | Admin | 系统管理员 | | C/S | Client/Server 架构 | | MyBatis-Plus | MyBatis 增强工具 | | LLM | Large Language Model,大语言模型 | --- ## 2. 总体设计 ### 2.1 系统架构 本系统采用经典 C/S 两层架构: ```mermaid flowchart TB subgraph Client [JavaFX 客户端 space.anyi.client] VIEW[FXML 视图层] CTRL[Controller 层] HSVC[HTTP Service 层] end subgraph Server [Spring Boot 服务端 space.anyi.server] CTL[Controller 层] SVC[Service 层] MPR[Mapper 层] end subgraph DB [MySQL 8.0] D[(campus_book_trade)] end Client <-->|HTTP/JSON RESTful API| Server MPR <--> D ``` 客户端与服务端之间仅通过 HTTP RESTful API 通信,无直接依赖。共享模块 `common` 提供实体类、DTO 和工具类。 ### 2.2 技术栈 | 层次 | 技术 | 版本 | |------|------|------| | 客户端 UI | JavaFX + FXML + Scene Builder | 23.0.2 | | 客户端 HTTP | `java.net.http.HttpClient` | JDK 内置 | | JSON 序列化 | Jackson (`jackson-databind` + `jackson-datatype-jsr310`) | 2.17.3 | | 服务端框架 | Spring Boot Web | 3.4.4 | | ORM | MyBatis-Plus (`mybatis-plus-spring-boot3-starter`) | 3.5.9 | | 数据库 | MySQL 8.0+ (Connector 8.4.0) | | | 构建工具 | Maven (3.9+) | | | Java | Corretto-23 | 23 | ### 2.3 模块划分 ``` CampusUsedBookTradingSystem/ ├── common/ 共享模块 — 实体、DTO、枚举 ├── server/ Spring Boot 服务端 │ ├── config/ 配置类(CORS、MyBatis-Plus、异常处理) │ ├── controller/ REST 控制器 │ ├── service/ 业务接口 │ ├── service/impl/ 业务实现 │ └── mapper/ MyBatis-Plus Mapper + XML ├── client/ JavaFX 客户端 │ ├── controller/ JavaFX 控制器 │ ├── service/ HTTP 调用封装 │ └── util/ 工具类 └── sql/ 数据库建表脚本 ``` 依赖关系:`server → common`,`client → common`。 ### 2.4 包结构总览 ``` space.anyi ├── common │ ├── entity/ User, Book, TransactionRecord │ ├── dto/ LoginRequest, RegisterRequest, R, PageResult, │ │ StatisticsSummary, DeptSalesDTO, DeptDiscountDTO, HotBookDTO │ └── enums/ UserRole ├── server │ ├── ServerApplication.java │ ├── config/ WebConfig, MyBatisPlusConfig, GlobalExceptionHandler │ ├── controller/ UserController, BookController, TransactionController, StatisticsController │ ├── service/ UserService, BookService, TransactionService, StatisticsService │ ├── service/impl/ UserServiceImpl, BookServiceImpl, TransactionServiceImpl, StatisticsServiceImpl │ └── mapper/ UserMapper, BookMapper, TransactionRecordMapper, StatisticsMapper └── client ├── App.java, Client.java ├── controller/ LoginController, RegisterController, MainController ├── service/ UserService, BookService, TransactionService, StatisticsService └── util/ HttpClientUtil, LoginUserHolder ``` --- ## 3. 数据库设计 ### 3.1 ER 图 ```mermaid erDiagram USER { int userid PK varchar username varchar password varchar nickname varchar email varchar phone varchar dept int credit int role int is_seller datetime created_at } BOOK { int book_id PK int seller_id FK varchar title varchar author varchar category decimal original_price decimal selling_price varchar image_url datetime created_at int stock } TRANSACTION_RECORD { int trans_id PK int book_id FK int buyer_id FK int transaction_num decimal transaction_price datetime transaction_time } USER ||--o{ BOOK : "seller" USER ||--o{ TRANSACTION_RECORD : "buyer" BOOK ||--o{ TRANSACTION_RECORD : "contains" ``` ### 3.2 表结构 #### 3.2.1 user 表 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | userid | int | PK, AUTO_INCREMENT | 用户ID | | username | varchar(255) | | 用户名 | | password | varchar(255) | | 密码(明文存储,后续改进) | | nickname | varchar(255) | | 昵称 | | email | varchar(255) | | 邮箱 | | phone | varchar(255) | | 电话 | | dept | varchar(255) | | 院系 | | credit | int | DEFAULT 100 | 信用分 | | role | int | DEFAULT 0 | 角色(0=学生, 1=管理员) | | is_seller | int | DEFAULT 0 | 是否为卖家(0=否, 1=是) | | created_at | datetime | | 注册时间 | #### 3.2.2 book 表 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | book_id | int | PK, AUTO_INCREMENT | 书籍ID | | seller_id | int | | 卖家ID(逻辑外键→user.userid) | | title | varchar(255) | | 书名 | | author | varchar(255) | | 作者 | | category | varchar(255) | | 分类 | | original_price | decimal(10,2) | | 原价 | | selling_price | decimal(10,2) | | 售价 | | image_url | varchar(255) | | 图片URL(预留) | | created_at | datetime | | 上架时间 | | stock | int | | 库存数量 | #### 3.2.3 transaction_record 表 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | trans_id | int | PK, AUTO_INCREMENT | 交易ID | | book_id | int | | 书籍ID(逻辑外键→book.book_id) | | buyer_id | int | | 买家ID(逻辑外键→user.userid) | | transaction_num | int | | 购买数量 | | transaction_price | decimal(10,2) | | 交易总价 | | transaction_time | datetime | | 交易时间 | ### 3.3 表关系说明 - `book.seller_id` → `user.userid`:一个卖家可发布多本书(一对多) - `transaction_record.book_id` → `book.book_id`:一本书可被多次交易(一对多) - `transaction_record.buyer_id` → `user.userid`:一个买家可有多笔交易(一对多) 当前 DDL 中未显式声明外键约束,由应用层(事务)保证数据一致性。 ### 3.4 SQL 脚本 建库脚本位于 `sql/campus_book_trade.sql`,包含完整 CREATE TABLE 和示例初始数据。字符集采用 `utf8mb4`。 --- ## 4. 服务端详细设计 ### 4.1 分层架构 ```mermaid flowchart LR subgraph Controller [Controller 层] direction LR UC[UserController] BC[BookController] TC[TransactionController] SC[StatisticsController] end subgraph Service [Service 层] direction LR US[UserService] BS[BookService] TS[TransactionService] SS[StatisticsService] end subgraph Mapper [Mapper 层] direction LR UM[UserMapper] BM[BookMapper] TM[TransactionRecordMapper] SM[StatisticsMapper] end DB[(MySQL)] Controller --> Service Service --> Mapper Mapper --> DB ``` 各层职责: | 层次 | 职责 | |------|------| | Controller | 请求映射、参数解析校验、调用 Service、封装 R 响应 | | Service | 核心业务逻辑、事务控制、组合操作 | | Mapper | 数据访问(继承 BaseMapper 提供 CRUD,自定义 SQL 提供统计) | | Config | CORS 跨域配置、MyBatis-Plus 分页插件、全局异常处理 | ### 4.2 RESTful API 接口定义 #### 4.2.1 用户模块 — `/api/user` | 方法 | 路径 | 请求体/参数 | 响应 | 说明 | |------|------|-------------|------|------| | POST | `/api/user/login` | `LoginRequest` | `R` | 登录认证 | | POST | `/api/user/register` | `RegisterRequest` | `R` | 注册新用户 | | GET | `/api/user` | `?page=&size=` | `R>` | 分页获取用户列表(Admin) | | GET | `/api/user/{id}` | | `R` | 获取单个用户 | | PUT | `/api/user/{id}` | `User` JSON | `R` | 更新用户信息 | | DELETE | `/api/user/{id}` | | `R` | 删除用户(Admin) | **LoginRequest**: ```json {"username": "string", "password": "string"} ``` **RegisterRequest**: ```json {"username": "string", "password": "string", "nickname": "string", "email": "string", "phone": "string", "dept": "string"} ``` #### 4.2.2 书籍模块 — `/api/book` | 方法 | 路径 | 参数 | 响应 | 说明 | |------|------|------|------|------| | GET | `/api/book` | keyword, category, page, size | `R>` | 搜索书籍(分页) | | GET | `/api/book/all` | | `R>` | 获取所有书籍 | | GET | `/api/book/{id}` | | `R` | 获取书籍详情 | | GET | `/api/book/my` | sellerId | `R>` | 卖家查看自己的书籍 | | GET | `/api/book/{id}/sales` | | `R>` | 查看书籍销售记录(卖家) | | GET | `/api/book/pending` | | `R>` | 查看待审核书籍列表(Admin) | | POST | `/api/book` | `Book` JSON | `R` | 创建/上架书籍(默认 status=0) | | PUT | `/api/book/{id}` | `Book` JSON | `R` | 更新书籍 | | PUT | `/api/book/{id}/audit` | `?status=` | `R` | 审核书籍(Admin: 0待审/1通过/2拒绝) | | DELETE | `/api/book/{id}` | | `R` | 删除书籍 | #### 4.2.3 交易模块 — `/api/transaction` | 方法 | 路径 | 请求体/参数 | 响应 | 说明 | |------|------|-------------|------|------| | POST | `/api/transaction` | `{bookId, buyerId, quantity}` | `R` | 购买 | | GET | `/api/transaction` | `?page=&size=` | `R>` | 分页查询所有交易 | | GET | `/api/transaction/{id}` | | `R` | 交易详情 | | GET | `/api/transaction/user/{userId}` | | `R>` | 用户交易记录 | | PUT | `/api/transaction/{id}` | `TransactionRecord` JSON | `R` | 更新交易(预留) | | DELETE | `/api/transaction/{id}` | | `R` | 删除交易 | #### 4.2.4 统计模块 — `/api/statistics` | 方法 | 路径 | 响应 | 说明 | |------|------|------|------| | GET | `/api/statistics/summary` | `R` | 交易总金额和总笔数 | | GET | `/api/statistics/top-departments` | `R>` | 销售额前三的院系 | | GET | `/api/statistics/top-books` | `R>` | 销量前五的书籍 | | GET | `/api/statistics/discount-rates` | `R>` | 各院系平均折扣率 | #### 4.2.5 AI 分析模块 — `/api/ai` | 方法 | 路径 | 响应 | 说明 | |------|------|------|------| | GET | `/api/ai/analysis` | `R` | 触发服务端固定分析流程,返回文本分析报告 | ### 4.3 统一响应格式 R\ 所有 API 返回统一结构: ```json { "code": 200, "message": "success", "data": { ... } } ``` | code | 含义 | |------|------| | 200 | 成功 | | 400 | 业务错误(参数错误、库存不足等) | | 500 | 服务器内部错误 | ### 4.4 分页设计 ```mermaid sequenceDiagram participant Client as JavaFX 客户端 participant Server as Spring Boot 服务端 participant DB as MySQL Client->>Server: GET /api/book?keyword=&category=&page=1&size=20 Server->>DB: MyBatis-Plus Page + LambdaQueryWrapper DB-->>Server: 分页数据 + 总数 Server->>Server: 转换为 PageResult Server-->>Client: R> Client->>Client: FXCollections.observableArrayList(records) → TableView ``` 服务端使用 MyBatis-Plus `IPage` 分页,通过 `PageResult` DTO 传输给客户端。MyBatis-Plus `PaginationInnerInterceptor` 自动拦截并改写分页 SQL。 ### 4.5 关键配置 #### WebConfig.java — CORS 允许跨域访问(开发环境 JavaFX 直连服务端,无代理层)。 #### MyBatisPlusConfig.java - 启用分页插件 `PaginationInnerInterceptor(DbType.MYSQL)` - 开启 `map-underscore-to-camel-case: true` - 主键生成策略:`id-type: auto`(数据库自增) #### GlobalExceptionHandler | 异常 | 响应 | |------|------| | `DuplicateKeyException` | `R.error("用户名已存在")` | | `IllegalArgumentException` | `R.error(异常消息)` | | `Exception`(兜底) | `R.error("服务器内部错误: " + e.getMessage())` | ### 4.6 核心业务逻辑 #### 4.6.1 注册流程 ```mermaid sequenceDiagram participant Client as JavaFX 客户端 participant Server as 服务端 participant DB as MySQL Client->>Server: POST /api/user/register (RegisterRequest) Server->>Server: 创建 User 对象 Note over Server: 设置默认值:
credit=100, role=0,
isSeller=0, createdAt=now Server->>DB: INSERT INTO user DB-->>Server: User (含自增ID) Server-->>Client: R.ok(user) ``` #### 4.6.2 登录流程 ```mermaid sequenceDiagram participant Client as JavaFX 客户端 participant Server as 服务端 participant DB as MySQL Client->>Server: POST /api/user/login (LoginRequest) Server->>DB: SELECT * FROM user WHERE username=? AND password=? DB-->>Server: User / null alt user == null Server-->>Client: R.error("Invalid username or password") else Server-->>Client: R.ok(user) Client->>Client: LoginUserHolder.set(user) Client->>Client: App.showMainScene() end ``` #### 4.6.3 购买流程(事务) ```mermaid sequenceDiagram participant Client as JavaFX 客户端 participant Server as 服务端 participant DB as MySQL Client->>Server: POST /api/transaction {bookId, buyerId, quantity} Server->>Server: @Transactional 开启事务 Server->>DB: SELECT * FROM book WHERE book_id=? DB-->>Server: {stock=N, sellingPrice=P} alt stock < quantity Server-->>Client: R.error("Insufficient stock") Server->>Server: 回滚事务 else Server->>DB: UPDATE book SET stock = stock - quantity Server->>DB: INSERT INTO transaction_record (bookId, buyerId, transactionNum, transactionPrice, transactionTime) Server->>Server: 提交事务 Server-->>Client: R.ok(transactionRecord) end ``` **事务边界**(`TransactionServiceImpl.purchase()`): 1. 查询书籍,校验库存 2. 扣减库存 `book.stock -= quantity` 3. 创建交易记录(价格 = `sellingPrice × quantity`) 4. 任一失败则 `@Transactional` 回滚 #### 4.6.4 搜索流程 ``` 1. 客户端组装参数:keyword + category + page + size 2. GET /api/book?keyword=&category=&page=&size= 3. 服务端构建动态查询条件: - keyword → LIKE title OR LIKE author - category → EQ category - 按 created_at DESC 排序 4. MyBatis-Plus 分页查询 + 返回 PageResult ``` ### 4.7 统计实现 统计模块全部使用自定义 SQL 在 `StatisticsMapper` 中通过 `@Select` 注解实现: | 统计项 | SQL 概要 | |--------|----------| | summary | `SELECT COALESCE(SUM(transaction_price),0), COUNT(*) FROM transaction_record` | | top-departments | JOIN `transaction_record` + `book` + `user`,按 `user.dept` 分组,销售额前3 | | top-books | JOIN `transaction_record` + `book`,按 `book` 分组,销量前5 | | discount-rates | `AVG((original_price - unit_price) / original_price * 100)`,按 `dept` 分组 | --- ## 5. 客户端详细设计 ### 5.1 界面导航 ```mermaid flowchart LR A[login.fxml] -->|登录成功| C[main.fxml] A -->|点击注册链接| B[register.fxml] B -->|注册成功| A B -->|返回登录| A C -->|退出登录| A ``` `App.java` 作为 JavaFX Application 入口,通过静态方法实现场景切换。`Client.java` 为启动入口(`Application.launch(App.class, args)`)。 ### 5.2 FXML 视图结构 #### login.fxml ``` VBox (400×350) ├── Label "校园书市"(标题,22px bold) ├── TextField #usernameField(用户名输入) ├── PasswordField #passwordField(密码输入) ├── Button "登录" → #handleLogin(btn-primary) └── Hyperlink "没有账号?立即注册" → #handleRegister ``` #### register.fxml ``` VBox (400×500) ├── Label "创建账号"(标题,20px bold) ├── TextField #usernameField(用户名 *) ├── PasswordField #passwordField(密码 *) ├── TextField #nicknameField(昵称) ├── TextField #emailField(邮箱) ├── TextField #phoneField(电话) ├── TextField #deptField(院系) ├── Button "注册" → #handleRegister(btn-primary) └── Hyperlink "已有账号?去登录" → #handleBack ``` #### main.fxml ``` BorderPane (1000×700) ├── Top: HBox 顶部标题栏 │ ├── Label #welcomeLabel "欢迎,xxx" │ └── Button "退出登录" → #handleLogout(btn-danger) │ └── Center: TabPane(6个Tab) │ ├── Tab "浏览书籍"(买家/卖家共有的 browse tab) │ ├── HBox 搜索栏: TextField #searchField + ComboBox #categoryCombo + Button "搜索" │ └── SplitPane (0.6) │ ├── TableView #bookTable [编号,书名,作者,分类,价格,库存] │ └── VBox: 详情 Label 组 + TextField #quantityField + Button "购买" │ ├── Tab "我的交易"(买家/卖家) │ ├── Button "刷新" → #handleLoadTransactions │ └── TableView #transTable [交易编号,书籍编号,数量,总价,时间] │ ├── Tab "个人信息"(买家/卖家) │ └── VBox: #profileUsername(只读), #profileNickname, #profileEmail, #profilePhone, #profileDept, #profileCredit(只读) + Button "保存修改" │ ├── Tab "卖家中心"(isSeller=1 启用) │ ├── Label "我的书籍" │ ├── Button "刷新" → #handleLoadMyBooks │ ├── TableView #myBookTable [编号,书名,价格,库存] │ ├── Button "删除选中" → #handleDeleteBook │ └── TitledPane "添加新书" │ └── GridPane: 书名/作者/分类/原价/售价/库存 输入 + Button "添加书籍" │ ├── Tab "数据统计"(所有角色可见) │ └── ScrollPane > VBox │ ├── Button "刷新数据" → #handleLoadStatistics │ ├── TitledPane "总览": statTotalAmount + statTotalCount │ ├── TitledPane "热门院系(销量前三)": TableView #deptTable │ ├── TitledPane "热门书籍(前五)": TableView #hotBookTable │ └── TitledPane "各院系平均折扣率": TableView #discountTable │ └── Tab "管理"(role=1 启用) ├── Label "用户管理" ├── Button "刷新用户" → #handleLoadAllUsers ├── TableView #userTable [编号,用户名,昵称,院系,信用分,角色,卖家] ├── Button "删除选中用户" → #handleDeleteUser ├── Label "全部交易" ├── Button "刷新交易" → #handleLoadAllTransactions ├── TableView #allTransTable [交易编号,书籍编号,买家编号,数量,价格,时间] └── Button "删除选中交易" → #handleDeleteTransaction ``` ### 5.3 控制器设计 #### LoginController | 字段/方法 | 类型 | 说明 | |-----------|------|------| | usernameField | TextField | 用户名输入框 | | passwordField | PasswordField | 密码输入框 | | userService | UserService | HTTP 服务层 | | handleLogin() | void | 校验非空 → 调用登录 API → 存入会话 → 跳转主界面 | | handleRegister() | void | 跳转到注册界面 | #### RegisterController | 字段/方法 | 类型 | 说明 | |-----------|------|------| | usernameField ~ deptField | TextField / PasswordField | 注册表单字段 | | userService | UserService | HTTP 服务层 | | handleRegister() | void | 校验必填 → 调用注册 API → 提示 → 跳回登录 | | handleBack() | void | 返回登录界面 | #### MainController | Tab | 核心方法 | 说明 | |-----|----------|------| | 浏览书籍 | `handleSearch()` | 搜索 + 刷新列表 | | | `handlePurchase()` | 校验 → 购买 → 刷新 | | | `initialize()` | 绑定表格列、设置角色权限、加载数据 | | 我的交易 | `handleLoadTransactions()` | 加载当前用户交易记录 | | 个人信息 | `handleUpdateProfile()` | 保存修改 + 更新会话 | | 卖家中心 | `handleLoadMyBooks()` | 加载卖家自己的书籍 | | | `handleAddBook()` | 上架新书 | | | `handleDeleteBook()` | 删除选中书籍 | | 数据统计 | `handleLoadStatistics()` | 加载4个统计指标 | | 管理 | `handleLoadAllUsers()` | 加载所有用户 | | | `handleDeleteUser()` | 删除选中用户 | | | `handleLoadAllTransactions()` | 加载所有交易 | | | `handleDeleteTransaction()` | 删除选中交易 | **会话初始化**(`initialize()` 方法): 1. 从 `LoginUserHolder` 获取当前用户 2. 设置欢迎语和个人信息回显 3. 根据 `isSeller` 和 `role` 控制 sellerTab 和 adminTab 的启用状态 ### 5.4 HTTP 服务层设计 #### HttpClientUtil 单例模式的 `HttpClient` + Jackson `ObjectMapper`,提供泛型方法: | 方法 | 说明 | |------|------| | `get(path, Class)` | GET 请求,简单类型反序列化 | | `get(path, TypeReference)` | GET 请求,泛型类型反序列化 | | `post(path, body, Class)` | POST 请求 | | `put(path, body, Class)` | PUT 请求 | | `delete(path, Class)` | DELETE 请求 | 基 URL = `http://localhost:8080`,错误时返回 code=500。 #### 客户端 Service 封装 | Service | 封装方法 | 对应 API | |---------|----------|----------| | UserService | login, register, getById, update, delete | `/api/user/*` | | BookService | search, getById, getMyBooks, listAll, create, update, delete | `/api/book/*` | | TransactionService | purchase, getById, getByUser, update, delete | `/api/transaction/*` | | StatisticsService | getSummary, getTopDepartments, getTopBooks, getDiscountRates | `/api/statistics/*` | ### 5.5 会话管理 `LoginUserHolder`:基于内存的静态会话管理。 ```java LoginUserHolder.set(user); // 登录成功后存入 LoginUserHolder.get(); // 获取当前用户 LoginUserHolder.isSeller(); // 判断是否为卖家 LoginUserHolder.clear(); // 退出时清除 ``` 当前无 Token/JWT 机制,userId 通过请求参数/体明文传输。 ### 5.6 BootstrapFX 样式整合 引入 `org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0`,在场景加载时添加 bootstrapfx.css。额外定制 `css/style.css`:全局字体、按钮手型光标、表格边框圆角。 --- ## 6. 用户角色与权限设计 ### 6.1 角色模型 用户角色由两个字段组合定义: | role | isSeller | 角色 | |:----:|:--------:|------| | 0 | 0 | 普通学生(买家) | | 0 | 1 | 卖家(同时具备买家权限) | | 1 | 0/1 | 管理员 | `UserRole.java` 枚举仅定义 `STUDENT(0)` 和 `ADMIN(1)`,卖家用 `isSeller` 标志区分。 ### 6.2 权限矩阵 | 功能模块 | 功能点 | 买家 | 卖家 | 管理员 | |----------|--------|:----:|:----:|:------:| | 账号 | 注册 | ✅ | ✅ | ✅ | | 账号 | 登录 | ✅ | ✅ | ✅ | | 书籍 | 浏览/搜索 | ✅ | ✅ | ✅ | | 书籍 | 查看详情 | ✅ | ✅ | ✅ | | 书籍 | 购买 | ✅ | ✅ | ❌ | | 书籍 | 上架 | ❌ | ✅ | ✅ | | 书籍 | 编辑 | ❌ | ✅ | ✅ | | 书籍 | 下架/删除 | ❌ | ✅ | ✅ | | 书籍 | 查看自己的发布 | ❌ | ✅ | ✅ | | 书籍 | 审核(待实现) | ❌ | ❌ | ✅ | | 订单 | 查看自己的订单 | ✅ | ✅ | ✅ | | 订单 | 查看全部订单 | ❌ | ❌ | ✅ | | 订单 | 删除订单 | ❌ | ❌ | ✅ | | 用户 | CRUD | ❌ | ❌ | ✅ | | 用户 | 重置密码 | ❌ | ❌ | ✅ | | 统计 | 查看统计数据 | ✅ | ✅ | ✅ | | AI | 分析报告(待实现) | ❌ | ❌ | ✅ | ### 6.3 客户端权限控制 在 `MainController.initialize()` 中: ```java if (user.getIsSeller() != 1) sellerTab.setDisable(true); // 非卖家禁用卖家中心 if (user.getRole() != 1) adminTab.setDisable(true); // 非管理员禁用管理Tab ``` Tab 被禁用后用户无法点击,但 FXML 元素仍保留。 ### 6.4 服务端校验(待完善) 当前服务端未实现权限拦截,所有 API 均可被任意客户端调用。生产环境建议引入 Spring Security 或自定义拦截器。 --- ## 7. 数据流设计 ### 7.1 登录注册流程 ```mermaid sequenceDiagram actor User as 用户 participant Login as 登录界面 participant Reg as 注册界面 participant Main as 主界面 participant Svc as 客户端Service participant API as 服务端API participant DB as 数据库 Note over User,DB: === 登录流程 === User->>Login: 输入用户名+密码 Login->>Svc: userService.login(username, password) Svc->>API: POST /api/user/login API->>DB: SELECT * FROM user WHERE username=? AND password=? DB-->>API: User API-->>Svc: R.ok(user) Svc-->>Login: R Login->>Login: LoginUserHolder.set(user) Login->>Main: App.showMainScene() Note over User,DB: === 注册流程 === User->>Reg: 填写表单 Reg->>Svc: userService.register(RegisterRequest) Svc->>API: POST /api/user/register API->>API: 设置默认值 (credit=100,role=0,isSeller=0) API->>DB: INSERT INTO user DB-->>API: User API-->>Svc: R.ok(user) Svc-->>Reg: 注册成功 Reg->>Login: App.showLoginScene() ``` ### 7.2 购买交易流程 ```mermaid sequenceDiagram actor Buyer as 买家 participant Browse as 浏览Tab participant Svc as TransactionService participant API as 服务端 participant DB as 数据库 Buyer->>Browse: 选择书籍 → 输入数量 → 点击购买 Browse->>Svc: purchase(bookId, buyerId, quantity) Svc->>API: POST /api/transaction API->>API: @Transactional 开启 API->>DB: SELECT stock FROM book WHERE book_id=? DB-->>API: stock=N alt N < quantity API-->>Svc: R.error("Insufficient stock") Svc-->>Browse: Alert 警告 else API->>DB: UPDATE book SET stock = stock - quantity API->>DB: INSERT INTO transaction_record API->>API: 提交事务 API-->>Svc: R.ok(record) Svc-->>Browse: Alert 成功 + 刷新列表 end ``` ### 7.3 搜索书籍流程 ```mermaid sequenceDiagram actor User as 用户 participant Browse as 浏览Tab participant Svc as BookService participant API as 服务端 participant DB as 数据库 User->>Browse: 输入关键字 / 选择分类 User->>Browse: 点击"搜索" Browse->>Svc: search(keyword, category, page, size) Svc->>API: GET /api/book?keyword=&category= API->>API: LambdaQueryWrapper 动态条件 API->>DB: SELECT ... WHERE title LIKE ? OR author LIKE ? AND category=? ORDER BY created_at DESC DB-->>API: 分页结果 API-->>Svc: R.ok(PageResult) Svc-->>Browse: 数据列表 Browse->>Browse: bookTable.setItems(...) ``` --- ## 8. 已实现功能清单 以下列出所有基于 `demand.md` 需求已实现的功能及其对应代码位置: ### 8.1 卖家-编辑书籍 — ✅ 已实现 | 组件 | 说明 | |------|------| | FXML | 卖家中心 Tab 新增"编辑选中"按钮 (`main.fxml:92`) | | Controller | `handleEditBook()` — 选中书籍回填表单,切换为编辑模式 (`MainController.java`) | | 复用 | `handleAddBook()` — 检测 `editingBook` 字段,区分新增/更新逻辑 | | 重置 | `clearBookForm()` — 编辑完成后重置表单状态 | ### 8.2 卖家-查看销售记录 — ✅ 已实现 | 组件 | 说明 | |------|------| | API | `GET /api/book/{id}/sales` — 返回 `List` (`BookController.java:56`) | | DTO | `SalesRecordDTO` — bookId, title, buyerId, buyerName, quantity, totalPrice, transactionTime | | Mapper | `BookMapper.selectSalesByBookId()` — JOIN transaction_record + book + user | | 客户端 | `handleViewSales()` — 弹出 Dialog 展示销售记录表格 (`MainController.java`) | ### 8.3 管理员-用户管理完善 — ✅ 已实现 | 组件 | 说明 | |------|------| | 编辑用户 | `handleEditUser()` — 选中用户回填表单,支持修改 (`MainController.java`) | | 添加用户 | `handleSaveUser()` — 创建用户(调用 Register API) | | 重置密码 | `handleResetPassword()` — 密码重置为 `123456` | | FXML | 用户表单 TitledPane (`main.fxml`) | ### 8.4 管理员-商品管理 — ✅ 已实现 | 组件 | 说明 | |------|------| | TableView | `adminBookTable` — 显示所有书籍(编号、书名、作者、分类、售价、库存、卖家ID) | | 刷新 | `handleLoadAllBooksAdmin()` — 调用 `GET /api/book/all` | | 删除 | `handleDeleteBookAdmin()` — 删除选中书籍 | ### 8.5 管理员-审核书籍 — ✅ 已实现 | 组件 | 说明 | |------|------| | Schema | `book` 表增加 `status` 字段: 0=待审核, 1=已上架, 2=已下架 | | Entity | `Book.java` 增加 `@TableField("status") private Integer status;` | | API | `GET /api/book/pending` — 获取待审核书籍 | | API | `PUT /api/book/{id}/audit?status=` — 审核通过/拒绝 | | 搜索过滤 | `searchBooks()` 仅返回 `status=1` 的书籍 | | 新书上架 | `create()` 默认 `status=0`(待审核) | | 客户端 | `pendingBookTable` + "通过"/"拒绝" 按钮 | ### 8.6 AI 分析 — ✅ 已实现 | 组件 | 说明 | |------|------| | Service | `AiServiceImpl.generateAnalysis()` — 汇总统计数据 → 格式化分析报告 | | Controller | `GET /api/ai/analysis` — 返回 `R` 文本报告 | | 客户端 | `AiService` — HTTP 调用封装 | | UI | 管理 Tab 增加"AI 分析"区域: "生成分析报告"按钮 + `TextArea` 展示区 | | 后续 | LLM 接入方案(API Key、模型选择、固定提示词模板)待补充 | ### 8.7 信用分修改 — ✅ 已实现 | 组件 | 说明 | |------|------| | UI | 管理 Tab 用户管理区增加"修改信用分"按钮 | | 交互 | `TextInputDialog` 输入新分值 → 调用 `PUT /api/user/{id}` 更新 | --- ## 附录 A:配置文件 ### application.yml ```yaml server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/campus_book_trade?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto ``` ## 附录 B:构建命令 ```sh # 全量构建(需 JDK 23) JAVA_HOME=/path/to/corretto-23 mvn clean install # 运行服务端 mvn spring-boot:run -pl server # 运行客户端 mvn javafx:run -pl client ```