13 KiB
项目异步文件上传功能 - 子计划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层核心实现