# 项目异步文件上传功能 - 子计划1：数据库和基础组件

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** 创建文件上传功能的数据库表、实体类、Mapper接口和基础配置

**Architecture:** 使用 MyBatis Plus 进行数据持久化，配置容量100的异步线程池

**Tech Stack:** MySQL 8.0, MyBatis Plus 3.5.10, Spring Boot 3.5.8

---

## Task 1: 数据库表创建

**Files:**
- Create: `sql/ccdi_file_upload_record.sql`

**Step 1: 创建SQL脚本文件**

创建文件 `sql/ccdi_file_upload_record.sql`:

```sql
-- 项目文件上传记录表
-- 用途：记录项目下所有文件的上传记录和处理状态
-- 作者：系统
-- 日期：2026-03-05

USE ccdi;

-- 创建文件上传记录表
CREATE TABLE `ccdi_file_upload_record` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `project_id` bigint(20) NOT NULL COMMENT '项目ID',
  `lsfx_project_id` int(11) DEFAULT NULL COMMENT '流水分析平台项目ID',
  `log_id` int(11) DEFAULT NULL COMMENT '流水分析平台返回的logId',
  `file_name` varchar(255) NOT NULL COMMENT '文件名称',
  `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小（字节）',
  `file_status` varchar(20) NOT NULL COMMENT '文件状态：uploading-上传中，parsing-解析中，parsed_success-解析成功，parsed_failed-解析失败',
  `enterprise_names` text COMMENT '主体名称（多个用逗号分隔）',
  `account_nos` text COMMENT '主体账号（多个用逗号分隔）',
  `error_message` text COMMENT '错误信息（解析失败时记录）',
  `upload_time` datetime NOT NULL COMMENT '上传时间',
  `upload_user` varchar(64) NOT NULL COMMENT '上传人',
  PRIMARY KEY (`id`),
  KEY `idx_project_id` (`project_id`),
  KEY `idx_log_id` (`log_id`),
  KEY `idx_file_status` (`file_status`),
  KEY `idx_upload_time` (`upload_time`),
  KEY `idx_project_status` (`project_id`, `file_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目文件上传记录表';
```

**Step 2: 执行SQL脚本**

```bash
mysql -h 116.62.17.81 -u root -pKfcx@1234 ccdi < sql/ccdi_file_upload_record.sql
```

**Step 3: 验证表创建成功**

```bash
mysql -h 116.62.17.81 -u root -pKfcx@1234 ccdi -e "SHOW CREATE TABLE ccdi_file_upload_record\G"
```

Expected: 输出表结构，包含所有字段和索引

**Step 4: 提交SQL脚本**

```bash
git add sql/ccdi_file_upload_record.sql
git commit -m "feat: 添加文件上传记录表SQL脚本"
```

---

## Task 2: 实体类创建

**Files:**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiFileUploadRecord.java`

**Step 1: 创建实体类**

创建文件 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiFileUploadRecord.java`:

```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.util.Date;

/**
 * 文件上传记录实体
 *
 * @author ruoyi
 * @date 2026-03-05
 */
@Data
@TableName("ccdi_file_upload_record")
public class CcdiFileUploadRecord implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 主键ID */
    @TableId(type = IdType.AUTO)
    private Long id;

    /** 项目ID */
    private Long projectId;

    /** 流水分析平台项目ID */
    private Integer lsfxProjectId;

    /** 流水分析平台返回的logId */
    private Integer logId;

    /** 文件名称 */
    private String fileName;

    /** 文件大小（字节） */
    private Long fileSize;

    /** 文件状态：uploading-上传中，parsing-解析中，parsed_success-解析成功，parsed_failed-解析失败 */
    private String fileStatus;

    /** 主体名称（多个用逗号分隔） */
    private String enterpriseNames;

    /** 主体账号（多个用逗号分隔） */
    private String accountNos;

    /** 错误信息（解析失败时记录） */
    private String errorMessage;

    /** 上传时间 */
    private Date uploadTime;

    /** 上传人 */
    private String uploadUser;
}
```

**Step 2: 编译验证**

```bash
cd ccdi-project
mvn clean compile
```

Expected: BUILD SUCCESS

**Step 3: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiFileUploadRecord.java
git commit -m "feat: 添加文件上传记录实体类"
```

---

## Task 3: Mapper 接口和 XML

**Files:**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiFileUploadRecordMapper.java`
- Create: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiFileUploadRecordMapper.xml`

**Step 1: 创建 Mapper 接口**

创建文件 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiFileUploadRecordMapper.java`:

```java
package com.ruoyi.ccdi.project.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 文件上传记录 Mapper 接口
 *
 * @author ruoyi
 * @date 2026-03-05
 */
@Mapper
public interface CcdiFileUploadRecordMapper extends BaseMapper<CcdiFileUploadRecord> {

    /**
     * 批量插入文件上传记录
     *
     * @param records 记录列表
     * @return 插入条数
     */
    int insertBatch(@Param("list") List<CcdiFileUploadRecord> records);

    /**
     * 统计各状态文件数量
     *
     * @param projectId 项目ID
     * @return 统计结果（Map形式，key为状态，value为数量）
     */
    List<java.util.Map<String, Object>> countByStatus(@Param("projectId") Long projectId);
}
```

**Step 2: 创建 Mapper XML**

创建文件 `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiFileUploadRecordMapper.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.CcdiFileUploadRecordMapper">

    <resultMap type="com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord" id="CcdiFileUploadRecordResult">
        <id     property="id"               column="id"                 />
        <result property="projectId"       column="project_id"         />
        <result property="lsfxProjectId"   column="lsfx_project_id"    />
        <result property="logId"           column="log_id"             />
        <result property="fileName"        column="file_name"          />
        <result property="fileSize"        column="file_size"          />
        <result property="fileStatus"      column="file_status"        />
        <result property="enterpriseNames" column="enterprise_names"   />
        <result property="accountNos"      column="account_nos"        />
        <result property="errorMessage"    column="error_message"      />
        <result property="uploadTime"      column="upload_time"        />
        <result property="uploadUser"      column="upload_user"        />
    </resultMap>

    <sql id="selectCcdiFileUploadRecordVo">
        select id, project_id, lsfx_project_id, log_id, file_name, file_size,
               file_status, enterprise_names, account_nos, error_message,
               upload_time, upload_user
        from ccdi_file_upload_record
    </sql>

    <!-- 批量插入 -->
    <insert id="insertBatch" parameterType="java.util.List">
        insert into ccdi_file_upload_record (
            project_id, lsfx_project_id, file_name, file_size, file_status,
            upload_time, upload_user
        ) values
        <foreach collection="list" item="item" separator=",">
            (
                #{item.projectId}, #{item.lsfxProjectId}, #{item.fileName},
                #{item.fileSize}, #{item.fileStatus}, #{item.uploadTime},
                #{item.uploadUser}
            )
        </foreach>
    </insert>

    <!-- 统计各状态文件数量 -->
    <select id="countByStatus" resultType="java.util.Map">
        select file_status as `status`, count(*) as count
        from ccdi_file_upload_record
        where project_id = #{projectId}
        group by file_status
    </select>

</mapper>
```

**Step 3: 编译验证**

```bash
cd ccdi-project
mvn clean compile
```

Expected: BUILD SUCCESS

**Step 4: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiFileUploadRecordMapper.java
git add ccdi-project/src/main/resources/mapper/ccdi/project/CcdiFileUploadRecordMapper.xml
git commit -m "feat: 添加文件上传记录Mapper接口和XML映射"
```

---

## Task 4: DTO 和 VO 类

**Files:**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiFileUploadQueryDTO.java`
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiFileUploadStatisticsVO.java`

**Step 1: 创建查询 DTO**

创建文件 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiFileUploadQueryDTO.java`:

```java
package com.ruoyi.ccdi.project.domain.dto;

import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 文件上传记录查询 DTO
 *
 * @author ruoyi
 * @date 2026-03-05
 */
@Data
public class CcdiFileUploadQueryDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 项目ID */
    private Long projectId;

    /** 文件状态 */
    private String fileStatus;

    /** 文件名称（模糊查询） */
    private String fileName;

    /** 上传人 */
    private String uploadUser;
}
```

**Step 2: 创建统计 VO**

创建文件 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiFileUploadStatisticsVO.java`:

```java
package com.ruoyi.ccdi.project.domain.vo;

import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 文件上传统计 VO
 *
 * @author ruoyi
 * @date 2026-03-05
 */
@Data
public class CcdiFileUploadStatisticsVO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 上传中数量 */
    private Long uploading;

    /** 解析中数量 */
    private Long parsing;

    /** 解析成功数量 */
    private Long parsedSuccess;

    /** 解析失败数量 */
    private Long parsedFailed;

    /** 总数量 */
    private Long total;
}
```

**Step 3: 编译验证**

```bash
cd ccdi-project
mvn clean compile
```

Expected: BUILD SUCCESS

**Step 4: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiFileUploadQueryDTO.java
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiFileUploadStatisticsVO.java
git commit -m "feat: 添加文件上传查询DTO和统计VO"
```

---

## Task 5: 线程池配置

**Files:**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/config/AsyncThreadPoolConfig.java`

**Step 1: 创建线程池配置类**

创建文件 `ccdi-project/src/main/java/com/ruoyi/ccdi/project/config/AsyncThreadPoolConfig.java`:

```java
package com.ruoyi.ccdi.project.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步线程池配置
 *
 * @author ruoyi
 * @date 2026-03-05
 */
@Configuration
@EnableAsync
public class AsyncThreadPoolConfig {

    /**
     * 文件上传专用线程池
     * 容量：100个线程
     * 拒绝策略：AbortPolicy（直接拒绝，由调度线程捕获并重试）
     */
    @Bean("fileUploadExecutor")
    public Executor fileUploadExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(100);
        // 最大线程数
        executor.setMaxPoolSize(100);
        // 队列容量（设为0，不使用队列，直接走拒绝策略）
        executor.setQueueCapacity(0);
        // 线程名称前缀
        executor.setThreadNamePrefix("file-upload-");
        // 拒绝策略：AbortPolicy，抛出 RejectedExecutionException
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        // 线程空闲时间（秒）
        executor.setKeepAliveSeconds(60);
        // 等待所有任务完成后再关闭
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 最长等待时间
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
}
```

**Step 2: 编译验证**

```bash
cd ccdi-project
mvn clean compile
```

Expected: BUILD SUCCESS

**Step 3: 提交**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/config/AsyncThreadPoolConfig.java
git commit -m "feat: 添加异步线程池配置"
```

---

## 子计划1完成检查清单

- [ ] 数据库表创建成功
- [ ] 实体类编译通过
- [ ] Mapper接口和XML映射正确
- [ ] DTO和VO类创建完成
- [ ] 线程池配置完成
- [ ] 所有代码已提交到git

**下一步：** 执行子计划2 - Service层核心实现
