# upload-module **Repository Path**: cyj000/upload-module ## Basic Information - **Project Name**: upload-module - **Description**: 分片上传模块 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-02 - **Last Updated**: 2026-04-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 分片上传模块(Chunk Upload Module) 基于 `rules/upload-module.mdc` 约定整理的分片上传通用代码,支持 **秒传**、**断点续传**、**分片上传与合并**。 可直接复制到新的 Spring Boot 项目中使用。 --- ## 一、功能特性 | 功能 | 说明 | |------|------| | **秒传** | 通过 `identifier + fileName` 判断服务端是否已有完整文件,有则直接返回 URL。 | | **断点续传** | 未传完时返回已上传的分片序号 `uploadedChunks`,前端只传缺失分片。 | | **分片上传** | 按块上传,每块单独请求;全部传完后调用 **合并接口** 生成最终文件。 | | **双端支持** | APP 使用 `MultipartFile`(`type=1`),PC/小程序使用 `byte[]`(`type=2`)。 | | **安全检测** | 合并后可对 PDF 等文件做异步安全检测(示例已集成 PDF 恶意脚本检测)。 | --- ## 二、目录结构 ``` upload-module/ ├── README.md ├── sql/ │ └── a_file_manage.sql -- 建表脚本 └── src/main/java/com/ireql/upload/ ├── controller/ │ └── UploadController.java -- 4 个核心接口(校验/APP上传/PC上传/合并) ├── dto/ │ └── FileDto.java -- 分片上传入参 ├── vo/ │ └── FileVo.java -- 秒传/校验出参 ├── entity/ │ └── FileManage.java -- 实体(对应 a_file_manage) ├── service/ │ ├── IFileManageService.java │ └── impl/ │ └── FileManageServiceImpl.java ├── mapper/ │ ├── FileManageMapper.java │ └── xml/ │ └── FileManageMapper.xml ├── response/ │ └── UploadResponse.java -- 合并后返回体 └── utils/ ├── UploadResult.java -- 简易通用返回封装(可替换为你项目的 Result) ├── MimeTypeUtils.java -- 文件类型白名单 ├── FileUploadUtils.java -- 上传工具(精简版) ├── CheckFileTypeUtil.java -- 文件后缀白名单校验 └── FileAuthUtil.java -- PDF 安全检测工具 ``` --- ## 三、快速集成步骤 ### 3.1 复制代码 将 `upload-module/src/main/java/com/ireql/upload` 整体复制到你项目的源码目录下(例如 `src/main/java/com/xxx/upload`),并将包名批量替换为你项目的包名。 将 `upload-module/src/main/resources/mapper/FileManageMapper.xml` 复制到你项目的 `resources/mapper/` 下。 ### 3.2 建表 执行 `sql/a_file_manage.sql` 创建 `a_file_manage` 表。 ### 3.3 添加必要依赖 确保 `pom.xml` 中已包含以下依赖(版本号根据你项目调整): ```xml com.baomidou mybatis-plus-boot-starter 3.5.x cn.hutool hutool-all 5.8.x org.apache.pdfbox pdfbox 2.0.x ``` ### 3.4 配置 application.yml ```yaml upload: # 对外访问的基础地址(例如你的域名或 IP) baseUrl: http://127.0.0.1:8080 # 合并后文件的本地存放目录 path: D:/upload # 临时分片文件的本地存放基目录 baseDir: D:/upload # 资源前缀(决定对外 URL 中的前缀路径) resourcePrefix: /profile # uploadPath 减去 profile 的长度,用于裁剪生成相对路径 # 例如 uploadPath=D:/upload,profileLen=8("D:/upload".length()) profileLen: 8 ``` ### 3.5 MapperScan 在启动类或 MybatisPlusConfig 中增加 Mapper 扫描: ```java @MapperScan({"com.xxx.upload.mapper", "..."}) ``` ### 3.6 安全/登录适配 - `UploadController` 中不再继承 `BaseController`,原 `getSysUser()` 获取登录用户的逻辑已注释掉。 - 请在你的项目中自行接入登录校验(如 Spring Security / JWT / Session),并将 `userId`、`nickName` 设置到 `FileDto` 中。 - 若使用 Spring Security,建议将 `/common/upload/**` 加入白名单或按你的认证规则放行。 ### 3.7 替换统一返回对象(可选) 本模块使用 `UploadResult` 作为简易返回封装。如果你的项目已有统一的 `AjaxResult` / `Result`,可将代码中的 `UploadResult` 批量替换为你项目的返回类。 --- ## 四、接口说明 > 前缀:`/common/upload` | 接口 | 方法 | 入参 | 出参 | 职责 | |------|------|------|------|------| | 秒传校验 | `GET /verifyUrl` | `identifier`、`fileName` | `FileVo` | 判断是否已存在完整文件 | | APP 分片上传 | `POST /uploadUrlByPhone` | `FileDto`(含 `MultipartFile file`) | `UploadResult` | `type=1` | | PC 分片上传 | `POST /uploadUrlByPc` | `byte[] fileBin` + `fileName, index, chunkSize, totalChunks, identifier, totalSize` | `UploadResult` | `type=2` | | 合并分块 | `GET /mergeUrl` | `identifier`、`fileName` | `UploadResult`(含最终 `url`) | 按序合并并清理临时分片 | ### 4.1 秒传校验返回示例 ```json { "code": 200, "msg": "操作成功", "data": { "url": "http://127.0.0.1:8080/profile/upload/2024-01/xxx.png", "needUpload": false, "uploadedChunks": [] } } ``` - `needUpload=false`:文件已存在,直接取 `url`。 - `needUpload=true`:需要继续上传,`uploadedChunks` 为已上传的分片序号列表。 ### 4.2 合并返回示例 ```json { "code": 200, "msg": "操作成功", "data": { "fileName": "xxx.png", "oriName": "xxx.png", "url": "http://127.0.0.1:8080/profile/upload/2024-01/xxx.png" }, "url": "http://127.0.0.1:8080/profile/upload/2024-01/xxx.png" } ``` --- ## 五、核心约定(与 mdc 保持一致) 1. **唯一键**:`identifier + fileName` 唯一标识一个上传任务,对应一条父记录(`pid IS NULL`)。 2. **父子记录**: - 父记录:存文件总信息,`pid = null`。 - 子记录:每个分片一条,`pid = 父id`,`fileIndex` 为分片序号,`path` 为临时分片本地路径。 3. **临时分片路径**:`{baseDir}/temp_file/{identifier}.{suffix}.{index}` 4. **合并后路径**:`{uploadPath}/{yyyy-MM}/{identifier}.{suffix}` 5. **合并时机**:仅当「已上传分片数 == totalChunks」时才执行物理合并。 6. **文件名支持 Base64**:接口内会先 `convertBase64(fileName)` 解码后再参与查库与类型校验。 --- ## 六、注意事项 - `FileManageServiceImpl` 中的 `@Transactional` 保证了**写分片文件 + 写子记录**、以及**合并文件 + 更新父记录 + 删子记录**的原子性。 - PDF 安全检测目前是同步执行的;若文件较大或并发高,建议改为 `CompletableFuture.runAsync()` 异步执行,避免阻塞合并接口响应。 - 若不需要 PDF 检测,可直接移除 `FileAuthUtil` 及 `FileManageServiceImpl` 中的相关调用。 - 文件类型白名单在 `MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION` 中定义,可按业务需求扩展。 --- ## 七、前端调用流程 1. **第一步**:调用 `GET /common/upload/verifyUrl` 做秒传/断点校验。 2. **第二步**: - 若 `needUpload=false`,直接取 `url` 使用。 - 若 `needUpload=true`,根据 `uploadedChunks` 过滤出未上传的分片。 3. **第三步**:循环调用 `POST /common/upload/uploadUrlByPhone`(APP)或 `/uploadUrlByPc`(PC)上传缺失分片。 4. **第四步**:全部传完后调用 `GET /common/upload/mergeUrl` 合并,获取最终文件 URL。