package com.rj.utils; import com.rj.service.MinIOService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * MinIO 临时访问URL生成工具类 * 提供各种场景下的临时URL生成方法 * * @author rj * @date 2025-10-02 */ @Slf4j @Component public class MinIOUrlGenerator { @Autowired private MinIOService minioService; /** * 生成临时访问URL(1小时有效) * * @param fileName 文件名 * @return 临时访问URL信息 */ public UrlInfo generateTempUrl(String fileName) { return generateTempUrl(fileName, 3600); // 1小时 } /** * 生成临时访问URL(指定过期时间) * * @param fileName 文件名 * @param expiresInSeconds 过期时间(秒) * @return 临时访问URL信息 */ public UrlInfo generateTempUrl(String fileName, int expiresInSeconds) { try { String presignedUrl = minioService.getPresignedUrl(fileName, expiresInSeconds); if (presignedUrl != null) { UrlInfo urlInfo = new UrlInfo(); urlInfo.setFileName(fileName); urlInfo.setUrl(presignedUrl); urlInfo.setExpiresInSeconds(expiresInSeconds); urlInfo.setGeneratedAt(LocalDateTime.now()); urlInfo.setExpiresAt(LocalDateTime.now().plusSeconds(expiresInSeconds)); urlInfo.setSuccess(true); log.info("生成临时访问URL成功: 文件={}, 有效期={}秒,链接是= {}", fileName, expiresInSeconds,presignedUrl); return urlInfo; } else { return createErrorUrlInfo(fileName, "生成预签名URL失败"); } } catch (Exception e) { log.error("生成临时访问URL失败: 文件={}, 错误={}", fileName, e.getMessage()); return createErrorUrlInfo(fileName, "生成临时访问URL异常: " + e.getMessage()); } } /** * 生成临时访问URL(指定存储桶) * * @param bucketName 存储桶名称 * @param fileName 文件名 * @param expiresInSeconds 过期时间(秒) * @return 临时访问URL信息 */ public UrlInfo generateTempUrl(String bucketName, String fileName, int expiresInSeconds) { try { // 检查文件是否存在 if (!minioService.fileExists(bucketName, fileName)) { return createErrorUrlInfo(fileName, "文件不存在"); } String presignedUrl = minioService.getPresignedUrl(fileName, expiresInSeconds); if (presignedUrl != null) { UrlInfo urlInfo = new UrlInfo(); urlInfo.setBucketName(bucketName); urlInfo.setFileName(fileName); urlInfo.setUrl(presignedUrl); urlInfo.setExpiresInSeconds(expiresInSeconds); urlInfo.setGeneratedAt(LocalDateTime.now()); urlInfo.setExpiresAt(LocalDateTime.now().plusSeconds(expiresInSeconds)); urlInfo.setSuccess(true); log.info("生成临时访问URL成功: 存储桶={}, 文件={}, 有效期={}秒", bucketName, fileName, expiresInSeconds); return urlInfo; } else { return createErrorUrlInfo(fileName, "生成预签名URL失败"); } } catch (Exception e) { log.error("生成临时访问URL失败: 存储桶={}, 文件={}, 错误={}", bucketName, fileName, e.getMessage()); return createErrorUrlInfo(fileName, "生成临时访问URL异常: " + e.getMessage()); } } /** * 批量生成临时访问URL * * @param fileNames 文件名列表 * @param expiresInSeconds 过期时间(秒) * @return 临时访问URL信息列表 */ public Map generateBatchTempUrls(String[] fileNames, int expiresInSeconds) { Map results = new HashMap<>(); for (String fileName : fileNames) { UrlInfo urlInfo = generateTempUrl(fileName, expiresInSeconds); results.put(fileName, urlInfo); } log.info("批量生成临时访问URL完成: 文件数量={}, 有效期={}秒", fileNames.length, expiresInSeconds); return results; } /** * 生成短期临时URL(15分钟有效) * 适用于临时预览 * * @param fileName 文件名 * @return 临时访问URL信息 */ public UrlInfo generateShortTermUrl(String fileName) { return generateTempUrl(fileName, 900); // 15分钟 } /** * 生成中期临时URL(4小时有效) * 适用于文件分享 * * @param fileName 文件名 * @return 临时访问URL信息 */ public UrlInfo generateMediumTermUrl(String fileName) { return generateTempUrl(fileName, 14400); // 4小时 } /** * 生成长期临时URL(24小时有效) * 适用于下载链接 * * @param fileName 文件名 * @return 临时访问URL信息 */ public UrlInfo generateLongTermUrl(String fileName) { return generateTempUrl(fileName, 86400); // 24小时 } /** * 生成最长期临时URL(7天有效) * 适用于长期访问 * * @param fileName 文件名 * @return 临时访问URL信息 */ public UrlInfo generateMaxTermUrl(String fileName) { return generateTempUrl(fileName, 604800); // 7天 } /** * 根据时间单位生成临时URL * * @param fileName 文件名 * @param duration 持续时间 * @param timeUnit 时间单位 * @return 临时访问URL信息 */ public UrlInfo generateTempUrl(String fileName, long duration, TimeUnit timeUnit) { int expiresInSeconds = (int) timeUnit.toSeconds(duration); return generateTempUrl(fileName, expiresInSeconds); } /** * 创建错误的URL信息对象 */ private UrlInfo createErrorUrlInfo(String fileName, String errorMessage) { UrlInfo urlInfo = new UrlInfo(); urlInfo.setFileName(fileName); urlInfo.setSuccess(false); urlInfo.setErrorMessage(errorMessage); urlInfo.setGeneratedAt(LocalDateTime.now()); return urlInfo; } /** * URL信息类 */ public static class UrlInfo { private String bucketName; private String fileName; private String url; private int expiresInSeconds; private LocalDateTime generatedAt; private LocalDateTime expiresAt; private boolean success; private String errorMessage; // Getters and Setters public String getBucketName() { return bucketName; } public void setBucketName(String bucketName) { this.bucketName = bucketName; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getExpiresInSeconds() { return expiresInSeconds; } public void setExpiresInSeconds(int expiresInSeconds) { this.expiresInSeconds = expiresInSeconds; } public LocalDateTime getGeneratedAt() { return generatedAt; } public void setGeneratedAt(LocalDateTime generatedAt) { this.generatedAt = generatedAt; } public LocalDateTime getExpiresAt() { return expiresAt; } public void setExpiresAt(LocalDateTime expiresAt) { this.expiresAt = expiresAt; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } /** * 获取格式化的过期时间字符串 */ public String getFormattedExpiresAt() { if (expiresAt != null) { return expiresAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } return null; } /** * 检查URL是否已过期 */ public boolean isExpired() { return expiresAt != null && LocalDateTime.now().isAfter(expiresAt); } /** * 获取剩余有效时间(秒) */ public long getRemainingSeconds() { if (expiresAt != null) { return java.time.Duration.between(LocalDateTime.now(), expiresAt).getSeconds(); } return 0; } @Override public String toString() { return "UrlInfo{" + "bucketName='" + bucketName + '\'' + ", fileName='" + fileName + '\'' + ", url='" + url + '\'' + ", expiresInSeconds=" + expiresInSeconds + ", generatedAt=" + generatedAt + ", expiresAt=" + expiresAt + ", success=" + success + ", errorMessage='" + errorMessage + '\'' + '}'; } } }