RuoYi-Vue-Plus文件管理:上传下载删除功能

RuoYi-Vue-Plus文件管理:上传下载删除功能

【免费下载链接】RuoYi-Vue-Plus 多租户后台管理系统 重写RuoYi-Vue所有功能 集成 Sa-Token、Mybatis-Plus、Warm-Flow工作流、SpringDoc、Hutool、OSS 定期同步 【免费下载链接】RuoYi-Vue-Plus 项目地址: https://gitcode.com/dromara/RuoYi-Vue-Plus

概述

在现代企业级应用开发中,文件管理是一个不可或缺的核心功能。RuoYi-Vue-Plus作为一款功能强大的多租户后台管理系统,提供了完整的文件上传、下载和删除解决方案。本文将深入解析RuoYi-Vue-Plus的文件管理架构、核心实现原理以及最佳实践。

架构设计

RuoYi-Vue-Plus采用基于S3协议的统一文件存储架构,支持多种云存储服务商:

mermaid

核心组件

组件名称功能描述所在模块
OssClient文件操作核心类ruoyi-common-oss
UploadResult上传结果封装类ruoyi-common-oss
OssFactory客户端工厂类ruoyi-common-oss
OssProperties配置属性类ruoyi-common-oss

文件上传功能

上传接口实现

RuoYi-Vue-Plus提供了多种上传方式,满足不同场景需求:

// 文件路径上传
public UploadResult upload(Path filePath, String key, String md5Digest, String contentType) {
    // 实现逻辑
    FileUpload fileUpload = transferManager.uploadFile(
        x -> x.putObjectRequest(
                y -> y.bucket(properties.getBucketName())
                    .key(key)
                    .contentMD5(md5Digest)
                    .contentType(contentType)
                    .build())
            .addTransferListener(LoggingTransferListener.create())
            .source(filePath).build());
    
    CompletedFileUpload uploadResult = fileUpload.completionFuture().join();
    return UploadResult.builder()
        .url(getUrl() + "/" + key)
        .filename(key)
        .eTag(uploadResult.response().eTag())
        .build();
}

// 流式上传
public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {
    BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
        .contentLength(length)
        .subscribeTimeout(Duration.ofSeconds(30))
        .build();
    
    // 上传逻辑
    Upload upload = transferManager.upload(
        x -> x.requestBody(body)
            .putObjectRequest(
                y -> y.bucket(properties.getBucketName())
                    .key(key)
                    .contentType(contentType)
                    .build())
            .build());
    
    body.writeInputStream(inputStream);
    CompletedUpload uploadResult = upload.completionFuture().join();
    return UploadResult.builder()
        .url(getUrl() + "/" + key)
        .filename(key)
        .eTag(uploadResult.response().eTag())
        .build();
}

文件路径生成策略

系统采用智能的文件路径生成算法,确保文件命名的唯一性和可管理性:

public String getPath(String prefix, String suffix) {
    String uuid = IdUtil.fastSimpleUUID();        // 生成UUID
    String datePath = DateUtils.datePath();       // 生成日期路径
    String path = StringUtils.isNotEmpty(prefix) ?
        prefix + "/" + datePath + "/" + uuid : datePath + "/" + uuid;
    return path + suffix;                         // 添加文件后缀
}

这种路径策略的优势:

  • 唯一性:UUID确保文件不会重名
  • 组织性:按日期分目录,便于管理
  • 扩展性:支持自定义前缀,适应多租户场景

文件下载功能

下载到本地临时文件

public Path fileDownload(String path) {
    Path tempFilePath = FileUtils.createTempFile().toPath();
    FileDownload downloadFile = transferManager.downloadFile(
        x -> x.getObjectRequest(
                y -> y.bucket(properties.getBucketName())
                    .key(removeBaseUrl(path))     // 移除基础URL
                    .build())
            .addTransferListener(LoggingTransferListener.create())
            .destination(tempFilePath)
            .build());
    
    downloadFile.completionFuture().join();
    return tempFilePath;
}

流式下载到输出流

public void download(String key, OutputStream out, Consumer<Long> consumer) {
    DownloadRequest<ResponseInputStream<GetObjectResponse>> downloadRequest = 
        DownloadRequest.builder()
            .getObjectRequest(y -> y.bucket(properties.getBucketName())
                .key(key)
                .build())
            .addTransferListener(LoggingTransferListener.create())
            .responseTransformer(AsyncResponseTransformer.toBlockingInputStream())
            .build();
    
    Download<ResponseInputStream<GetObjectResponse>> responseFuture = 
        transferManager.download(downloadRequest);
    
    try (ResponseInputStream<GetObjectResponse> responseStream = 
         responseFuture.completionFuture().join().result()) {
        if (consumer != null) {
            consumer.accept(responseStream.response().contentLength());
        }
        responseStream.transferTo(out);
    }
}

文件删除功能

安全删除实现

public void delete(String path) {
    try {
        client.deleteObject(
            x -> x.bucket(properties.getBucketName())
                .key(removeBaseUrl(path))         // 确保删除正确的文件
                .build());
    } catch (Exception e) {
        throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]");
    }
}

配置管理

多存储商支持配置

RuoYi-Vue-Plus支持多种云存储服务商的配置:

# 阿里云OSS配置
oss:
  ali:
    access-key: your-access-key
    secret-key: your-secret-key
    endpoint: oss-cn-hangzhou.aliyuncs.com
    bucket-name: your-bucket
    region: oss-cn-hangzhou

# 腾讯云COS配置  
oss:
  tencent:
    access-key: your-access-key
    secret-key: your-secret-key
    endpoint: cos.ap-shanghai.myqcloud.com
    bucket-name: your-bucket
    region: ap-shanghai

# MinIO配置
oss:
  minio:
    access-key: minioadmin
    secret-key: minioadmin
    endpoint: localhost:9000
    bucket-name: ruoyi
    region: us-east-1

异常处理机制

系统提供了完善的异常处理机制:

public class OssException extends RuntimeException {
    public OssException(String message) {
        super(message);
    }
    
    public OssException(String message, Throwable cause) {
        super(message, cause);
    }
}

常见的异常场景处理:

异常类型处理方式重试策略
网络超时抛出OssException支持配置重试次数
认证失败抛出OssException立即失败,需要检查配置
存储空间不足抛出OssException需要扩容存储空间
文件不存在抛出OssException检查文件路径是否正确

性能优化策略

1. 连接池优化

S3AsyncClient.builder()
    .credentialsProvider(credentialsProvider)
    .endpointOverride(URI.create(getEndpoint()))
    .region(of())
    .forcePathStyle(isStyle)
    .httpClient(NettyNioAsyncHttpClient.builder()
        .connectionTimeout(Duration.ofSeconds(60)).build())
    .build();

2. 传输监听器

.addTransferListener(LoggingTransferListener.create())

3. 超时配置

.subscribeTimeout(Duration.ofSeconds(30))

安全考虑

1. 访问权限控制

public AccessPolicyType getAccessPolicy() {
    return AccessPolicyType.getByType(properties.getAccessPolicy());
}

支持多种访问策略:

  • 私有访问:仅授权用户可访问
  • 公共读:所有人可读,仅授权用户可写
  • 公共读写:所有人可读写

2. 临时访问链接

public String getPrivateUrl(String objectKey, Duration expiredTime) {
    URL url = presigner.presignGetObject(
            x -> x.signatureDuration(expiredTime)
                .getObjectRequest(
                    y -> y.bucket(properties.getBucketName())
                        .key(objectKey)
                        .build())
                .build())
        .url();
    return url.toString();
}

最佳实践

1. 大文件分片上传

对于大文件,建议采用分片上传策略:

mermaid

2. 文件校验机制

// MD5校验
public UploadResult upload(Path filePath, String key, String md5Digest, String contentType) {
    // 使用MD5进行文件完整性校验
    .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
}

// ETag验证
public void validateFileIntegrity(String localMd5, String remoteETag) {
    if (!localMd5.equals(remoteETag)) {
        throw new OssException("文件完整性校验失败");
    }
}

3. 监控和日志

// 添加传输监听器用于监控
.addTransferListener(LoggingTransferListener.create())

常见问题解决方案

1. 跨域访问问题

配置CORS规则,允许前端直接访问OSS资源:

<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>

2. 网络超时处理

.httpClient(NettyNioAsyncHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(60)).build())

3. 存储空间管理

定期清理过期文件,设置生命周期规则:

-- 示例:删除30天前的临时文件
DELETE FROM file_metadata WHERE created_time < DATE_SUB(NOW(), INTERVAL 30 DAY);

总结

RuoYi-Vue-Plus的文件管理模块提供了企业级的完整解决方案,具有以下特点:

  1. 多存储商支持:一套代码适配多种云存储服务
  2. 高性能设计:基于异步IO和连接池优化
  3. 安全可靠:完善的权限控制和校验机制
  4. 易于扩展:模块化设计,支持自定义存储策略
  5. 监控完备:完整的日志和性能监控

通过本文的详细解析,开发者可以深入了解RuoYi-Vue-Plus文件管理的实现原理,并能够根据实际业务需求进行定制化开发。无论是简单的文件上传下载,还是复杂的大文件分片处理,RuoYi-Vue-Plus都能提供稳定可靠的解决方案。

【免费下载链接】RuoYi-Vue-Plus 多租户后台管理系统 重写RuoYi-Vue所有功能 集成 Sa-Token、Mybatis-Plus、Warm-Flow工作流、SpringDoc、Hutool、OSS 定期同步 【免费下载链接】RuoYi-Vue-Plus 项目地址: https://gitcode.com/dromara/RuoYi-Vue-Plus

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值