文字转语音
This commit is contained in:
531
src/main/java/com/rj/utils/MinIOUtil.java
Normal file
531
src/main/java/com/rj/utils/MinIOUtil.java
Normal file
@@ -0,0 +1,531 @@
|
||||
package com.rj.utils;
|
||||
|
||||
import com.rj.config.MinIOConfig;
|
||||
import io.minio.*;
|
||||
import io.minio.http.Method;
|
||||
import io.minio.messages.Bucket;
|
||||
import io.minio.messages.Item;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* MinIO 工具类
|
||||
* 提供文件上传、下载、删除等常用操作
|
||||
*
|
||||
* @author rj
|
||||
* @date 2025-10-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MinIOUtil {
|
||||
|
||||
@Autowired
|
||||
private MinioClient minioClient;
|
||||
|
||||
@Autowired
|
||||
private MinIOConfig minioConfig;
|
||||
|
||||
/**
|
||||
* 检查存储桶是否存在
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
public boolean bucketExists(String bucketName) {
|
||||
try {
|
||||
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||
} catch (Exception e) {
|
||||
log.error("检查存储桶是否存在失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建存储桶
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
public boolean createBucket(String bucketName) {
|
||||
try {
|
||||
if (!bucketExists(bucketName)) {
|
||||
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
||||
log.info("存储桶创建成功: {}", bucketName);
|
||||
return true;
|
||||
}
|
||||
log.info("存储桶已存在: {}", bucketName);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("创建存储桶失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有存储桶
|
||||
*
|
||||
* @return 存储桶列表
|
||||
*/
|
||||
public List<String> getAllBuckets() {
|
||||
try {
|
||||
List<Bucket> buckets = minioClient.listBuckets();
|
||||
List<String> bucketNames = new ArrayList<>();
|
||||
for (Bucket bucket : buckets) {
|
||||
bucketNames.add(bucket.name());
|
||||
}
|
||||
return bucketNames;
|
||||
} catch (Exception e) {
|
||||
log.error("获取存储桶列表失败: {}", e.getMessage());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除存储桶
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
public boolean removeBucket(String bucketName) {
|
||||
try {
|
||||
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
|
||||
log.info("存储桶删除成功: {}", bucketName);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("删除存储桶失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param file 文件
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 文件名
|
||||
*/
|
||||
public String uploadFile(MultipartFile file, String bucketName) {
|
||||
return uploadFile(file, bucketName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param file 文件
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称(文件名),如果为null则自动生成
|
||||
* @return 文件名
|
||||
*/
|
||||
public String uploadFile(MultipartFile file, String bucketName, String objectName) {
|
||||
try {
|
||||
// 确保存储桶存在
|
||||
createBucket(bucketName);
|
||||
|
||||
// 生成文件名
|
||||
if (objectName == null || objectName.trim().isEmpty()) {
|
||||
objectName = generateFileName(file.getOriginalFilename());
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.stream(file.getInputStream(), file.getSize(), -1)
|
||||
.contentType(file.getContentType())
|
||||
.build()
|
||||
);
|
||||
|
||||
log.info("文件上传成功: {}/{}", bucketName, objectName);
|
||||
return objectName;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("文件上传失败: {}", e.getMessage());
|
||||
throw new RuntimeException("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件流
|
||||
*
|
||||
* @param inputStream 文件流
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @param contentType 内容类型
|
||||
* @return 是否上传成功
|
||||
*/
|
||||
public boolean uploadFile(InputStream inputStream, String bucketName, String objectName, String contentType) {
|
||||
try {
|
||||
createBucket(bucketName);
|
||||
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.stream(inputStream, -1, 10485760) // 10MB
|
||||
.contentType(contentType)
|
||||
.build()
|
||||
);
|
||||
|
||||
log.info("文件流上传成功: {}/{}", bucketName, objectName);
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("文件流上传失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传字节数组
|
||||
*
|
||||
* @param data 字节数组
|
||||
* @param objectName 对象名称
|
||||
* @param contentType 内容类型
|
||||
* @return 对象名称
|
||||
*/
|
||||
public String uploadFile(byte[] data, String objectName, String contentType) {
|
||||
try {
|
||||
// 使用配置中的默认存储桶
|
||||
String bucketName = minioConfig.getBucketName();
|
||||
|
||||
// 确保存储桶存在
|
||||
createBucket(bucketName);
|
||||
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.stream(new java.io.ByteArrayInputStream(data), data.length, -1)
|
||||
.contentType(contentType)
|
||||
.build()
|
||||
);
|
||||
|
||||
log.info("字节数组上传成功: {}/{}, 大小: {} bytes", bucketName, objectName, data.length);
|
||||
return objectName;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("字节数组上传失败: {}", e.getMessage());
|
||||
throw new RuntimeException("字节数组上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @return 文件流
|
||||
*/
|
||||
public InputStream downloadFile(String bucketName, String objectName) {
|
||||
try {
|
||||
return minioClient.getObject(
|
||||
GetObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("文件下载失败: {}", e.getMessage());
|
||||
throw new RuntimeException("文件下载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件到本地
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @param fileName 本地文件路径
|
||||
* @return 是否下载成功
|
||||
*/
|
||||
public boolean downloadFile(String bucketName, String objectName, String fileName) {
|
||||
try {
|
||||
minioClient.downloadObject(
|
||||
DownloadObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.filename(fileName)
|
||||
.build()
|
||||
);
|
||||
log.info("文件下载成功: {}/{} -> {}", bucketName, objectName, fileName);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("文件下载失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
public boolean removeFile(String bucketName, String objectName) {
|
||||
try {
|
||||
minioClient.removeObject(
|
||||
RemoveObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build()
|
||||
);
|
||||
log.info("文件删除成功: {}/{}", bucketName, objectName);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("文件删除失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @return 文件信息
|
||||
*/
|
||||
public StatObjectResponse getFileInfo(String bucketName, String objectName) {
|
||||
try {
|
||||
return minioClient.statObject(
|
||||
StatObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("获取文件信息失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件列表
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 文件列表
|
||||
*/
|
||||
public List<String> listFiles(String bucketName) {
|
||||
return listFiles(bucketName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件列表
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param prefix 文件前缀
|
||||
* @return 文件列表
|
||||
*/
|
||||
public List<String> listFiles(String bucketName, String prefix) {
|
||||
List<String> files = new ArrayList<>();
|
||||
try {
|
||||
Iterable<Result<Item>> results = minioClient.listObjects(
|
||||
ListObjectsArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.prefix(prefix)
|
||||
.build()
|
||||
);
|
||||
|
||||
for (Result<Item> result : results) {
|
||||
Item item = result.get();
|
||||
files.add(item.objectName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取文件列表失败: {}", e.getMessage());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件详细列表
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @return 文件详细信息列表
|
||||
*/
|
||||
public List<FileInfo> listFileDetails(String bucketName) {
|
||||
return listFileDetails(bucketName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件详细列表
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param prefix 文件前缀
|
||||
* @return 文件详细信息列表
|
||||
*/
|
||||
public List<FileInfo> listFileDetails(String bucketName, String prefix) {
|
||||
List<FileInfo> files = new ArrayList<>();
|
||||
try {
|
||||
Iterable<Result<Item>> results = minioClient.listObjects(
|
||||
ListObjectsArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.prefix(prefix)
|
||||
.build()
|
||||
);
|
||||
|
||||
for (Result<Item> result : results) {
|
||||
Item item = result.get();
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
fileInfo.setObjectName(item.objectName());
|
||||
fileInfo.setSize(item.size());
|
||||
fileInfo.setLastModified(item.lastModified());
|
||||
fileInfo.setEtag(item.etag());
|
||||
files.add(fileInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取文件详细列表失败: {}", e.getMessage());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件预签名URL(用于临时访问)
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @param expires 过期时间(秒)
|
||||
* @return 预签名URL
|
||||
*/
|
||||
public String getPresignedObjectUrl(String bucketName, String objectName, int expires) {
|
||||
try {
|
||||
return minioClient.getPresignedObjectUrl(
|
||||
GetPresignedObjectUrlArgs.builder()
|
||||
.method(Method.GET)
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.expiry(expires, TimeUnit.SECONDS)
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("获取预签名URL失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件预签名URL(默认7天过期)
|
||||
*
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 对象名称
|
||||
* @return 预签名URL
|
||||
*/
|
||||
public String getPresignedObjectUrl(String bucketName, String objectName) {
|
||||
return getPresignedObjectUrl(bucketName, objectName, 7 * 24 * 3600); // 7天
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件
|
||||
*
|
||||
* @param sourceBucketName 源存储桶名称
|
||||
* @param sourceObjectName 源对象名称
|
||||
* @param targetBucketName 目标存储桶名称
|
||||
* @param targetObjectName 目标对象名称
|
||||
* @return 是否复制成功
|
||||
*/
|
||||
public boolean copyFile(String sourceBucketName, String sourceObjectName,
|
||||
String targetBucketName, String targetObjectName) {
|
||||
try {
|
||||
createBucket(targetBucketName);
|
||||
|
||||
minioClient.copyObject(
|
||||
CopyObjectArgs.builder()
|
||||
.bucket(targetBucketName)
|
||||
.object(targetObjectName)
|
||||
.source(CopySource.builder()
|
||||
.bucket(sourceBucketName)
|
||||
.object(sourceObjectName)
|
||||
.build())
|
||||
.build()
|
||||
);
|
||||
|
||||
log.info("文件复制成功: {}/{} -> {}/{}",
|
||||
sourceBucketName, sourceObjectName, targetBucketName, targetObjectName);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("文件复制失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一文件名
|
||||
*
|
||||
* @param originalFilename 原始文件名
|
||||
* @return 唯一文件名
|
||||
*/
|
||||
private String generateFileName(String originalFilename) {
|
||||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||
String extension = "";
|
||||
|
||||
if (originalFilename != null && originalFilename.contains(".")) {
|
||||
extension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
}
|
||||
|
||||
return timestamp + "_" + uuid + extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件信息类
|
||||
*/
|
||||
public static class FileInfo {
|
||||
private String objectName;
|
||||
private Long size;
|
||||
private java.time.ZonedDateTime lastModified;
|
||||
private String etag;
|
||||
|
||||
// Getters and Setters
|
||||
public String getObjectName() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
public void setObjectName(String objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
|
||||
public Long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public java.time.ZonedDateTime getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(java.time.ZonedDateTime lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
public String getEtag() {
|
||||
return etag;
|
||||
}
|
||||
|
||||
public void setEtag(String etag) {
|
||||
this.etag = etag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FileInfo{" +
|
||||
"objectName='" + objectName + '\'' +
|
||||
", size=" + size +
|
||||
", lastModified=" + lastModified +
|
||||
", etag='" + etag + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user