开发环境
- Ruoyi-Vue-Plus 5.1.2(Spring Boot 3.1.7)
- MySQL 8.0.32
- minio
- open JDK 17
common-oss 模块添加相关封装类
entity
ChunkFileInfoBO
package org.dromara.common.oss.chunkfile.entity;import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** 分片文件信息** @since 2024/2/6 10:24*/
@Data
@NoArgsConstructor
public class ChunkFileInfoBO implements Serializable {/*** 文件内容 唯一标识 md5 (文件分片、总文件整体)*/@NotEmpty(message = "文件内容唯一标识 不能为空")private String identifier;/*** 文件名称*/@NotEmpty(message = "文件名称 不能为空")private String filename;/*** 分块大小 根据 totalSize 和这个值可以计算出总共的块数。*/private Long chunkSize;/*** 文件总大小*/private Long totalSize;/*** 总块数*/@NotNull(message = "文件分片总块数 不能为空")private Integer totalChunks;/*** 分块编号 从1开始,注意不是从 0 开始的*/@NotNull(message = "当前文件分片编号 不能为空")private Integer chunkNumber;/*** 当前分块大小*/@NotNull(message = "当前文件分片大小 不能为空")private Long currentChunkSize;/*** 文件前端上传请求唯一标识*/@NotEmpty(message = "文件上传请求唯一标识 不能为空")private String requestId;/*** 文件后端上传请求唯一标识*/private String uploadId;/*** 文件类型后缀*/private String suffix;/*** 文件原始名称*/private String newFilename;/*** 相对路径*/private String relativePath;}
FileMergeBO
package org.dromara.common.oss.chunkfile.entity;import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** 分片合并上传参数** @since 2024/2/6 14:24*/
@Data
@NoArgsConstructor
public class FileMergeBO implements Serializable {/*** 文件名称*/@NotEmpty(message = "文件名称 不能为空")private String filename;/*** 文件内容唯一标识*/@NotEmpty(message = "文件内容唯一标识 不能为空")private String identifier;/*** 文件前端上传请求唯一标识*/@NotEmpty(message = "文件上传请求唯一标识 不能为空")private String requestId;/*** 总块数*/@NotNull(message = "文件分片总块数 不能为空")private Integer totalChunks;}
FileUploadResult
package org.dromara.common.oss.chunkfile.entity;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Set;/*** 分片文件上传返回结果** @since 2024/2/6 10:25*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class FileUploadResult {/*** 是否跳过上传 (已经上传过的,跳过)*/private Boolean skipUpload;/****/private Set<String> uploaded;/*** 是否需要合并*/private Boolean needMerge;/*** 当前文件分片编号*/private Integer currentChunkNum;/*** 文件内容 唯一标识 md5 (文件分片、总文件整体)*/private String identifier;/*** 文件名称*/private String fileName;/*** 文件前端上传请求唯一标识*/private String requestId;/*** sys_oss 主键标识*/private Long ossFileId;/*** 文件上传后的url地址*/private String url;}
SysOssRedisDTO
package org.dromara.common.oss.chunkfile.entity;import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** redis缓存存储对象** @since 2024/2/6 14:08*/
@Data
@NoArgsConstructor
public class SysOssRedisDTO implements Serializable {/*** 文件后端上传请求唯一标识*/private String uploadId;/*** 文件上传后的url地址*/private String url;/*** 文件名称*/private String filePathName;/*** 文件内容 唯一标识 md5 (文件分片、总文件整体)*/private String identifier;/*** 服务商*/private String ossService;
}
enum
FileUploadStatus
package org.dromara.common.oss.chunkfile.enumd;import lombok.AllArgsConstructor;
import lombok.Getter;/*** 文件分片 上传状态枚举** @since 2024/2/6 11:05*/
@Getter
@AllArgsConstructor
public enum FileUploadStatus {/*** 上传中*/UPLOADING("0", "上传进行中"),/*** 上传完成*/UPLOADED("1", "上传完成");/*** 状态码*/private final String code;/*** 状态描述*/private final String desc;}
常量
常量类 OssConstant
中添加文件分片上传缓存常量
/*** 分片文件 块前缀*/String CHUNK_FILE_PART_PREFIX = GlobalConstants.GLOBAL_REDIS_KEY + "chunk_file_part:";/*** 分片文件 信息前缀*/String CHUNK_FILE_INFO_PREFIX = GlobalConstants.GLOBAL_REDIS_KEY + "chunk_file_info:";
OssClient 类改造
改造 OssClient
类,添加文件分片上传合并到oss的相关方法。
package org.dromara.common.oss.core;public class OssClient {
// ------ 扩展方法 ---------public String getPath(String suffix) {return getPath(properties.getPrefix(), suffix);}/*** 获取分片上传的统一id** @param path 完整文件路径*/public String getChunkUploadUnionId(String path, String contentType) {String uploadId = null;try {InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(properties.getBucketName(), path);if (StringUtils.isNotBlank(contentType)) {ObjectMetadata metadata = new ObjectMetadata();metadata.setContentType(contentType);initRequest.setObjectMetadata(metadata);}initRequest.setCannedACL(getAccessPolicy().getAcl());InitiateMultipartUploadResult initResult = client.initiateMultipartUpload(initRequest);uploadId = initResult.getUploadId();} catch (Exception e) {throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");}System.out.println("uploadId-----:" + uploadId);return uploadId;}/*** 分片上传** @param inputStream* @param path 完整文件路径* @param uploadId* @param partSize* @param partNum* @return*/public PartETag chunkUpload(InputStream inputStream, String path,String uploadId, Long partSize, int partNum) {if (!(inputStream instanceof ByteArrayInputStream