docs: 添加银行流水实体类实施计划
This commit is contained in:
745
docs/plans/2026-03-04-bank-statement-implementation.md
Normal file
745
docs/plans/2026-03-04-bank-statement-implementation.md
Normal file
@@ -0,0 +1,745 @@
|
|||||||
|
# 银行流水实体类实现计划
|
||||||
|
|
||||||
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||||
|
|
||||||
|
**目标:** 创建 CcdiBankStatement 实体类,实现从流水分析接口响应到数据库实体的数据转换功能。
|
||||||
|
|
||||||
|
**架构:** 在 ccdi-project 模块中创建实体类,使用 Spring BeanUtils 进行对象映射,手动处理字段名不一致的情况。实体类包含静态转换方法 fromResponse()。
|
||||||
|
|
||||||
|
**技术栈:** MyBatis Plus 3.5.10, Spring BeanUtils, Lombok, MySQL 8.2.0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 任务概览
|
||||||
|
|
||||||
|
| 任务 | 预估时间 | 文件 |
|
||||||
|
|------|---------|------|
|
||||||
|
| Task 1: 数据库表修改 | 5分钟 | SQL脚本 |
|
||||||
|
| Task 2: 创建实体类基础结构 | 10分钟 | CcdiBankStatement.java |
|
||||||
|
| Task 3: 编写转换方法测试 | 15分钟 | CcdiBankStatementTest.java |
|
||||||
|
| Task 4: 实现转换方法 | 10分钟 | CcdiBankStatement.java |
|
||||||
|
| Task 5: 创建 Mapper 接口 | 5分钟 | CcdiBankStatementMapper.java |
|
||||||
|
| Task 6: 创建 Mapper XML | 10分钟 | CcdiBankStatementMapper.xml |
|
||||||
|
| Task 7: 验证测试 | 5分钟 | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: 数据库表修改
|
||||||
|
|
||||||
|
**目标:** 在 ccdi_bank_statement 表中添加 project_id 字段和索引。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 创建: `sql/ccdi_bank_statement_add_project_id.sql`
|
||||||
|
|
||||||
|
**Step 1: 创建数据库修改脚本**
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 为 ccdi_bank_statement 表添加 project_id 字段
|
||||||
|
ALTER TABLE `ccdi_bank_statement`
|
||||||
|
ADD COLUMN `project_id` bigint(20) DEFAULT NULL COMMENT '关联项目ID' AFTER `bank_statement_id`,
|
||||||
|
ADD INDEX `idx_project_id` (`project_id`);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 执行数据库修改脚本**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 连接到数据库并执行脚本
|
||||||
|
mysql -h 116.62.17.81 -u root -p ccdi < sql/ccdi_bank_statement_add_project_id.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** 执行成功,无错误信息。
|
||||||
|
|
||||||
|
**Step 3: 验证字段已添加**
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 查看表结构,确认 project_id 字段已添加
|
||||||
|
SHOW COLUMNS FROM ccdi_bank_statement LIKE 'project_id';
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:**
|
||||||
|
```
|
||||||
|
Field | Type | Null | Key | Default | Extra
|
||||||
|
-------------|------------|------|-----|---------|-------
|
||||||
|
project_id | bigint(20) | YES | MUL | NULL |
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add sql/ccdi_bank_statement_add_project_id.sql
|
||||||
|
git commit -m "feat: 为银行流水表添加 project_id 字段"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: 创建实体类基础结构
|
||||||
|
|
||||||
|
**目标:** 创建 CcdiBankStatement 实体类的基础结构,包含所有字段定义。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 创建: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java`
|
||||||
|
|
||||||
|
**Step 1: 创建实体类文件**
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.ruoyi.ccdi.project.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行流水对象 ccdi_bank_statement
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("ccdi_bank_statement")
|
||||||
|
public class CcdiBankStatement implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
// ===== 主键和关联字段 =====
|
||||||
|
|
||||||
|
/** 流水ID */
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long bankStatementId;
|
||||||
|
|
||||||
|
/** 关联项目ID(业务字段) */
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
/** 企业ID */
|
||||||
|
private Integer leId;
|
||||||
|
|
||||||
|
/** 账号ID */
|
||||||
|
private Long accountId;
|
||||||
|
|
||||||
|
/** 项目id(保留原有字段) */
|
||||||
|
private Integer groupId;
|
||||||
|
|
||||||
|
// ===== 账号信息 =====
|
||||||
|
|
||||||
|
/** 企业账号名称 */
|
||||||
|
private String leAccountName;
|
||||||
|
|
||||||
|
/** 企业银行账号 */
|
||||||
|
private String leAccountNo;
|
||||||
|
|
||||||
|
/** 账号日期ID */
|
||||||
|
private Integer accountingDateId;
|
||||||
|
|
||||||
|
/** 账号日期 */
|
||||||
|
private String accountingDate;
|
||||||
|
|
||||||
|
/** 交易日期 */
|
||||||
|
private String trxDate;
|
||||||
|
|
||||||
|
/** 币种 */
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
// ===== 交易金额 =====
|
||||||
|
|
||||||
|
/** 付款金额 */
|
||||||
|
private BigDecimal amountDr;
|
||||||
|
|
||||||
|
/** 收款金额 */
|
||||||
|
private BigDecimal amountCr;
|
||||||
|
|
||||||
|
/** 余额 */
|
||||||
|
private BigDecimal amountBalance;
|
||||||
|
|
||||||
|
// ===== 交易类型和标志 =====
|
||||||
|
|
||||||
|
/** 交易类型 */
|
||||||
|
private String cashType;
|
||||||
|
|
||||||
|
/** 交易标志位 */
|
||||||
|
private String trxFlag;
|
||||||
|
|
||||||
|
/** 分类ID */
|
||||||
|
private Integer trxType;
|
||||||
|
|
||||||
|
/** 异常类型 */
|
||||||
|
private String exceptionType;
|
||||||
|
|
||||||
|
/** 是否为内部交易 */
|
||||||
|
private Integer internalFlag;
|
||||||
|
|
||||||
|
// ===== 对手方信息 =====
|
||||||
|
|
||||||
|
/** 对手方企业ID */
|
||||||
|
private Integer customerLeId;
|
||||||
|
|
||||||
|
/** 对手方企业名称 */
|
||||||
|
private String customerAccountName;
|
||||||
|
|
||||||
|
/** 对手方账号 */
|
||||||
|
private String customerAccountNo;
|
||||||
|
|
||||||
|
/** 对手方银行 */
|
||||||
|
private String customerBank;
|
||||||
|
|
||||||
|
/** 对手方备注 */
|
||||||
|
private String customerReference;
|
||||||
|
|
||||||
|
// ===== 摘要和备注 =====
|
||||||
|
|
||||||
|
/** 用户交易摘要 */
|
||||||
|
private String userMemo;
|
||||||
|
|
||||||
|
/** 银行交易摘要 */
|
||||||
|
private String bankComments;
|
||||||
|
|
||||||
|
/** 银行交易号 */
|
||||||
|
private String bankTrxNumber;
|
||||||
|
|
||||||
|
// ===== 银行信息 =====
|
||||||
|
|
||||||
|
/** 所属银行缩写 */
|
||||||
|
private String bank;
|
||||||
|
|
||||||
|
// ===== 批次和上传信息 =====
|
||||||
|
|
||||||
|
/** 上传logId */
|
||||||
|
private Integer batchId;
|
||||||
|
|
||||||
|
/** 每次上传在文件中的line */
|
||||||
|
private Integer batchSequence;
|
||||||
|
|
||||||
|
// ===== 附加字段 =====
|
||||||
|
|
||||||
|
/** meta json(固定为null) */
|
||||||
|
private String metaJson;
|
||||||
|
|
||||||
|
/** 是否包含余额 */
|
||||||
|
private Integer noBalance;
|
||||||
|
|
||||||
|
/** 初始余额 */
|
||||||
|
private Integer beginBalance;
|
||||||
|
|
||||||
|
/** 结束余额 */
|
||||||
|
private Integer endBalance;
|
||||||
|
|
||||||
|
/** 覆盖标识 */
|
||||||
|
private Long overrideBsId;
|
||||||
|
|
||||||
|
/** 交易方式 */
|
||||||
|
private String paymentMethod;
|
||||||
|
|
||||||
|
/** 身份证号 */
|
||||||
|
private String cretNo;
|
||||||
|
|
||||||
|
// ===== 审计字段 =====
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
/** 创建者 */
|
||||||
|
private Long createdBy;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 验证代码编译**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** BUILD SUCCESS
|
||||||
|
|
||||||
|
**Step 3: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java
|
||||||
|
git commit -m "feat: 创建银行流水实体类基础结构"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: 编写转换方法测试
|
||||||
|
|
||||||
|
**目标:** 使用 TDD 方法,先编写 fromResponse() 方法的单元测试。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 创建: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatementTest.java`
|
||||||
|
|
||||||
|
**Step 1: 添加测试依赖(如果不存在)**
|
||||||
|
|
||||||
|
检查 `ccdi-project/pom.xml` 是否包含测试依赖:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果没有,添加上述依赖。
|
||||||
|
|
||||||
|
**Step 2: 创建测试类**
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.ruoyi.ccdi.project.domain.entity;
|
||||||
|
|
||||||
|
import com.ruoyi.lsfx.domain.response.GetBankStatementResponse.BankStatementItem;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行流水实体类测试
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-04
|
||||||
|
*/
|
||||||
|
class CcdiBankStatementTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFromResponse_Success() {
|
||||||
|
// 准备测试数据
|
||||||
|
BankStatementItem item = new BankStatementItem();
|
||||||
|
item.setBankStatementId(123456L);
|
||||||
|
item.setLeId(100);
|
||||||
|
item.setAccountId(200L);
|
||||||
|
item.setLeName("测试企业");
|
||||||
|
item.setAccountMaskNo("6222****1234");
|
||||||
|
item.setDrAmount(new BigDecimal("1000.00"));
|
||||||
|
item.setCrAmount(new BigDecimal("500.00"));
|
||||||
|
item.setBalanceAmount(new BigDecimal("5000.00"));
|
||||||
|
item.setTrxDate("2026-03-04");
|
||||||
|
item.setCustomerAccountMaskNo("6228****5678");
|
||||||
|
item.setUploadSequnceNumber(1);
|
||||||
|
|
||||||
|
// 执行转换
|
||||||
|
CcdiBankStatement entity = CcdiBankStatement.fromResponse(item);
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
assertNotNull(entity, "转换结果不应为null");
|
||||||
|
assertEquals(123456L, entity.getBankStatementId(), "流水ID应该匹配");
|
||||||
|
assertEquals(100, entity.getLeId(), "企业ID应该匹配");
|
||||||
|
assertEquals(200L, entity.getAccountId(), "账号ID应该匹配");
|
||||||
|
assertEquals("测试企业", entity.getLeAccountName(), "企业名称应该匹配");
|
||||||
|
|
||||||
|
// 验证手动映射的字段
|
||||||
|
assertEquals("6222****1234", entity.getLeAccountNo(), "企业账号应该从 accountMaskNo 映射");
|
||||||
|
assertEquals("6228****5678", entity.getCustomerAccountNo(), "对手方账号应该从 customerAccountMaskNo 映射");
|
||||||
|
assertEquals(1, entity.getBatchSequence(), "批次序号应该从 uploadSequnceNumber 映射");
|
||||||
|
|
||||||
|
// 验证金额字段
|
||||||
|
assertEquals(new BigDecimal("1000.00"), entity.getAmountDr(), "付款金额应该匹配");
|
||||||
|
assertEquals(new BigDecimal("500.00"), entity.getAmountCr(), "收款金额应该匹配");
|
||||||
|
assertEquals(new BigDecimal("5000.00"), entity.getAmountBalance(), "余额应该匹配");
|
||||||
|
|
||||||
|
// 验证特殊字段
|
||||||
|
assertNull(entity.getMetaJson(), "metaJson 应该强制为 null");
|
||||||
|
assertNull(entity.getProjectId(), "projectId 应该为 null(需要 Service 层设置)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFromResponse_Null() {
|
||||||
|
// 测试空值处理
|
||||||
|
CcdiBankStatement entity = CcdiBankStatement.fromResponse(null);
|
||||||
|
|
||||||
|
// 验证返回 null
|
||||||
|
assertNull(entity, "传入 null 应该返回 null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFromResponse_EmptyObject() {
|
||||||
|
// 测试空对象转换
|
||||||
|
BankStatementItem item = new BankStatementItem();
|
||||||
|
|
||||||
|
// 执行转换
|
||||||
|
CcdiBankStatement entity = CcdiBankStatement.fromResponse(item);
|
||||||
|
|
||||||
|
// 验证不会抛出异常
|
||||||
|
assertNotNull(entity, "空对象转换结果不应为 null");
|
||||||
|
assertNull(entity.getMetaJson(), "metaJson 应该为 null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFromResponse_FieldTypeCompatibility() {
|
||||||
|
// 测试字段类型兼容性
|
||||||
|
BankStatementItem item = new BankStatementItem();
|
||||||
|
item.setInternalFlag(1); // Integer 类型
|
||||||
|
item.setTransTypeId(100); // Integer 类型
|
||||||
|
|
||||||
|
// 执行转换
|
||||||
|
CcdiBankStatement entity = CcdiBankStatement.fromResponse(item);
|
||||||
|
|
||||||
|
// 验证类型转换正确
|
||||||
|
assertNotNull(entity, "转换结果不应为 null");
|
||||||
|
assertEquals(1, entity.getInternalFlag(), "Integer 类型应该正确复制");
|
||||||
|
assertEquals(100, entity.getTrxType(), "Integer 类型应该正确复制");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: 运行测试验证失败**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn test -Dtest=CcdiBankStatementTest
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** 编译失败,因为 `fromResponse()` 方法还不存在。
|
||||||
|
|
||||||
|
**Step 4: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add ccdi-project/src/test/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatementTest.java
|
||||||
|
git commit -m "test: 添加银行流水转换方法的单元测试"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: 实现转换方法
|
||||||
|
|
||||||
|
**目标:** 在 CcdiBankStatement 实体类中实现 fromResponse() 静态方法。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 修改: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java`
|
||||||
|
|
||||||
|
**Step 1: 添加必要的导入**
|
||||||
|
|
||||||
|
在文件顶部添加:
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.ruoyi.lsfx.domain.response.GetBankStatementResponse.BankStatementItem;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 添加日志常量**
|
||||||
|
|
||||||
|
在类的开头添加:
|
||||||
|
|
||||||
|
```java
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(CcdiBankStatement.class);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: 实现 fromResponse() 方法**
|
||||||
|
|
||||||
|
在类的末尾(createdBy 字段之后)添加转换方法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 从流水分析接口响应转换为实体
|
||||||
|
*
|
||||||
|
* @param item 流水分析接口返回的流水项
|
||||||
|
* @return 流水实体,如果 item 为 null 则返回 null
|
||||||
|
*/
|
||||||
|
public static CcdiBankStatement fromResponse(BankStatementItem item) {
|
||||||
|
// 1. 空值检查
|
||||||
|
if (item == null) {
|
||||||
|
log.warn("流水项为空,无法转换");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2. 创建实体对象
|
||||||
|
CcdiBankStatement entity = new CcdiBankStatement();
|
||||||
|
|
||||||
|
// 3. 使用 BeanUtils 复制同名字段
|
||||||
|
BeanUtils.copyProperties(item, entity);
|
||||||
|
|
||||||
|
// 4. 手动映射字段名不一致的情况
|
||||||
|
entity.setLeAccountNo(item.getAccountMaskNo());
|
||||||
|
entity.setCustomerAccountNo(item.getCustomerAccountMaskNo());
|
||||||
|
entity.setBatchSequence(item.getUploadSequnceNumber());
|
||||||
|
|
||||||
|
// 5. 特殊字段处理
|
||||||
|
entity.setMetaJson(null); // 根据文档要求强制设为 null
|
||||||
|
|
||||||
|
// 注意:project_id 需要在 Service 层根据业务逻辑设置
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("流水数据转换失败, bankStatementId={}", item.getBankStatementId(), e);
|
||||||
|
throw new RuntimeException("流水数据转换失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: 运行测试验证通过**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn test -Dtest=CcdiBankStatementTest
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:**
|
||||||
|
```
|
||||||
|
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
|
||||||
|
[INFO] BUILD SUCCESS
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java
|
||||||
|
git commit -m "feat: 实现银行流水转换方法 fromResponse()"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: 创建 Mapper 接口
|
||||||
|
|
||||||
|
**目标:** 创建 MyBatis Mapper 接口,继承 BaseMapper 并提供批量插入方法。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 创建: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapper.java`
|
||||||
|
|
||||||
|
**Step 1: 创建 Mapper 接口**
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.ruoyi.ccdi.project.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行流水Mapper接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-04
|
||||||
|
*/
|
||||||
|
public interface CcdiBankStatementMapper extends BaseMapper<CcdiBankStatement> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入银行流水
|
||||||
|
*
|
||||||
|
* @param list 银行流水列表
|
||||||
|
* @return 插入记录数
|
||||||
|
*/
|
||||||
|
int insertBatch(@Param("list") List<CcdiBankStatement> list);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 验证代码编译**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** BUILD SUCCESS
|
||||||
|
|
||||||
|
**Step 3: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapper.java
|
||||||
|
git commit -m "feat: 创建银行流水 Mapper 接口"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 6: 创建 Mapper XML
|
||||||
|
|
||||||
|
**目标:** 创建 MyBatis XML 映射文件,实现批量插入 SQL。
|
||||||
|
|
||||||
|
**文件:**
|
||||||
|
- 创建: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml`
|
||||||
|
|
||||||
|
**Step 1: 创建 XML 文件**
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.ccdi.project.mapper.CcdiBankStatementMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement" id="CcdiBankStatementResult">
|
||||||
|
<id property="bankStatementId" column="bank_statement_id" />
|
||||||
|
<result property="projectId" column="project_id" />
|
||||||
|
<result property="leId" column="LE_ID" />
|
||||||
|
<result property="accountId" column="ACCOUNT_ID" />
|
||||||
|
<result property="groupId" column="group_id" />
|
||||||
|
<result property="leAccountName" column="LE_ACCOUNT_NAME" />
|
||||||
|
<result property="leAccountNo" column="LE_ACCOUNT_NO" />
|
||||||
|
<result property="accountingDateId" column="ACCOUNTING_DATE_ID" />
|
||||||
|
<result property="accountingDate" column="ACCOUNTING_DATE" />
|
||||||
|
<result property="trxDate" column="TRX_DATE" />
|
||||||
|
<result property="currency" column="CURRENCY" />
|
||||||
|
<result property="amountDr" column="AMOUNT_DR" />
|
||||||
|
<result property="amountCr" column="AMOUNT_CR" />
|
||||||
|
<result property="amountBalance" column="AMOUNT_BALANCE" />
|
||||||
|
<result property="cashType" column="CASH_TYPE" />
|
||||||
|
<result property="customerLeId" column="CUSTOMER_LE_ID" />
|
||||||
|
<result property="customerAccountName" column="CUSTOMER_ACCOUNT_NAME" />
|
||||||
|
<result property="customerAccountNo" column="CUSTOMER_ACCOUNT_NO" />
|
||||||
|
<result property="customerBank" column="customer_bank" />
|
||||||
|
<result property="customerReference" column="customer_reference" />
|
||||||
|
<result property="userMemo" column="USER_MEMO" />
|
||||||
|
<result property="bankComments" column="BANK_COMMENTS" />
|
||||||
|
<result property="bankTrxNumber" column="BANK_TRX_NUMBER" />
|
||||||
|
<result property="bank" column="BANK" />
|
||||||
|
<result property="trxFlag" column="TRX_FLAG" />
|
||||||
|
<result property="trxType" column="TRX_TYPE" />
|
||||||
|
<result property="exceptionType" column="EXCEPTION_TYPE" />
|
||||||
|
<result property="internalFlag" column="internal_flag" />
|
||||||
|
<result property="batchId" column="batch_id" />
|
||||||
|
<result property="batchSequence" column="batch_sequence" />
|
||||||
|
<result property="createDate" column="CREATE_DATE" />
|
||||||
|
<result property="createdBy" column="created_by" />
|
||||||
|
<result property="metaJson" column="meta_json" />
|
||||||
|
<result property="noBalance" column="no_balance" />
|
||||||
|
<result property="beginBalance" column="begin_balance" />
|
||||||
|
<result property="endBalance" column="end_balance" />
|
||||||
|
<result property="overrideBsId" column="override_bs_id" />
|
||||||
|
<result property="paymentMethod" column="payment_method" />
|
||||||
|
<result property="cretNo" column="cret_no" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectCcdiBankStatementVo">
|
||||||
|
select bank_statement_id, project_id, LE_ID, ACCOUNT_ID, group_id,
|
||||||
|
LE_ACCOUNT_NAME, LE_ACCOUNT_NO, ACCOUNTING_DATE_ID, ACCOUNTING_DATE,
|
||||||
|
TRX_DATE, CURRENCY, AMOUNT_DR, AMOUNT_CR, AMOUNT_BALANCE,
|
||||||
|
CASH_TYPE, CUSTOMER_LE_ID, CUSTOMER_ACCOUNT_NAME, CUSTOMER_ACCOUNT_NO,
|
||||||
|
customer_bank, customer_reference, USER_MEMO, BANK_COMMENTS,
|
||||||
|
BANK_TRX_NUMBER, BANK, TRX_FLAG, TRX_TYPE, EXCEPTION_TYPE,
|
||||||
|
internal_flag, batch_id, batch_sequence, CREATE_DATE, created_by,
|
||||||
|
meta_json, no_balance, begin_balance, end_balance,
|
||||||
|
override_bs_id, payment_method, cret_no
|
||||||
|
from ccdi_bank_statement
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<insert id="insertBatch" parameterType="java.util.List">
|
||||||
|
insert into ccdi_bank_statement (
|
||||||
|
project_id, LE_ID, ACCOUNT_ID, group_id,
|
||||||
|
LE_ACCOUNT_NAME, LE_ACCOUNT_NO, ACCOUNTING_DATE_ID, ACCOUNTING_DATE,
|
||||||
|
TRX_DATE, CURRENCY, AMOUNT_DR, AMOUNT_CR, AMOUNT_BALANCE,
|
||||||
|
CASH_TYPE, CUSTOMER_LE_ID, CUSTOMER_ACCOUNT_NAME, CUSTOMER_ACCOUNT_NO,
|
||||||
|
customer_bank, customer_reference, USER_MEMO, BANK_COMMENTS,
|
||||||
|
BANK_TRX_NUMBER, BANK, TRX_FLAG, TRX_TYPE, EXCEPTION_TYPE,
|
||||||
|
internal_flag, batch_id, batch_sequence, CREATE_DATE, created_by,
|
||||||
|
meta_json, no_balance, begin_balance, end_balance,
|
||||||
|
override_bs_id, payment_method, cret_no
|
||||||
|
) values
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(
|
||||||
|
#{item.projectId}, #{item.leId}, #{item.accountId}, #{item.groupId},
|
||||||
|
#{item.leAccountName}, #{item.leAccountNo}, #{item.accountingDateId}, #{item.accountingDate},
|
||||||
|
#{item.trxDate}, #{item.currency}, #{item.amountDr}, #{item.amountCr}, #{item.amountBalance},
|
||||||
|
#{item.cashType}, #{item.customerLeId}, #{item.customerAccountName}, #{item.customerAccountNo},
|
||||||
|
#{item.customerBank}, #{item.customerReference}, #{item.userMemo}, #{item.bankComments},
|
||||||
|
#{item.bankTrxNumber}, #{item.bank}, #{item.trxFlag}, #{item.trxType}, #{item.exceptionType},
|
||||||
|
#{item.internalFlag}, #{item.batchId}, #{item.batchSequence}, #{item.createDate}, #{item.createdBy},
|
||||||
|
#{item.metaJson}, #{item.noBalance}, #{item.beginBalance}, #{item.endBalance},
|
||||||
|
#{item.overrideBsId}, #{item.paymentMethod}, #{item.cretNo}
|
||||||
|
)
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 验证 XML 语法**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** BUILD SUCCESS,无 XML 解析错误
|
||||||
|
|
||||||
|
**Step 3: 提交**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml
|
||||||
|
git commit -m "feat: 创建银行流水 Mapper XML 映射文件"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 7: 验证测试
|
||||||
|
|
||||||
|
**目标:** 运行所有测试,确保功能正常。
|
||||||
|
|
||||||
|
**Step 1: 运行单元测试**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ccdi-project
|
||||||
|
mvn test
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:**
|
||||||
|
```
|
||||||
|
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
|
||||||
|
[INFO] BUILD SUCCESS
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 运行集成编译**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn clean compile
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期输出:** BUILD SUCCESS
|
||||||
|
|
||||||
|
**Step 3: 检查依赖关系**
|
||||||
|
|
||||||
|
确认 `ccdi-project` 模块的 `pom.xml` 中已依赖 `ccdi-lsfx` 模块:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ruoyi</groupId>
|
||||||
|
<artifactId>ccdi-lsfx</artifactId>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果没有,添加上述依赖并重新编译。
|
||||||
|
|
||||||
|
**Step 4: 提交所有更改**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "test: 完成银行流水实体类功能验证"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 完成检查清单
|
||||||
|
|
||||||
|
- [ ] 数据库已添加 `project_id` 字段和索引
|
||||||
|
- [ ] 实体类包含 39 个字段,类型正确
|
||||||
|
- [ ] `fromResponse()` 方法正确处理 3 个字段名映射
|
||||||
|
- [ ] `fromResponse()` 方法强制设置 `metaJson` 为 null
|
||||||
|
- [ ] 单元测试覆盖正常转换、空值处理、字段映射等场景
|
||||||
|
- [ ] Mapper 接口继承 `BaseMapper`
|
||||||
|
- [ ] Mapper XML 包含批量插入 SQL
|
||||||
|
- [ ] 所有测试通过
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后续工作
|
||||||
|
|
||||||
|
本实施计划完成后,可以进行以下扩展:
|
||||||
|
|
||||||
|
1. **创建 Service 层** - 实现 `IBankStatementService` 接口和实现类
|
||||||
|
2. **创建 Controller 层** - 提供 REST API 接口
|
||||||
|
3. **编写集成测试** - 测试完整的数据库插入流程
|
||||||
|
4. **添加业务逻辑** - 在 Service 层设置 `projectId` 等业务字段
|
||||||
|
5. **性能优化** - 根据实际数据量调整批量插入大小
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**计划版本:** 1.0
|
||||||
|
**创建日期:** 2026-03-04
|
||||||
Reference in New Issue
Block a user