| | |
| | | import io.minio.http.Method; |
| | | import io.minio.messages.DeleteError; |
| | | import io.minio.messages.DeleteObject; |
| | | import jakarta.servlet.ServletOutputStream; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.Getter; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | |
| | | import org.springframework.util.FastByteArrayOutputStream; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import jakarta.servlet.ServletOutputStream; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.InputStream; |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 下载url(强制浏览器下载文件) |
| | | * @param bucketFileName minio文件名称 |
| | | * @param bucketName 存储桶名称 |
| | | * @param (小时),默认24小时 |
| | | * @return 文件下载URL |
| | | */ |
| | | public String getDownloadUrl(String bucketFileName, String bucketName) { |
| | | if (StringUtils.isNotBlank(bucketFileName)) { |
| | | try { |
| | | // 检查文件是否存在 |
| | | minioClient.statObject(StatObjectArgs.builder() |
| | | .bucket(bucketName) |
| | | .object(bucketFileName) |
| | | .build()); |
| | | |
| | | // 设置响应头 |
| | | Map<String, String> reqParams = new HashMap<>(); |
| | | // 提取原始文件名(如果存储时保留了原始名称) |
| | | String originalFileName = extractOriginalFileName(bucketFileName); |
| | | reqParams.put("response-content-disposition", |
| | | "attachment; filename=\"" + URLEncoder.encode(originalFileName, StandardCharsets.UTF_8) + "\""); |
| | | |
| | | // 构建预签名URL参数 |
| | | GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucketName) |
| | | .object(bucketFileName) |
| | | .expiry(previewExpiry, TimeUnit.HOURS) |
| | | .extraQueryParams(reqParams) |
| | | .build(); |
| | | |
| | | return minioClient.getPresignedObjectUrl(args); |
| | | } catch (Exception e) { |
| | | throw new UtilException("MinioUtils:生成下载链接异常", e); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 从bucketFileName中提取原始文件名 |
| | | * 需根据实际存储规则调整(例如,如果存储时添加了时间戳或UUID后缀) |
| | | */ |
| | | private String extractOriginalFileName(String bucketFileName) { |
| | | // 示例:如果存储格式为 "原始文件名_UUID" |
| | | int underscoreIndex = bucketFileName.lastIndexOf("_"); |
| | | if (underscoreIndex > 0) { |
| | | return bucketFileName.substring(0, underscoreIndex); |
| | | } |
| | | // 如果没有特殊格式,直接返回完整文件名 |
| | | return bucketFileName; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 生成预览URL |
| | | * @param bucketFilename 文件在MinIO中的唯一标识 |
| | | * @param bucketName 存储桶名称 |
| | | * @param useDefaultExpiry 是否使用默认过期时间(true=使用默认过期时间,false=永久有效) |
| | | * @return 预览URL |
| | | */ |
| | | public String getPreviewUrls(String bucketFilename, String bucketName, boolean useDefaultExpiry) { |
| | | if (StringUtils.isBlank(bucketFilename)) { |
| | | return null; |
| | | } |
| | | |
| | | try { |
| | | // 验证文件存在性 |
| | | minioClient.statObject(StatObjectArgs.builder() |
| | | .bucket(bucketName) |
| | | .object(bucketFilename) |
| | | .build()); |
| | | |
| | | GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucketName) |
| | | .object(bucketFilename); |
| | | |
| | | // 设置过期时间:useDefaultExpiry=true 使用配置的过期时间 |
| | | if (useDefaultExpiry) { |
| | | builder.expiry(previewExpiry, TimeUnit.HOURS); |
| | | } |
| | | |
| | | return minioClient.getPresignedObjectUrl(builder.build()); |
| | | } catch (Exception e) { |
| | | throw new UtilException("生成预览URL失败: " + e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 生成下载URL(强制浏览器下载) |
| | | * @param bucketFilename 文件在MinIO中的唯一标识 |
| | | * @param bucketName 存储桶名称 |
| | | * @param originalFileName 原始文件名(用于下载时显示) |
| | | * @param useDefaultExpiry 是否使用默认过期时间(true=使用默认,false=无过期时间) |
| | | * @return 下载URL |
| | | */ |
| | | public String getDownloadUrls(String bucketFilename, String bucketName, String originalFileName, boolean useDefaultExpiry) { |
| | | if (StringUtils.isBlank(bucketFilename)) { |
| | | return null; |
| | | } |
| | | |
| | | try { |
| | | // 验证文件存在性 |
| | | minioClient.statObject(StatObjectArgs.builder() |
| | | .bucket(bucketName) |
| | | .object(bucketFilename) |
| | | .build()); |
| | | |
| | | // 正确编码文件名:替换 + 为 %20 |
| | | String encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8) |
| | | .replace("+", "%20"); |
| | | |
| | | Map<String, String> reqParams = new HashMap<>(); |
| | | reqParams.put("response-content-disposition", |
| | | "attachment; filename=\"" + encodedFileName + "\""); |
| | | |
| | | GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucketName) |
| | | .object(bucketFilename) |
| | | .extraQueryParams(reqParams); |
| | | |
| | | // 根据参数决定是否设置过期时间 |
| | | if (useDefaultExpiry) { |
| | | // 使用默认过期时间(从配置读取) |
| | | builder.expiry(previewExpiry, TimeUnit.HOURS); |
| | | } else { |
| | | // 不设置过期时间(MinIO 默认7天) |
| | | } |
| | | return minioClient.getPresignedObjectUrl(builder.build()); |
| | | } catch (Exception e) { |
| | | throw new UtilException("生成下载URL失败: " + e.getMessage(), e); |
| | | } |
| | | } |
| | | } |