Files
ccdi/doc/plans/2026-03-05-async-file-upload-part1-database.md

13 KiB
Raw Blame History

项目异步文件上传功能 - 子计划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:

-- 项目文件上传记录表
-- 用途:记录项目下所有文件的上传记录和处理状态
-- 作者:系统
-- 日期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脚本

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

Step 3: 验证表创建成功

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

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

Step 4: 提交SQL脚本

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:

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: 编译验证

cd ccdi-project
mvn clean compile

Expected: BUILD SUCCESS

Step 3: 提交

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:

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 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: 编译验证

cd ccdi-project
mvn clean compile

Expected: BUILD SUCCESS

Step 4: 提交

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:

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:

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: 编译验证

cd ccdi-project
mvn clean compile

Expected: BUILD SUCCESS

Step 4: 提交

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:

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: 编译验证

cd ccdi-project
mvn clean compile

Expected: BUILD SUCCESS

Step 3: 提交

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层核心实现