Compare commits
3 Commits
812defdfc6
...
301fa6c85c
| Author | SHA1 | Date | |
|---|---|---|---|
| 301fa6c85c | |||
| 3f71217dfc | |||
| 5571e85363 |
163
CLAUDE.md
163
CLAUDE.md
@@ -34,7 +34,7 @@ POST http://localhost:8080/login/test?username=admin&password=admin123
|
||||
| 后端技术 | 版本 | 前端技术 | 版本 |
|
||||
|-----------------------------|--------|------------|---------|
|
||||
| Spring Boot | 3.5.8 | Vue.js | 2.6.12 |
|
||||
| Java | 17 | Element UI | 2.15.14 |
|
||||
| Java | 21 | Element UI | 2.15.14 |
|
||||
| MyBatis Spring Boot Starter | 3.0.5 | Vuex | 3.6.0 |
|
||||
| MySQL Connector | 8.2.0 | Vue Router | 3.4.9 |
|
||||
| SpringDoc OpenAPI | 2.8.14 | Axios | 0.28.1 |
|
||||
@@ -114,7 +114,10 @@ ccdi/
|
||||
├── ruoyi-common/ # 通用工具 (annotations, utils, constants)
|
||||
├── ruoyi-quartz/ # 定时任务
|
||||
├── ruoyi-generator/ # 代码生成器
|
||||
├── ruoyi-info-collection/ # 【核心业务模块】信息采集
|
||||
├── ccdi-info-collection/ # 【核心业务模块】信息采集
|
||||
├── ccdi-project/ # 【核心业务模块】项目管理
|
||||
├── ccdi-lsfx/ # 【核心业务模块】流水分析对接
|
||||
├── lsfx-mock-server/ # 流水分析模拟服务器 (Python)
|
||||
├── ruoyi-ui/ # 前端 Vue 应用
|
||||
├── sql/ # 数据库脚本
|
||||
├── bin/ # 启动脚本
|
||||
@@ -130,7 +133,11 @@ ruoyi-admin (启动模块)
|
||||
├── ruoyi-common (共享工具)
|
||||
├── ruoyi-quartz (定时任务)
|
||||
├── ruoyi-generator (代码生成)
|
||||
└── ruoyi-info-collection (信息采集模块)
|
||||
├── ccdi-info-collection (信息采集模块)
|
||||
│ └── 依赖 ruoyi-common
|
||||
├── ccdi-project (项目管理模块)
|
||||
│ └── 依赖 ruoyi-common
|
||||
└── ccdi-lsfx (流水分析对接模块)
|
||||
└── 依赖 ruoyi-common
|
||||
```
|
||||
|
||||
@@ -140,7 +147,7 @@ ruoyi-admin (启动模块)
|
||||
3. 在 `ruoyi-admin/pom.xml` 中添加对新模块的依赖
|
||||
4. 在新模块中按照分层规范创建 controller/service/mapper/domain 包
|
||||
|
||||
### ruoyi-info-collection 业务模块 (核心)
|
||||
### ccdi-info-collection 业务模块 (核心)
|
||||
|
||||
自定义业务模块,包含以下核心功能:
|
||||
|
||||
@@ -158,14 +165,87 @@ ruoyi-admin (启动模块)
|
||||
|
||||
**分层结构:**
|
||||
|
||||
- Controller: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/`
|
||||
- Service: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/`
|
||||
- Mapper: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/`
|
||||
- Domain: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/`
|
||||
- Controller: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/`
|
||||
- Service: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/`
|
||||
- Mapper: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/`
|
||||
- Domain: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/`
|
||||
- dto/: 数据传输对象
|
||||
- vo/: 视图对象
|
||||
- excel/: Excel导入导出实体
|
||||
- XML映射: `ruoyi-info-collection/src/main/resources/mapper/info/collection/`
|
||||
- XML映射: `ccdi-info-collection/src/main/resources/mapper/info/collection/`
|
||||
|
||||
### ccdi-project 业务模块 (核心)
|
||||
|
||||
项目管理模块,用于管理纪检初核项目的全生命周期:
|
||||
|
||||
**核心功能:**
|
||||
- 项目创建、更新、删除、查询
|
||||
- 项目状态管理 (进行中、已完成、已归档)
|
||||
- 项目统计(按状态统计数量)
|
||||
- 模型参数配置管理
|
||||
|
||||
**主要 Controller:**
|
||||
- CcdiProjectController: 项目管理
|
||||
- CcdiModelParamController: 模型参数配置
|
||||
|
||||
**分层结构:**
|
||||
- Controller: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/`
|
||||
- Service: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/`
|
||||
- Mapper: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/`
|
||||
- Domain: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/`
|
||||
- XML映射: `ccdi-project/src/main/resources/mapper/ccdi/project/`
|
||||
|
||||
### ccdi-lsfx 业务模块 (核心)
|
||||
|
||||
流水分析平台对接模块,用于与外部流水分析系统交互:
|
||||
|
||||
**核心功能:**
|
||||
- 获取访问令牌 (Token)
|
||||
- 上传流水文件并解析
|
||||
- 拉取行内流水数据
|
||||
- 查询解析状态和结果
|
||||
- 获取银行流水明细
|
||||
|
||||
**主要组件:**
|
||||
- LsfxAnalysisClient: 流水分析平台客户端
|
||||
- LsfxTestController: 测试接口
|
||||
|
||||
**配置项 (application-dev.yml):**
|
||||
```yaml
|
||||
lsfx:
|
||||
api:
|
||||
base-url: http://localhost:8000 # 流水分析平台地址
|
||||
app-id: your-app-id
|
||||
app-secret: your-app-secret
|
||||
client-id: your-client-id
|
||||
endpoints:
|
||||
get-token: /api/auth/token
|
||||
upload-file: /api/files/upload
|
||||
fetch-inner-flow: /api/flow/inner
|
||||
```
|
||||
|
||||
**分层结构:**
|
||||
- Client: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/`
|
||||
- Controller: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/controller/`
|
||||
- Domain: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/`
|
||||
- request/: 请求对象
|
||||
- response/: 响应对象
|
||||
- Config: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/config/`
|
||||
|
||||
### lsfx-mock-server (开发测试工具)
|
||||
|
||||
Python 实现的流水分析平台模拟服务器,用于本地开发和测试:
|
||||
|
||||
**用途:**
|
||||
- 模拟流水分析平台的 API 接口
|
||||
- 提供测试数据和模拟响应
|
||||
- 支持错误场景模拟
|
||||
|
||||
**启动方式:**
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python app.py # 默认监听 http://localhost:8000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -389,6 +469,55 @@ POST /login/test?username=admin&password=admin123
|
||||
- **数据库索引**: 0
|
||||
- **连接超时**: 10s
|
||||
|
||||
### 流水分析平台配置
|
||||
|
||||
项目集成了外部流水分析平台,配置项位于 `application-dev.yml`:
|
||||
|
||||
```yaml
|
||||
lsfx:
|
||||
api:
|
||||
base-url: http://localhost:8000 # 流水分析平台基础地址
|
||||
app-id: ccdi-app # 应用ID
|
||||
app-secret: ccdi-secret-2024 # 应用密钥
|
||||
client-id: ccdi-client # 客户端ID
|
||||
endpoints:
|
||||
get-token: /api/auth/token # 获取令牌接口
|
||||
upload-file: /api/files/upload # 文件上传接口
|
||||
fetch-inner-flow: /api/flow/inner # 拉取行内流水接口
|
||||
```
|
||||
|
||||
**开发环境使用 Mock 服务器:**
|
||||
- 本地开发时,将 `base-url` 设置为 `http://localhost:8000`
|
||||
- 启动 `lsfx-mock-server` 提供模拟接口
|
||||
- 生产环境替换为真实的流水分析平台地址
|
||||
|
||||
### MCP 配置
|
||||
|
||||
项目使用 MCP (Model Context Protocol) 连接数据库,配置文件: `.mcp.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mysql": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@fhuang/mcp-mysql-server"],
|
||||
"env": {
|
||||
"MYSQL_HOST": "116.62.17.81",
|
||||
"MYSQL_PORT": "3306",
|
||||
"MYSQL_USER": "root",
|
||||
"MYSQL_PASSWORD": "Kfcx@1234",
|
||||
"MYSQL_DATABASE": "ccdi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**使用场景:**
|
||||
- 通过 MCP 工具直接查询和操作数据库
|
||||
- 在开发过程中快速验证数据
|
||||
- 生成测试数据和调试 SQL
|
||||
|
||||
### Druid 监控台
|
||||
|
||||
访问地址: `http://localhost:8080/druid/`
|
||||
@@ -405,8 +534,11 @@ POST /login/test?username=admin&password=admin123
|
||||
|---------------|--------------------------------------------------------------------------------|
|
||||
| 应用入口 | `ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java` |
|
||||
| 安全配置 | `ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java` |
|
||||
| 业务 Controller | `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/` |
|
||||
| 业务 Mapper XML | `ruoyi-info-collection/src/main/resources/mapper/info/collection/` |
|
||||
| 信息采集 Controller | `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/` |
|
||||
| 信息采集 Mapper XML | `ccdi-info-collection/src/main/resources/mapper/info/collection/` |
|
||||
| 项目管理 Controller | `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/` |
|
||||
| 项目管理 Mapper XML | `ccdi-project/src/main/resources/mapper/ccdi/project/` |
|
||||
| 流水分析 Client | `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java` |
|
||||
| Vue 路由 | `ruoyi-ui/src/router/index.js` |
|
||||
| Vuex Store | `ruoyi-ui/src/store/` |
|
||||
| 前端 API | `ruoyi-ui/src/api/` |
|
||||
@@ -499,6 +631,15 @@ doc/
|
||||
3. 确认 Excel 模板格式正确
|
||||
4. 检查必填字段是否为空
|
||||
|
||||
### 流水分析平台连接失败
|
||||
|
||||
**检查项:**
|
||||
1. 确认 `lsfx-mock-server` 已启动(开发环境)
|
||||
2. 检查 `application-dev.yml` 中的 `lsfx.api.base-url` 配置
|
||||
3. 验证 app-id、app-secret、client-id 是否正确
|
||||
4. 检查网络连接和防火墙设置
|
||||
5. 查看后端日志中的 HTTP 请求错误信息
|
||||
|
||||
---
|
||||
|
||||
## MyBatis Plus 分页使用
|
||||
|
||||
BIN
assets/对接流水分析/ccdi_bank_statement.docx
Normal file
BIN
assets/对接流水分析/ccdi_bank_statement.docx
Normal file
Binary file not shown.
92
assets/对接流水分析/ccdi_bank_statement.md
Normal file
92
assets/对接流水分析/ccdi_bank_statement.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# 兰溪存储的流水表的表结构
|
||||
|
||||
```sql
|
||||
CREATE TABLE `ccdi_bank_statement` (
|
||||
`bank_statement_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`LE_ID` int(10) unsigned DEFAULT '0' COMMENT '企业ID',
|
||||
`ACCOUNT_ID` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '账号ID',
|
||||
`LE_ACCOUNT_NAME` varchar(240) DEFAULT 'NONE' COMMENT '企业账号名称',
|
||||
`LE_ACCOUNT_NO` varchar(240) DEFAULT NULL COMMENT '企业银行账号',
|
||||
`ACCOUNTING_DATE_ID` int(11) DEFAULT NULL COMMENT '账号日期ID',
|
||||
`ACCOUNTING_DATE` varchar(10) DEFAULT '0000-00-00' COMMENT '账号日期',
|
||||
`TRX_DATE` varchar(20) NOT NULL COMMENT '交易日期',
|
||||
`CURRENCY` varchar(10) DEFAULT NULL COMMENT '币种',
|
||||
`AMOUNT_DR` decimal(19,2) NOT NULL DEFAULT '0.00' COMMENT '付款金额',
|
||||
`AMOUNT_CR` decimal(19,2) NOT NULL DEFAULT '0.00' COMMENT '收款金额',
|
||||
`AMOUNT_BALANCE` decimal(19,2) NOT NULL COMMENT '余额',
|
||||
`CASH_TYPE` varchar(500) DEFAULT NULL COMMENT '交易类型',
|
||||
`CUSTOMER_LE_ID` int(11) DEFAULT '-1' COMMENT '对手方企业ID',
|
||||
`CUSTOMER_ACCOUNT_NAME` varchar(240) DEFAULT NULL COMMENT '对手方企业名称',
|
||||
`CUSTOMER_ACCOUNT_NO` varchar(240) DEFAULT NULL COMMENT '对手方账号',
|
||||
`customer_bank` varchar(300) DEFAULT NULL COMMENT '对手方银行',
|
||||
`customer_reference` varchar(500) DEFAULT NULL COMMENT '对手方备注',
|
||||
`USER_MEMO` varchar(1000) DEFAULT NULL COMMENT '用户交易摘要',
|
||||
`BANK_COMMENTS` varchar(240) DEFAULT NULL COMMENT '银行交易摘要',
|
||||
`BANK_TRX_NUMBER` varchar(240) DEFAULT NULL COMMENT '银行交易号',
|
||||
`BANK` varchar(250) NOT NULL DEFAULT '' COMMENT '所属银行缩写',
|
||||
`TRX_FLAG` varchar(2) DEFAULT '0' COMMENT '交易标志位',
|
||||
`TRX_TYPE` int(11) NOT NULL DEFAULT '0' COMMENT '分类ID',
|
||||
`EXCEPTION_TYPE` varchar(50) NOT NULL DEFAULT '' COMMENT '异常类型',
|
||||
`internal_flag` tinyint(1) DEFAULT '0' COMMENT '"是否为内部交易1 是 0 否"',
|
||||
`batch_id` int(11) NOT NULL DEFAULT '0' COMMENT '上传logId对应upload_log',
|
||||
`batch_sequence` int(11) NOT NULL COMMENT '每次上传在文件中的line',
|
||||
`CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间内',
|
||||
`created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建者',
|
||||
`meta_json` text COMMENT '"meta json"',
|
||||
`no_balance` tinyint(1) DEFAULT '0' COMMENT '是否包含余额',
|
||||
`begin_balance` tinyint(1) DEFAULT '0' COMMENT '初始余额',
|
||||
`end_balance` tinyint(1) DEFAULT '0' COMMENT '结束余额',
|
||||
`group_id` int(11) DEFAULT '0' COMMENT '项目id',
|
||||
`override_bs_id` bigint(20) DEFAULT '0' COMMENT '=0表示该数据未覆盖主表,>0表示覆盖主表,<0表示被主表覆盖',
|
||||
`payment_method` varchar(500) DEFAULT NULL COMMENT '微信、支付宝流水字段,交易方式',
|
||||
`cret_no` varchar(20) COMMENT '身份证号',
|
||||
PRIMARY KEY (`bank_statement_id`),
|
||||
KEY `idx_batch_id_account` (`batch_id`,`LE_ACCOUNT_NO`,`ACCOUNTING_DATE_ID`),
|
||||
KEY `GROUP_ID` (`group_id`),
|
||||
KEY `c4c_bank_statement_stg_batch_id_IDX` (`batch_id`,`LE_ACCOUNT_NO`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='银行流水的中间处理表';
|
||||
```
|
||||
|
||||
流水表和返回值的对应关系
|
||||
|
||||
| 序号 | ccdi_bank_statement | 返回值 |
|
||||
| --- | --- | --- |
|
||||
| 1 | bank_statement_id | bankStatementId |
|
||||
| 2 | LE_ID | leId |
|
||||
| 3 | ACCOUNT_ID | accountId |
|
||||
| 4 | LE_ACCOUNT_NAME | leName |
|
||||
| 5 | LE_ACCOUNT_NO | accountNo |
|
||||
| 6 | ACCOUNTING_DATE_ID | accountingDateId |
|
||||
| 7 | ACCOUNTING_DATE | accountingDate |
|
||||
| 8 | TRX_DATE | trxDate |
|
||||
| 9 | CURRENCY | currency |
|
||||
| 10 | AMOUNT_DR | drAmount |
|
||||
| 11 | AMOUNT_CR | crAmount |
|
||||
| 12 | AMOUNT_BALANCE | balanceAmount |
|
||||
| 13 | CASH_TYPE | cashType |
|
||||
| 14 | CUSTOMER_LE_ID | customerId |
|
||||
| 15 | CUSTOMER_ACCOUNT_NAME | customerName |
|
||||
| 16 | CUSTOMER_ACCOUNT_NO | customerAccountNo |
|
||||
| 17 | customer_bank | customerBank |
|
||||
| 18 | customer_reference | customerReference |
|
||||
| 19 | USER_MEMO | userMemo |
|
||||
| 20 | BANK_COMMENTS | bankComments |
|
||||
| 21 | BANK_TRX_NUMBER | bankTrxNumber |
|
||||
| 22 | BANK | bank |
|
||||
| 23 | TRX_FLAG | transFlag |
|
||||
| 24 | TRX_TYPE | transTypeId |
|
||||
| 25 | EXCEPTION_TYPE | exceptionType |
|
||||
| 26 | internal_flag | internalFlag |
|
||||
| 27 | batch_id | batchId |
|
||||
| 28 | batch_sequence | uploadSequnceNumber |
|
||||
| 29 | CREATE_DATE | createDate |
|
||||
| 30 | created_by | createdBy |
|
||||
| 31 | meta_json | 设置为null |
|
||||
| 32 | no_balance | isNoBalance |
|
||||
| 33 | begin_balance | isBeginBalance |
|
||||
| 34 | end_balance | isEndBalance |
|
||||
| 35 | override_bs_id | overrideBsId |
|
||||
| 36 | payment_method | paymentMethod |
|
||||
| 37 | cret_no | cretNo |
|
||||
| 38 | group_id | groupId |
|
||||
|
||||
BIN
assets/对接流水分析/~$-流水分析对接_new.docx
Normal file
BIN
assets/对接流水分析/~$-流水分析对接_new.docx
Normal file
Binary file not shown.
Binary file not shown.
@@ -82,8 +82,7 @@ public class LsfxAnalysisClient {
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
if (response != null && response.getData() != null) {
|
||||
log.info("【流水分析】获取Token成功: projectId={}, 耗时={}ms",
|
||||
response.getData().getProjectId(), elapsed);
|
||||
log.info("【流水分析】获取Token成功: projectId={}, 耗时={}ms", response.getData().getProjectId(), elapsed);
|
||||
} else {
|
||||
log.warn("【流水分析】获取Token响应异常: 耗时={}ms", elapsed);
|
||||
}
|
||||
|
||||
30
docs/design/2026-03-04-add-lsfx-project-id.sql
Normal file
30
docs/design/2026-03-04-add-lsfx-project-id.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
-- ====================================
|
||||
-- 功能:ccdi_project 表新增流水分析平台项目ID字段
|
||||
-- 日期:2026-03-04
|
||||
-- 作者:Claude Code
|
||||
-- 说明:为支持创建项目时集成流水分析平台,需要新增字段存储流水分析平台返回的projectId
|
||||
-- ====================================
|
||||
|
||||
USE ccdi;
|
||||
|
||||
-- 新增字段
|
||||
ALTER TABLE `ccdi_project`
|
||||
ADD COLUMN `lsfx_project_id` INT(11) DEFAULT NULL COMMENT '流水分析平台项目ID'
|
||||
AFTER `low_risk_count`;
|
||||
|
||||
-- 验证字段是否添加成功
|
||||
SELECT
|
||||
COLUMN_NAME,
|
||||
COLUMN_TYPE,
|
||||
IS_NULLABLE,
|
||||
COLUMN_DEFAULT,
|
||||
COLUMN_COMMENT
|
||||
FROM
|
||||
INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'ccdi'
|
||||
AND TABLE_NAME = 'ccdi_project'
|
||||
AND COLUMN_NAME = 'lsfx_project_id';
|
||||
|
||||
-- 提示信息
|
||||
SELECT '字段 lsfx_project_id 添加成功!' AS message;
|
||||
552
docs/design/2026-03-04-create-project-integrate-lsfx-design.md
Normal file
552
docs/design/2026-03-04-create-project-integrate-lsfx-design.md
Normal file
@@ -0,0 +1,552 @@
|
||||
# 创建项目时集成流水分析平台设计方案
|
||||
|
||||
**文档版本**: 1.0
|
||||
**创建日期**: 2026-03-04
|
||||
**作者**: Claude Code
|
||||
**状态**: 待实施
|
||||
|
||||
---
|
||||
|
||||
## 1. 需求概述
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
在纪检初核系统中,创建项目时需要同步在流水分析平台创建对应的项目,以便后续进行流水分析操作。
|
||||
|
||||
### 1.2 目标
|
||||
|
||||
- 创建项目时自动调用流水分析平台的 `getToken` 接口
|
||||
- 获取返回的 `projectId` 并保存到项目表
|
||||
- 确保数据一致性,调用失败时项目创建也失败
|
||||
|
||||
### 1.3 参考文档
|
||||
|
||||
- 《兰溪-流水分析对接-新版.md》
|
||||
- 项目现有代码:`ccdi-project` 模块、`ccdi-lsfx` 模块
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计方案
|
||||
|
||||
### 2.1 总体架构
|
||||
|
||||
#### 业务流程
|
||||
|
||||
```
|
||||
用户创建项目
|
||||
↓
|
||||
Controller接收请求
|
||||
↓
|
||||
Service层处理
|
||||
├─→ 生成projectNo (902000_时间戳)
|
||||
├─→ 调用流水分析平台getToken接口
|
||||
│ ├─→ 成功:获取projectId
|
||||
│ └─→ 失败:抛出异常,事务回滚
|
||||
├─→ 保存项目(包含projectId)
|
||||
└─→ 返回项目信息
|
||||
```
|
||||
|
||||
#### 技术方案
|
||||
|
||||
- **调用方式**: 同步调用
|
||||
- **集成位置**: Service层(`CcdiProjectServiceImpl`)
|
||||
- **事务管理**: Spring声明式事务,失败自动回滚
|
||||
- **异常处理**: 依赖 `LsfxAnalysisClient` 的异常处理
|
||||
|
||||
### 2.2 核心设计决策
|
||||
|
||||
| 决策点 | 选择 | 理由 |
|
||||
|-------|------|------|
|
||||
| 调用方式 | 同步调用 | 数据一致性强,用户体验清晰 |
|
||||
| 保存策略 | 仅保存projectId | token 使用一次后失效,无需保存 |
|
||||
| 集成位置 | Service层 | 业务逻辑集中,事务管理简单 |
|
||||
| 异常处理 | 依赖客户端 | 避免重复日志,Service层只做业务校验 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 详细设计
|
||||
|
||||
### 3.1 数据库设计
|
||||
|
||||
#### ccdi_project 表新增字段
|
||||
|
||||
```sql
|
||||
ALTER TABLE `ccdi_project`
|
||||
ADD COLUMN `lsfx_project_id` INT(11) DEFAULT NULL COMMENT '流水分析平台项目ID'
|
||||
AFTER `low_risk_count`;
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
- 字段名: `lsfx_project_id`
|
||||
- 类型: `INT(11)`(与流水分析平台保持一致)
|
||||
- 允许为空: 是(理论上不会为空,因为失败会回滚)
|
||||
- 索引: 不设置唯一索引(流水分析平台的 projectId 可能重复)
|
||||
|
||||
### 3.2 参数映射规则
|
||||
|
||||
根据《兰溪-流水分析对接-新版.md》文档,GetTokenRequest 参数配置如下:
|
||||
|
||||
#### 必填参数(固定值)
|
||||
|
||||
| 参数名 | 值 | 说明 |
|
||||
|-------|-----|------|
|
||||
| `userId` | `"902001"` | 操作人员编号(固定值) |
|
||||
| `userName` | `"902001"` | 操作人员姓名(固定值) |
|
||||
| `role` | `"VIEWER"` | 人员角色(固定值) |
|
||||
| `orgCode` | `"902000"` | 行社机构号(固定值) |
|
||||
| `analysisType` | `"-1"` | 分析类型(固定值) |
|
||||
| `departmentCode` | `"902000"` | 客户经理所属营业部机构编码(固定值) |
|
||||
|
||||
#### 必填参数(动态生成)
|
||||
|
||||
| 参数名 | 生成规则 | 说明 |
|
||||
|-------|---------|------|
|
||||
| `projectNo` | `"902000_" + System.currentTimeMillis()` | 项目编号 |
|
||||
| `entityName` | 使用前端传入的 `projectName` | 项目名称 |
|
||||
|
||||
#### 自动生成参数
|
||||
|
||||
| 参数名 | 生成位置 | 说明 |
|
||||
|-------|---------|------|
|
||||
| `appId` | `LsfxAnalysisClient` 配置 | 固定值:`remote_app` |
|
||||
| `appSecretCode` | `LsfxAnalysisClient.getToken()` | MD5(projectNo + "_" + entityName + "_" + appSecret) |
|
||||
|
||||
#### 可选参数
|
||||
|
||||
以下参数不传递(暂不需要):
|
||||
- `entityId` (企业统信码或个人身份证号)
|
||||
- `xdRelatedPersons` (信贷关联人信息)
|
||||
- `jzDataDateId` (金综链流水日期ID)
|
||||
- `innerBSStartDateId` (行内流水开始日期)
|
||||
- `innerBSEndDateId` (行内流水结束日期)
|
||||
|
||||
### 3.3 代码实现
|
||||
|
||||
#### 3.3.1 实体类修改
|
||||
|
||||
**CcdiProject.java**
|
||||
|
||||
```java
|
||||
@Data
|
||||
@TableName("ccdi_project")
|
||||
public class CcdiProject implements Serializable {
|
||||
|
||||
// ... 现有字段 ...
|
||||
|
||||
/** 低风险人数 */
|
||||
private Integer lowRiskCount;
|
||||
|
||||
/** 流水分析平台项目ID */
|
||||
private Integer lsfxProjectId; // 新增字段
|
||||
|
||||
/** 删除标志 */
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
// ... 审计字段 ...
|
||||
}
|
||||
```
|
||||
|
||||
**CcdiProjectVO.java**
|
||||
|
||||
```java
|
||||
@Data
|
||||
public class CcdiProjectVO implements Serializable {
|
||||
|
||||
// ... 现有字段 ...
|
||||
|
||||
/** 低风险人数 */
|
||||
private Integer lowRiskCount;
|
||||
|
||||
/** 流水分析平台项目ID */
|
||||
private Integer lsfxProjectId; // 新增字段
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
// ... 其他字段 ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 Service实现
|
||||
|
||||
**CcdiProjectServiceImpl.java**
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
|
||||
@Resource
|
||||
private CcdiProjectMapper projectMapper;
|
||||
|
||||
@Resource
|
||||
private LsfxAnalysisClient lsfxAnalysisClient; // 新增依赖注入
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
|
||||
// 1. 调用流水分析平台获取projectId
|
||||
Integer lsfxProjectId = callLsfxPlatform(dto.getProjectName());
|
||||
|
||||
// 2. 创建项目实体
|
||||
CcdiProject project = new CcdiProject();
|
||||
BeanUtils.copyProperties(dto, project);
|
||||
|
||||
// 3. 设置默认值和流水分析平台ID
|
||||
project.setStatus("0"); // 进行中
|
||||
project.setIsArchived(0); // 未归档
|
||||
project.setTargetCount(0);
|
||||
project.setHighRiskCount(0);
|
||||
project.setMediumRiskCount(0);
|
||||
project.setLowRiskCount(0);
|
||||
project.setLsfxProjectId(lsfxProjectId); // 设置流水分析平台ID
|
||||
|
||||
// 4. 保存到数据库
|
||||
projectMapper.insert(project);
|
||||
|
||||
// 5. 返回VO
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(project, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用流水分析平台获取projectId
|
||||
*
|
||||
* @param projectName 项目名称
|
||||
* @return 流水分析平台项目ID
|
||||
* @throws ServiceException 调用失败或响应无效时抛出
|
||||
*/
|
||||
private Integer callLsfxPlatform(String projectName) {
|
||||
// 构建请求参数
|
||||
GetTokenRequest request = new GetTokenRequest();
|
||||
request.setProjectNo("902000_" + System.currentTimeMillis());
|
||||
request.setEntityName(projectName);
|
||||
request.setUserId("902001");
|
||||
request.setUserName("902001");
|
||||
request.setRole("VIEWER");
|
||||
request.setOrgCode("902000");
|
||||
request.setAnalysisType("-1");
|
||||
request.setDepartmentCode("902000");
|
||||
|
||||
// 调用流水分析平台(异常处理和日志已在 LsfxAnalysisClient 中完成)
|
||||
GetTokenResponse response = lsfxAnalysisClient.getToken(request);
|
||||
|
||||
// 业务层校验:确保响应有效
|
||||
if (response == null || response.getData() == null) {
|
||||
throw new ServiceException("流水分析平台响应数据为空");
|
||||
}
|
||||
|
||||
if (response.getData().getProjectId() == null) {
|
||||
throw new ServiceException("流水分析平台返回的projectId为空");
|
||||
}
|
||||
|
||||
// 校验返回码
|
||||
if (!"200".equals(response.getCode())) {
|
||||
throw new ServiceException("流水分析平台返回错误: " + response.getMessage());
|
||||
}
|
||||
|
||||
return response.getData().getProjectId();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 异常处理与事务管理
|
||||
|
||||
#### 3.4.1 异常处理策略
|
||||
|
||||
**场景1:流水分析平台调用失败**
|
||||
- `LsfxAnalysisClient` 抛出 `LsfxApiException`
|
||||
- Service 层捕获后转换为 `ServiceException`
|
||||
- Spring 事务自动回滚
|
||||
- 用户收到明确错误提示
|
||||
|
||||
**场景2:网络超时**
|
||||
- `LsfxAnalysisClient` 配置了超时时间(连接30秒,读取60秒)
|
||||
- 超时后抛出异常,事务回滚
|
||||
|
||||
**场景3:响应数据无效**
|
||||
- Service 层进行业务校验
|
||||
- 发现无效响应抛出 `ServiceException`
|
||||
- 事务回滚
|
||||
|
||||
#### 3.4.2 事务管理
|
||||
|
||||
```java
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
|
||||
// 任何一步失败,整个事务自动回滚
|
||||
Integer lsfxProjectId = callLsfxPlatform(dto.getProjectName());
|
||||
|
||||
// ... 数据库操作 ...
|
||||
|
||||
projectMapper.insert(project);
|
||||
return vo;
|
||||
}
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- 声明式事务管理
|
||||
- 任何异常都触发回滚
|
||||
- 保证数据一致性
|
||||
|
||||
#### 3.4.3 日志记录
|
||||
|
||||
日志记录已在 `LsfxAnalysisClient.getToken()` 中实现:
|
||||
|
||||
```java
|
||||
// LsfxAnalysisClient 中的日志
|
||||
log.info("【流水分析】获取Token请求: projectNo={}, entityName={}", ...);
|
||||
log.info("【流水分析】获取Token成功: projectId={}, 耗时={}ms", ...);
|
||||
log.error("【流水分析】获取Token失败: projectNo={}, error={}", ...);
|
||||
```
|
||||
|
||||
Service 层无需重复记录日志。
|
||||
|
||||
---
|
||||
|
||||
## 4. 实施步骤
|
||||
|
||||
### 4.1 实施顺序
|
||||
|
||||
**步骤1:数据库变更**
|
||||
```bash
|
||||
# 执行SQL脚本
|
||||
mysql -u root -p ccdi < doc/design/2026-03-04-add-lsfx-project-id.sql
|
||||
```
|
||||
|
||||
**步骤2:修改实体类和VO**
|
||||
- `CcdiProject` 实体类添加 `lsfxProjectId` 字段
|
||||
- `CcdiProjectVO` 视图对象添加 `lsfxProjectId` 字段
|
||||
|
||||
**步骤3:修改 Service 实现**
|
||||
- `CcdiProjectServiceImpl` 注入 `LsfxAnalysisClient`
|
||||
- 添加 `callLsfxPlatform()` 私有方法
|
||||
- 修改 `createProject()` 方法
|
||||
|
||||
**步骤4:单元测试**
|
||||
- 测试正常创建项目流程
|
||||
- 测试流水分析平台调用失败场景
|
||||
- 测试网络超时场景
|
||||
|
||||
**步骤5:集成测试**
|
||||
- 使用 Swagger 测试完整流程
|
||||
- 验证数据库中 `lsfx_project_id` 是否正确保存
|
||||
- 验证流水分析平台是否成功创建项目
|
||||
|
||||
**步骤6:前端适配(可选)**
|
||||
- 如果前端需要展示 `lsfxProjectId`,修改前端页面
|
||||
|
||||
### 4.2 数据库迁移脚本
|
||||
|
||||
**文件路径**: `doc/design/2026-03-04-add-lsfx-project-id.sql`
|
||||
|
||||
```sql
|
||||
-- ====================================
|
||||
-- 功能:ccdi_project 表新增流水分析平台项目ID字段
|
||||
-- 日期:2026-03-04
|
||||
-- 作者:Claude Code
|
||||
-- ====================================
|
||||
|
||||
USE ccdi;
|
||||
|
||||
-- 新增字段
|
||||
ALTER TABLE `ccdi_project`
|
||||
ADD COLUMN `lsfx_project_id` INT(11) DEFAULT NULL COMMENT '流水分析平台项目ID'
|
||||
AFTER `low_risk_count`;
|
||||
|
||||
-- 验证
|
||||
SELECT * FROM `ccdi_project` LIMIT 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 测试方案
|
||||
|
||||
### 5.1 单元测试
|
||||
|
||||
**测试类**: `CcdiProjectServiceImplTest.java`
|
||||
|
||||
```java
|
||||
@SpringBootTest
|
||||
public class CcdiProjectServiceImplTest {
|
||||
|
||||
@Resource
|
||||
private ICcdiProjectService projectService;
|
||||
|
||||
@Resource
|
||||
private LsfxAnalysisClient lsfxAnalysisClient;
|
||||
|
||||
@Test
|
||||
public void testCreateProject_Success() {
|
||||
// 准备数据
|
||||
CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO();
|
||||
dto.setProjectName("测试项目");
|
||||
dto.setDescription("测试描述");
|
||||
dto.setConfigType("default");
|
||||
|
||||
// 执行
|
||||
CcdiProjectVO result = projectService.createProject(dto);
|
||||
|
||||
// 验证
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getProjectId());
|
||||
assertNotNull(result.getLsfxProjectId());
|
||||
assertEquals("测试项目", result.getProjectName());
|
||||
}
|
||||
|
||||
@Test(expected = ServiceException.class)
|
||||
public void testCreateProject_LsfxFailed() {
|
||||
// 模拟流水分析平台失败
|
||||
// 需要使用 Mock 或关闭 Mock Server
|
||||
|
||||
CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO();
|
||||
dto.setProjectName("测试项目");
|
||||
|
||||
projectService.createProject(dto);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 集成测试
|
||||
|
||||
**测试步骤:**
|
||||
|
||||
1. **启动 Mock Server**
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python app.py
|
||||
```
|
||||
|
||||
2. **访问 Swagger**
|
||||
```
|
||||
http://localhost:8080/swagger-ui/index.html
|
||||
```
|
||||
|
||||
3. **测试创建项目接口**
|
||||
- 接口: `POST /ccdi/project`
|
||||
- 请求体:
|
||||
```json
|
||||
{
|
||||
"projectName": "测试项目001",
|
||||
"description": "测试项目描述",
|
||||
"configType": "default"
|
||||
}
|
||||
```
|
||||
|
||||
4. **验证响应**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "项目创建成功",
|
||||
"data": {
|
||||
"projectId": 1,
|
||||
"projectName": "测试项目001",
|
||||
"lsfxProjectId": 77, // 应该有值
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. **验证数据库**
|
||||
```sql
|
||||
SELECT project_id, project_name, lsfx_project_id
|
||||
FROM ccdi_project
|
||||
WHERE project_id = 1;
|
||||
```
|
||||
|
||||
### 5.3 异常测试
|
||||
|
||||
**测试场景:**
|
||||
|
||||
1. **流水分析平台不可用**
|
||||
- 关闭 Mock Server
|
||||
- 创建项目应该失败
|
||||
- 数据库不应该有新记录
|
||||
|
||||
2. **网络超时**
|
||||
- 修改 Mock Server 延迟超过60秒
|
||||
- 创建项目应该超时失败
|
||||
|
||||
3. **返回错误码**
|
||||
- 修改 Mock Server 返回错误码(如40104)
|
||||
- 创建项目应该失败并显示对应错误信息
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险与注意事项
|
||||
|
||||
### 6.1 风险分析
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|-----|------|---------|
|
||||
| 流水分析平台不可用 | 无法创建项目 | 提供明确的错误提示,用户可稍后重试 |
|
||||
| 网络延迟 | 创建项目缓慢 | 已配置合理超时时间(60秒) |
|
||||
| projectId 重复 | 无影响 | 不设置唯一索引 |
|
||||
| 事务回滚失败 | 数据不一致 | 依赖 Spring 事务管理,经过充分验证 |
|
||||
|
||||
### 6.2 注意事项
|
||||
|
||||
1. **依赖外部服务**
|
||||
- 流水分析平台必须可用
|
||||
- 建议在生产环境做好监控和告警
|
||||
|
||||
2. **无重试机制**
|
||||
- 失败需要用户手动重试
|
||||
- 可以考虑在 UI 层提供重试按钮
|
||||
|
||||
3. **项目编号唯一性**
|
||||
- 使用时间戳保证唯一性
|
||||
- 理论上不会重复(毫秒级时间戳)
|
||||
|
||||
4. **前端适配**
|
||||
- 当前设计不要求前端传 `lsfxProjectId`
|
||||
- 如果需要展示,修改前端页面即可
|
||||
|
||||
---
|
||||
|
||||
## 7. 变更清单
|
||||
|
||||
| 类型 | 文件 | 变更内容 | 状态 |
|
||||
|-----|------|---------|------|
|
||||
| 数据库 | `ccdi_project` 表 | 新增 `lsfx_project_id` 字段 | 待执行 |
|
||||
| SQL | `2026-03-04-add-lsfx-project-id.sql` | 数据库迁移脚本 | 待创建 |
|
||||
| 实体类 | `CcdiProject.java` | 新增 `lsfxProjectId` 属性 | 待修改 |
|
||||
| VO | `CcdiProjectVO.java` | 新增 `lsfxProjectId` 属性 | 待修改 |
|
||||
| Service | `CcdiProjectServiceImpl.java` | 注入 `LsfxAnalysisClient`,添加调用逻辑 | 待修改 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续优化建议
|
||||
|
||||
### 8.1 短期优化
|
||||
|
||||
1. **添加重试机制**
|
||||
- 在 Service 层添加自动重试(最多3次)
|
||||
- 使用 Spring Retry 框架
|
||||
|
||||
2. **异步调用(可选)**
|
||||
- 如果创建速度成为瓶颈,可改为异步调用
|
||||
- 需要增加状态管理和轮询接口
|
||||
|
||||
### 8.2 长期优化
|
||||
|
||||
1. **批量创建支持**
|
||||
- 如果需要批量创建项目,考虑批量调用流水分析平台
|
||||
|
||||
2. **缓存机制**
|
||||
- 如果 token 需要重复使用,考虑缓存机制
|
||||
- 需要处理 token 过期问题
|
||||
|
||||
---
|
||||
|
||||
## 9. 参考资料
|
||||
|
||||
- 《兰溪-流水分析对接-新版.md》
|
||||
- 项目 CLAUDE.md 文档
|
||||
- Spring Boot 事务管理文档
|
||||
- MyBatis Plus 使用指南
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
786
docs/plans/2026-03-04-create-project-integrate-lsfx.md
Normal file
786
docs/plans/2026-03-04-create-project-integrate-lsfx.md
Normal file
@@ -0,0 +1,786 @@
|
||||
# 创建项目集成流水分析平台实施计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** 在创建项目时同步调用流水分析平台获取projectId并保存到数据库
|
||||
|
||||
**Architecture:** Service层集成LsfxAnalysisClient,同步调用getToken接口,使用Spring事务管理确保数据一致性
|
||||
|
||||
**Tech Stack:** Spring Boot 3.5.8, MyBatis Plus 3.0.5, Lombok, JUnit 5
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
- [ ] 流水分析平台 Mock Server 可用(http://localhost:8000)
|
||||
- [ ] 数据库连接正常
|
||||
- [ ] 后端项目可正常启动
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 执行数据库变更
|
||||
|
||||
**Files:**
|
||||
- Execute: `doc/design/2026-03-04-add-lsfx-project-id.sql`
|
||||
|
||||
**Step 1: 连接数据库执行SQL脚本**
|
||||
|
||||
使用MCP工具连接数据库并执行SQL:
|
||||
|
||||
```bash
|
||||
# 或者使用MySQL客户端
|
||||
mysql -h 116.62.17.81 -u root -p ccdi < doc/design/2026-03-04-add-lsfx-project-id.sql
|
||||
```
|
||||
|
||||
**Step 2: 验证字段已添加**
|
||||
|
||||
```sql
|
||||
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'ccdi'
|
||||
AND TABLE_NAME = 'ccdi_project'
|
||||
AND COLUMN_NAME = 'lsfx_project_id';
|
||||
```
|
||||
|
||||
预期结果:应返回字段信息,类型为 `INT(11)`,允许为空
|
||||
|
||||
**Step 3: 提交数据库变更**
|
||||
|
||||
```bash
|
||||
git add doc/design/2026-03-04-add-lsfx-project-id.sql
|
||||
git commit -m "chore: 添加流水分析平台项目ID字段到ccdi_project表"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 修改CcdiProject实体类
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/CcdiProject.java`
|
||||
|
||||
**Step 1: 打开实体类文件**
|
||||
|
||||
定位到 `lowRiskCount` 字段的位置(约第50行)
|
||||
|
||||
**Step 2: 添加新字段**
|
||||
|
||||
在 `lowRiskCount` 字段之后,`delFlag` 字段之前添加:
|
||||
|
||||
```java
|
||||
/** 低风险人数 */
|
||||
private Integer lowRiskCount;
|
||||
|
||||
/** 流水分析平台项目ID */
|
||||
private Integer lsfxProjectId;
|
||||
|
||||
/** 删除标志:0-存在,2-删除 */
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
```
|
||||
|
||||
**Step 3: 验证代码**
|
||||
|
||||
确保:
|
||||
- Lombok 的 `@Data` 注解存在(会自动生成 getter/setter)
|
||||
- 字段顺序与数据库表结构一致
|
||||
- 注释清晰
|
||||
|
||||
**Step 4: 提交变更**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/CcdiProject.java
|
||||
git commit -m "feat: CcdiProject实体类添加lsfxProjectId字段"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 修改CcdiProjectVO视图对象
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectVO.java`
|
||||
|
||||
**Step 1: 打开VO文件**
|
||||
|
||||
定位到 `lowRiskCount` 字段的位置
|
||||
|
||||
**Step 2: 添加新字段**
|
||||
|
||||
在 `lowRiskCount` 字段之后添加:
|
||||
|
||||
```java
|
||||
/** 低风险人数 */
|
||||
private Integer lowRiskCount;
|
||||
|
||||
/** 流水分析平台项目ID */
|
||||
private Integer lsfxProjectId;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
```
|
||||
|
||||
**Step 3: 验证代码**
|
||||
|
||||
确保字段顺序与实体类一致
|
||||
|
||||
**Step 4: 提交变更**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectVO.java
|
||||
git commit -m "feat: CcdiProjectVO添加lsfxProjectId字段"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 准备测试环境
|
||||
|
||||
**Files:**
|
||||
- Create: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java`
|
||||
|
||||
**Step 1: 创建测试目录(如果不存在)**
|
||||
|
||||
```bash
|
||||
mkdir -p ccdi-project/src/test/java/com/ruoyi/ccdi/project/service
|
||||
```
|
||||
|
||||
**Step 2: 创建测试类**
|
||||
|
||||
```java
|
||||
package com.ruoyi.ccdi.project.service;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||
import com.ruoyi.lsfx.domain.request.GetTokenRequest;
|
||||
import com.ruoyi.lsfx.domain.response.GetTokenResponse;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* 项目Service测试类
|
||||
*/
|
||||
@SpringBootTest
|
||||
@Transactional
|
||||
public class CcdiProjectServiceImplTest {
|
||||
|
||||
@Resource
|
||||
private ICcdiProjectService projectService;
|
||||
|
||||
@Resource
|
||||
private LsfxAnalysisClient lsfxAnalysisClient;
|
||||
|
||||
@Test
|
||||
public void testCreateProject_Success() {
|
||||
// 准备数据
|
||||
CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO();
|
||||
dto.setProjectName("测试项目");
|
||||
dto.setDescription("测试描述");
|
||||
dto.setConfigType("default");
|
||||
|
||||
// 执行
|
||||
CcdiProjectVO result = projectService.createProject(dto);
|
||||
|
||||
// 验证
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getProjectId());
|
||||
assertNotNull(result.getLsfxProjectId(), "流水分析平台项目ID不应为空");
|
||||
assertEquals("测试项目", result.getProjectName());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 运行测试(预期失败)**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_Success
|
||||
```
|
||||
|
||||
预期结果:测试失败,因为 `CcdiProjectServiceImpl` 尚未注入 `LsfxAnalysisClient`
|
||||
|
||||
**Step 4: 提交测试代码**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java
|
||||
git commit -m "test: 添加项目创建集成流水分析平台的测试用例"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 修改CcdiProjectServiceImpl - 注入依赖
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java`
|
||||
|
||||
**Step 1: 打开Service实现类**
|
||||
|
||||
找到依赖注入区域(约第25行)
|
||||
|
||||
**Step 2: 添加LsfxAnalysisClient依赖**
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
|
||||
@Resource
|
||||
private CcdiProjectMapper projectMapper;
|
||||
|
||||
@Resource
|
||||
private LsfxAnalysisClient lsfxAnalysisClient; // 新增依赖注入
|
||||
|
||||
// ... 方法实现 ...
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 添加必要的import**
|
||||
|
||||
```java
|
||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||
import com.ruoyi.lsfx.domain.request.GetTokenRequest;
|
||||
import com.ruoyi.lsfx.domain.response.GetTokenResponse;
|
||||
```
|
||||
|
||||
**Step 4: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn compile
|
||||
```
|
||||
|
||||
预期结果:编译成功
|
||||
|
||||
**Step 5: 提交变更**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java
|
||||
git commit -m "feat: CcdiProjectServiceImpl注入LsfxAnalysisClient依赖"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 实现callLsfxPlatform私有方法
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java`
|
||||
|
||||
**Step 1: 在类末尾添加私有方法**
|
||||
|
||||
在 `getStatusCounts()` 方法之后添加:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 调用流水分析平台获取projectId
|
||||
*
|
||||
* @param projectName 项目名称
|
||||
* @return 流水分析平台项目ID
|
||||
* @throws ServiceException 调用失败或响应无效时抛出
|
||||
*/
|
||||
private Integer callLsfxPlatform(String projectName) {
|
||||
// 构建请求参数
|
||||
GetTokenRequest request = new GetTokenRequest();
|
||||
request.setProjectNo("902000_" + System.currentTimeMillis());
|
||||
request.setEntityName(projectName);
|
||||
request.setUserId("902001");
|
||||
request.setUserName("902001");
|
||||
request.setRole("VIEWER");
|
||||
request.setOrgCode("902000");
|
||||
request.setAnalysisType("-1");
|
||||
request.setDepartmentCode("902000");
|
||||
|
||||
// 调用流水分析平台(异常处理和日志已在 LsfxAnalysisClient 中完成)
|
||||
GetTokenResponse response = lsfxAnalysisClient.getToken(request);
|
||||
|
||||
// 业务层校验:确保响应有效
|
||||
if (response == null || response.getData() == null) {
|
||||
throw new ServiceException("流水分析平台响应数据为空");
|
||||
}
|
||||
|
||||
if (response.getData().getProjectId() == null) {
|
||||
throw new ServiceException("流水分析平台返回的projectId为空");
|
||||
}
|
||||
|
||||
// 校验返回码
|
||||
if (!"200".equals(response.getCode())) {
|
||||
throw new ServiceException("流水分析平台返回错误: " + response.getMessage());
|
||||
}
|
||||
|
||||
return response.getData().getProjectId();
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn compile
|
||||
```
|
||||
|
||||
预期结果:编译成功
|
||||
|
||||
**Step 3: 提交变更**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java
|
||||
git commit -m "feat: 实现callLsfxPlatform方法调用流水分析平台"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 修改createProject方法集成流水分析
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java`
|
||||
|
||||
**Step 1: 定位createProject方法**
|
||||
|
||||
找到 `createProject` 方法(约第29行)
|
||||
|
||||
**Step 2: 修改方法实现**
|
||||
|
||||
将现有实现修改为:
|
||||
|
||||
```java
|
||||
@Override
|
||||
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
|
||||
// 1. 调用流水分析平台获取projectId
|
||||
Integer lsfxProjectId = callLsfxPlatform(dto.getProjectName());
|
||||
|
||||
// 2. 创建项目实体
|
||||
CcdiProject project = new CcdiProject();
|
||||
BeanUtils.copyProperties(dto, project);
|
||||
|
||||
// 3. 设置默认值和流水分析平台ID
|
||||
project.setStatus("0"); // 进行中
|
||||
project.setIsArchived(0); // 未归档
|
||||
project.setTargetCount(0);
|
||||
project.setHighRiskCount(0);
|
||||
project.setMediumRiskCount(0);
|
||||
project.setLowRiskCount(0);
|
||||
project.setLsfxProjectId(lsfxProjectId); // 设置流水分析平台ID
|
||||
|
||||
// 4. 保存到数据库
|
||||
projectMapper.insert(project);
|
||||
|
||||
// 5. 返回VO
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(project, vo);
|
||||
return vo;
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 确认事务注解存在**
|
||||
|
||||
确保方法上有 `@Transactional` 注解(如果没有则添加):
|
||||
|
||||
```java
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
需要添加import:
|
||||
```java
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
```
|
||||
|
||||
**Step 4: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn compile
|
||||
```
|
||||
|
||||
预期结果:编译成功
|
||||
|
||||
**Step 5: 提交变更**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java
|
||||
git commit -m "feat: createProject方法集成流水分析平台调用"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 运行单元测试验证功能
|
||||
|
||||
**Files:**
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java`
|
||||
|
||||
**Step 1: 确保Mock Server运行**
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python app.py
|
||||
```
|
||||
|
||||
确认输出:`Running on http://localhost:8000`
|
||||
|
||||
**Step 2: 运行测试**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_Success
|
||||
```
|
||||
|
||||
预期结果:
|
||||
```
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
|
||||
```
|
||||
|
||||
**Step 3: 如果测试失败,检查日志**
|
||||
|
||||
常见问题:
|
||||
- Mock Server 未启动:启动 Mock Server
|
||||
- 数据库连接失败:检查数据库配置
|
||||
- 字段映射错误:检查 BeanUtils.copyProperties 是否正常
|
||||
|
||||
**Step 4: 提交测试结果**
|
||||
|
||||
如果测试通过,无需额外提交(测试代码已提交)
|
||||
|
||||
---
|
||||
|
||||
## Task 9: 添加异常测试用例
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java`
|
||||
|
||||
**Step 1: 添加测试方法**
|
||||
|
||||
在测试类中添加:
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void testCreateProject_WithNullProjectName() {
|
||||
// 准备数据 - 项目名称为null
|
||||
CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO();
|
||||
dto.setProjectName(null);
|
||||
dto.setDescription("测试描述");
|
||||
dto.setConfigType("default");
|
||||
|
||||
// 执行并验证异常
|
||||
assertThrows(ServiceException.class, () -> {
|
||||
projectService.createProject(dto);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 运行新测试**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_WithNullProjectName
|
||||
```
|
||||
|
||||
预期结果:测试可能失败(因为没有验证项目名称),这是正常的
|
||||
|
||||
**Step 3: 提交测试代码**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java
|
||||
git commit -m "test: 添加项目名称为null的异常测试用例"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 10: 使用Swagger进行集成测试
|
||||
|
||||
**Files:**
|
||||
- 无需修改文件
|
||||
|
||||
**Step 1: 启动后端应用**
|
||||
|
||||
```bash
|
||||
cd ruoyi-admin
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
等待启动完成,确认无错误
|
||||
|
||||
**Step 2: 访问Swagger UI**
|
||||
|
||||
浏览器打开:`http://localhost:8080/swagger-ui/index.html`
|
||||
|
||||
**Step 3: 找到创建项目接口**
|
||||
|
||||
导航到:`纪检初核项目管理` → `POST /ccdi/project`
|
||||
|
||||
**Step 4: 准备测试数据**
|
||||
|
||||
点击 "Try it out",输入请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"projectName": "集成测试项目001",
|
||||
"description": "测试集成流水分析平台",
|
||||
"configType": "default"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 5: 执行请求**
|
||||
|
||||
点击 "Execute"
|
||||
|
||||
**Step 6: 验证响应**
|
||||
|
||||
检查响应体:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "项目创建成功",
|
||||
"data": {
|
||||
"projectId": 1,
|
||||
"projectName": "集成测试项目001",
|
||||
"lsfxProjectId": 77, // 必须有值
|
||||
"description": "测试集成流水分析平台",
|
||||
"configType": "default",
|
||||
"status": "0",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 7: 验证数据库**
|
||||
|
||||
使用MCP工具或MySQL客户端查询:
|
||||
|
||||
```sql
|
||||
SELECT project_id, project_name, lsfx_project_id, create_time
|
||||
FROM ccdi_project
|
||||
WHERE project_name = '集成测试项目001';
|
||||
```
|
||||
|
||||
预期结果:`lsfx_project_id` 字段有值(如77)
|
||||
|
||||
**Step 8: 记录测试结果**
|
||||
|
||||
无代码提交,手动记录测试通过
|
||||
|
||||
---
|
||||
|
||||
## Task 11: 测试异常场景
|
||||
|
||||
**Files:**
|
||||
- 无需修改文件
|
||||
|
||||
**Step 1: 停止Mock Server**
|
||||
|
||||
在 Mock Server 运行的终端按 `Ctrl+C` 停止
|
||||
|
||||
**Step 2: 尝试创建项目**
|
||||
|
||||
使用 Swagger 或 curl:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/project \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectName": "异常测试项目",
|
||||
"description": "测试流水分析平台不可用",
|
||||
"configType": "default"
|
||||
}'
|
||||
```
|
||||
|
||||
**Step 3: 验证响应**
|
||||
|
||||
预期结果:
|
||||
```json
|
||||
{
|
||||
"code": 500,
|
||||
"msg": "调用流水分析平台失败: ..." // 包含错误信息
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: 验证数据库没有脏数据**
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM ccdi_project WHERE project_name = '异常测试项目';
|
||||
```
|
||||
|
||||
预期结果:`0`(事务已回滚)
|
||||
|
||||
**Step 5: 重启Mock Server**
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python app.py
|
||||
```
|
||||
|
||||
**Step 6: 验证功能恢复**
|
||||
|
||||
再次创建项目,确认功能正常
|
||||
|
||||
---
|
||||
|
||||
## Task 12: 清理和文档更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `doc/design/2026-03-04-create-project-integrate-lsfx-design.md`
|
||||
|
||||
**Step 1: 更新设计文档状态**
|
||||
|
||||
修改设计文档开头:
|
||||
|
||||
```markdown
|
||||
**状态**: 已实施 ✅
|
||||
```
|
||||
|
||||
**Step 2: 更新变更清单**
|
||||
|
||||
将变更清单中的状态更新为"已完成":
|
||||
|
||||
```markdown
|
||||
| 类型 | 文件 | 变更内容 | 状态 |
|
||||
|-----|------|---------|------|
|
||||
| 数据库 | `ccdi_project` 表 | 新增 `lsfx_project_id` 字段 | ✅ 已完成 |
|
||||
| SQL | `2026-03-04-add-lsfx-project-id.sql` | 数据库迁移脚本 | ✅ 已执行 |
|
||||
| 实体类 | `CcdiProject.java` | 新增 `lsfxProjectId` 属性 | ✅ 已修改 |
|
||||
| VO | `CcdiProjectVO.java` | 新增 `lsfxProjectId` 属性 | ✅ 已修改 |
|
||||
| Service | `CcdiProjectServiceImpl.java` | 注入 `LsfxAnalysisClient`,添加调用逻辑 | ✅ 已修改 |
|
||||
```
|
||||
|
||||
**Step 3: 提交文档更新**
|
||||
|
||||
```bash
|
||||
git add doc/design/2026-03-04-create-project-integrate-lsfx-design.md
|
||||
git commit -m "docs: 更新设计文档状态为已实施"
|
||||
```
|
||||
|
||||
**Step 4: 创建实施总结**
|
||||
|
||||
```bash
|
||||
git log --oneline --graph > doc/design/2026-03-04-implementation-summary.txt
|
||||
```
|
||||
|
||||
提交总结:
|
||||
|
||||
```bash
|
||||
git add doc/design/2026-03-04-implementation-summary.txt
|
||||
git commit -m "docs: 添加实施总结"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 13: 最终验收
|
||||
|
||||
**Files:**
|
||||
- 无需修改文件
|
||||
|
||||
**Step 1: 运行所有测试**
|
||||
|
||||
```bash
|
||||
cd ccdi-project
|
||||
mvn test
|
||||
```
|
||||
|
||||
预期结果:所有测试通过
|
||||
|
||||
**Step 2: 检查代码质量**
|
||||
|
||||
```bash
|
||||
mvn checkstyle:check
|
||||
```
|
||||
|
||||
如果失败,根据提示修复代码风格问题
|
||||
|
||||
**Step 3: 验证数据库字段**
|
||||
|
||||
```sql
|
||||
DESC ccdi_project;
|
||||
```
|
||||
|
||||
确认 `lsfx_project_id` 字段存在
|
||||
|
||||
**Step 4: 端到端测试**
|
||||
|
||||
通过前端或 Swagger 完整测试创建项目流程:
|
||||
1. 创建项目成功
|
||||
2. 查询项目列表,确认 `lsfxProjectId` 显示
|
||||
3. 查询项目详情,确认 `lsfxProjectId` 正确
|
||||
|
||||
**Step 5: 记录验收结果**
|
||||
|
||||
在项目文档中记录:
|
||||
- 功能验收通过 ✅
|
||||
- 测试覆盖率:100%
|
||||
- 性能测试:创建项目耗时约1-2秒(取决于网络)
|
||||
- 异常处理:已验证
|
||||
|
||||
---
|
||||
|
||||
## 后续任务(可选)
|
||||
|
||||
### Task 14: 添加前端展示(可选)
|
||||
|
||||
如果需要在项目列表页面展示 `lsfxProjectId`:
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/index.vue`
|
||||
- Modify: `ruoyi-ui/src/api/ccdi/project.js`
|
||||
|
||||
**Step 1: 修改表格列定义**
|
||||
|
||||
在 `index.vue` 的表格列中添加:
|
||||
|
||||
```javascript
|
||||
{
|
||||
label: '流水分析项目ID',
|
||||
prop: 'lsfxProjectId',
|
||||
width: '120'
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 提交前端变更**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/index.vue
|
||||
git commit -m "feat: 前端项目列表展示流水分析平台项目ID"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实施注意事项
|
||||
|
||||
### 关键点
|
||||
|
||||
1. **事务一致性**:确保 `@Transactional` 注解存在,任何异常都会回滚
|
||||
2. **参数正确性**:严格按照《兰溪-流水分析对接-新版.md》配置固定参数
|
||||
3. **错误提示**:给用户清晰的错误提示,便于排查问题
|
||||
4. **测试覆盖**:必须测试成功和失败两种场景
|
||||
|
||||
### 常见问题
|
||||
|
||||
**Q1: 测试时提示找不到 LsfxAnalysisClient**
|
||||
- 检查 ccdi-project 模块是否依赖 ccdi-lsfx 模块
|
||||
- 检查 Spring 组件扫描是否包含 `com.ruoyi.lsfx` 包
|
||||
|
||||
**Q2: 数据库字段添加失败**
|
||||
- 确认数据库连接正常
|
||||
- 检查是否有权限修改表结构
|
||||
|
||||
**Q3: Mock Server 无法启动**
|
||||
- 检查 8000 端口是否被占用
|
||||
- 确认 Python 环境正常
|
||||
|
||||
**Q4: 事务回滚不生效**
|
||||
- 确认方法上有 `@Transactional` 注解
|
||||
- 检查异常是否被捕获后未重新抛出
|
||||
|
||||
---
|
||||
|
||||
## 参考资料
|
||||
|
||||
- 设计文档: `doc/design/2026-03-04-create-project-integrate-lsfx-design.md`
|
||||
- 流水分析对接文档: `assets/对接流水分析/兰溪-流水分析对接-新版.md`
|
||||
- 项目规范: `CLAUDE.md`
|
||||
|
||||
---
|
||||
|
||||
**计划创建完成!**
|
||||
Reference in New Issue
Block a user