系统集成 minio
This commit is contained in:
parent
abd50ba966
commit
e37c6c1370
|
|
@ -0,0 +1,44 @@
|
|||
package com.bonus.web.controller.file;
|
||||
|
||||
import com.bonus.common.core.domain.AjaxResult;
|
||||
import com.bonus.common.domain.ocr.dto.OcrRequest;
|
||||
import com.bonus.common.domain.ocr.vo.OcrResponse;
|
||||
import com.bonus.file.service.FileUploadService;
|
||||
import com.bonus.file.util.FileUtil;
|
||||
import com.bonus.ocr.service.OcrService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @className:FileUploadController
|
||||
* @author:cwchen
|
||||
* @date:2025-10-16-15:47
|
||||
* @version:1.0
|
||||
* @description:文件上传
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
public class FileUploadController {
|
||||
|
||||
@Resource(name = "FileUploadService")
|
||||
private FileUploadService fileUploadService;
|
||||
|
||||
@Value("${uploadSuffix.main_database}")
|
||||
private String uploadSuffix;
|
||||
|
||||
@PostMapping(value = "uploadFile")
|
||||
private AjaxResult ocrHandler(MultipartFile file) {
|
||||
// 生成文件路径
|
||||
String uploadPath = FileUtil.generateDatePath(file, uploadSuffix);
|
||||
String s = fileUploadService.uploadFile(file,uploadPath);
|
||||
System.err.println("文件路径" + s);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,4 +4,7 @@ minio:
|
|||
endpoint: http://192.168.0.14:9090
|
||||
access-key: minio
|
||||
secret-key: bonus@admin123
|
||||
bucket-name: smart-bid
|
||||
bucket-name: smart-bid
|
||||
# 文件上传前缀
|
||||
uploadSuffix:
|
||||
main_database: main_database #主体库
|
||||
|
|
@ -181,6 +181,12 @@
|
|||
<version>4.5.14</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>${minio.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.bonus.common.domain.file.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author bonus
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FileDetails {
|
||||
/**
|
||||
* 文件或文件夹的路径
|
||||
*/
|
||||
private String fileName;
|
||||
/**
|
||||
* 相对地址
|
||||
*/
|
||||
private String objectKey;
|
||||
/**
|
||||
* 文件大小,文件夹默认为 0
|
||||
*/
|
||||
private long size;
|
||||
|
||||
/**
|
||||
* 最后修改时间,文件夹也有此属性
|
||||
*/
|
||||
private Date lastModified;
|
||||
|
||||
/**
|
||||
* ETag,文件夹一般没有 ETag
|
||||
*/
|
||||
private String etag;
|
||||
|
||||
/**
|
||||
* 内容类型,文件夹一般没有此信息
|
||||
*/
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 是否是文件夹,默认值为 false
|
||||
*/
|
||||
private boolean isFolder;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.bonus.common.domain.file.vo;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
/**
|
||||
* 文件信息
|
||||
*
|
||||
* @author bonus
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class SysFile
|
||||
{
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 文件地址,除mongodb 存fileid之外,其他均存上传文件的网络路径
|
||||
*/
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("name", getName())
|
||||
.append("url", getUrl())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.bonus.file.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import io.minio.MinioClient;
|
||||
|
||||
/**
|
||||
* @className:MinioConfig
|
||||
* @author:cwchen
|
||||
* @date:2025-10-16-15:04
|
||||
* @version:1.0
|
||||
* @description:Minio配置
|
||||
*/
|
||||
@Configuration
|
||||
@Data
|
||||
public class MinioConfig {
|
||||
|
||||
/**
|
||||
* 服务地址
|
||||
*/
|
||||
@Value("${minio.url}")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 服务地址
|
||||
*/
|
||||
@Value("${minio.endpoint}")
|
||||
private String endpoint;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Value("${minio.access-key}")
|
||||
private String accessKey;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Value("${minio.secret-key}")
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 存储桶名称
|
||||
*/
|
||||
@Value("${minio.bucket-name}")
|
||||
private String bucketName;
|
||||
|
||||
@Bean
|
||||
public MinioClient getMinioClient()
|
||||
{
|
||||
return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package com.bonus.file.service;
|
||||
|
||||
import com.bonus.common.domain.file.vo.SysFile;
|
||||
import com.bonus.file.config.MinioConfig;
|
||||
import com.bonus.file.util.MinioUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @className:FileUploadService
|
||||
* @author:cwchen
|
||||
* @date:2025-10-16-15:31
|
||||
* @version:1.0
|
||||
* @description:文件上传实现类
|
||||
*/
|
||||
@Service(value = "FileUploadService")
|
||||
@Slf4j
|
||||
public class FileUploadService {
|
||||
|
||||
@Resource
|
||||
public MinioUtil minioUtil;
|
||||
|
||||
@Resource
|
||||
private MinioConfig minioConfig;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public String uploadFile(MultipartFile file, String path) {
|
||||
try{
|
||||
minioUtil.uploadFile(minioConfig.getBucketName(), file,path);
|
||||
return minioConfig.getBucketName();
|
||||
}catch (Exception e){
|
||||
log.error(e.toString(),e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param filePath
|
||||
*/
|
||||
public void delFile(String filePath) {
|
||||
try {
|
||||
boolean isExist = minioUtil.isObjectExist(minioConfig.getBucketName(), filePath);
|
||||
if (isExist) {
|
||||
minioUtil.removeFile(minioConfig.getBucketName(), filePath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传大文件
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public SysFile uploadLargeFile(MultipartFile file, String path) {
|
||||
try{
|
||||
return minioUtil.uploadFile(file, path);
|
||||
}catch (Exception e){
|
||||
log.error(e.toString(),e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.bonus.file.util;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @className:FileUtil
|
||||
* @author:cwchen
|
||||
* @date:2025-10-16-15:56
|
||||
* @version:1.0
|
||||
* @description:文件工具类
|
||||
*/
|
||||
public class FileUtil {
|
||||
|
||||
/**
|
||||
* 生成日期目录格式的存储路径
|
||||
*/
|
||||
public static String generateDatePath(MultipartFile file, String baseDir) {
|
||||
// 生成日期目录:年/月/日
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
|
||||
String datePath = sdf.format(new Date());
|
||||
// 生成唯一文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String fileExtension = getFileExtension(originalFilename);
|
||||
String uniqueFileName = UUID.randomUUID().toString() + fileExtension;
|
||||
|
||||
// 构建完整路径
|
||||
return Paths.get(baseDir, datePath, uniqueFileName).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*/
|
||||
private static String getFileExtension(String filename) {
|
||||
if (filename == null || filename.lastIndexOf(".") == -1) {
|
||||
return "";
|
||||
}
|
||||
return filename.substring(filename.lastIndexOf("."));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,501 @@
|
|||
package com.bonus.file.util;
|
||||
|
||||
import com.bonus.common.domain.file.vo.SysFile;
|
||||
import io.minio.*;
|
||||
import com.bonus.file.config.MinioConfig;
|
||||
import io.minio.errors.MinioException;
|
||||
import io.minio.http.Method;
|
||||
import io.minio.messages.Item;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* MinioUtil 工具类
|
||||
* 封装 MinIO 常用操作,如文件上传、下载、删除、复制等功能
|
||||
* @author bonus
|
||||
*/
|
||||
@Component
|
||||
public class MinioUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MinioUtil.class);
|
||||
|
||||
@Resource
|
||||
private MinioClient minioClient;
|
||||
|
||||
@Resource
|
||||
private MinioConfig minioConfig;
|
||||
/**
|
||||
* 分片大小
|
||||
*/
|
||||
private static final long PART_SIZE = 5*1024*1024;
|
||||
/**
|
||||
* 初始化默认存储桶
|
||||
* 在 Spring 容器启动后自动调用,检查默认存储桶是否存在,若不存在则创建
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
if (bucketExists(minioConfig.getBucketName())) {
|
||||
LOGGER.error("桶已存在: {}", minioConfig.getBucketName());
|
||||
} else {
|
||||
createBucket(minioConfig.getBucketName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("创建桶失败: {}",e.getMessage(),e);
|
||||
throw new RuntimeException("创建桶失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定存储桶是否存在
|
||||
* @param bucketName 存储桶名称
|
||||
* @return true 表示存在,false 表示不存在
|
||||
* @throws Exception 若检查过程中发生异常
|
||||
*/
|
||||
public boolean bucketExists(String bucketName) throws Exception {
|
||||
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定的存储桶
|
||||
* @param bucketName 存储桶名称
|
||||
* @throws Exception 若创建过程中发生异常
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public void createBucket(String bucketName) {
|
||||
if (bucketExists(bucketName)) {
|
||||
LOGGER.error("桶已存在: {}", bucketName);
|
||||
} else {
|
||||
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
||||
LOGGER.error("创建桶成功: {}", bucketName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 上传文件到指定存储桶
|
||||
* @param file MultipartFile 文件对象
|
||||
* @return 上传后的文件访问 URL
|
||||
* @throws Exception 若上传过程中发生异常
|
||||
*/
|
||||
public SysFile uploadFile(MultipartFile file, String folderPath) throws Exception {
|
||||
|
||||
if (file.getSize() < 10 * 1024 * 1024L) {
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.object(folderPath)
|
||||
// -1 表示不限制文件大小
|
||||
.stream(file.getInputStream(), file.getInputStream().available(), -1)
|
||||
.contentType(file.getContentType())
|
||||
.build());
|
||||
} else {
|
||||
uploadLargeFile(folderPath, file);
|
||||
}
|
||||
|
||||
return SysFile.builder()
|
||||
.name(file.getOriginalFilename())
|
||||
.url(folderPath).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分片上传文件到指定文件夹
|
||||
* @param file MultipartFile 文件对象
|
||||
* @param folderPath 目标文件夹路径(如 "folder/subfolder")
|
||||
* @throws Exception 若上传过程中发生异常
|
||||
*/
|
||||
public void uploadLargeFile(String folderPath,MultipartFile file) throws Exception {
|
||||
long fileSize = file.getSize();
|
||||
int partCount = (int) Math.ceil((double) fileSize / PART_SIZE);
|
||||
|
||||
List<String> partNames = new ArrayList<>();
|
||||
// 创建线程池
|
||||
ExecutorService executor = Executors.newFixedThreadPool(5);
|
||||
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
|
||||
// 上传每个分片
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
long offset = i * PART_SIZE;
|
||||
long currentPartSize = Math.min(PART_SIZE, fileSize - offset);
|
||||
// 设置分片名称
|
||||
String partObjectName = folderPath + "part." + i;
|
||||
partNames.add(partObjectName);
|
||||
|
||||
final long partOffset = offset;
|
||||
final long partSizeFinal = currentPartSize;
|
||||
final String partName = partObjectName;
|
||||
|
||||
// 异步上传每个分片
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
try (InputStream inputStream = file.getInputStream()) { // 获取文件的输入流
|
||||
// 跳过文件前面的部分,直到当前分片的起始位置
|
||||
long skipped = inputStream.skip(partOffset);
|
||||
if (skipped != partOffset) {
|
||||
throw new RuntimeException("Could not skip to the correct part offset.");
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) partSizeFinal]; // 创建缓冲区来存储分片数据
|
||||
int bytesRead = inputStream.read(buffer); // 读取分片数据
|
||||
if (bytesRead == -1) {
|
||||
throw new RuntimeException("Error reading the part data.");
|
||||
}
|
||||
|
||||
// 上传分片
|
||||
try (ByteArrayInputStream stream = new ByteArrayInputStream(buffer)) {
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.object(partName)
|
||||
.stream(stream, stream.available(), -1)
|
||||
.build());
|
||||
System.out.println("Uploaded part: " + partName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error uploading part: " + partName, e);
|
||||
}
|
||||
}, executor); // 指定使用线程池执行任务
|
||||
|
||||
futures.add(future); // 将任务添加到 futures 列表
|
||||
}
|
||||
|
||||
// 等待所有分片上传完成
|
||||
CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
allOf.join(); // 阻塞等待所有任务完成
|
||||
|
||||
// 合并所有分片
|
||||
List<ComposeSource> sources = new ArrayList<>();
|
||||
for (String partName : partNames) {
|
||||
sources.add(ComposeSource.builder().bucket(minioConfig.getBucketName()).object(partName).build());
|
||||
}
|
||||
|
||||
// 将所有分片合并成最终文件
|
||||
try {
|
||||
minioClient.composeObject(ComposeObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
// 最终文件的路径
|
||||
.object(folderPath) // 可以自定义最终文件名
|
||||
.sources(sources)
|
||||
.build());
|
||||
System.out.println("Large file uploaded and composed successfully.");
|
||||
} catch (MinioException e) {
|
||||
throw new Exception("Error during file composition: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 删除临时分片
|
||||
for (String partName : partNames) {
|
||||
minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(partName).build());
|
||||
System.out.println("Removed part: " + partName);
|
||||
}
|
||||
|
||||
System.out.println("Large file uploaded successfully to folder: " + folderPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载指定文件,以 InputStream 形式返回
|
||||
|
||||
* @param objectName 存储对象名称(文件名)
|
||||
* @return 文件的输入流
|
||||
*/
|
||||
public InputStream downloadFile(String objectName){
|
||||
try (InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.object(objectName)
|
||||
.build())) {
|
||||
return inputStream;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error downloading file: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将多个文件压缩为 ZIP 并上传至 MinIO,返回压缩文件的下载链接
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectNames 文件对象列表(文件名)
|
||||
* @param zipFileName 压缩后的文件名
|
||||
* @return 压缩文件的下载 URL
|
||||
* @throws Exception
|
||||
*/
|
||||
public String downloadFilesAsZip(String bucketName, List<String> objectNames, String zipFileName) throws Exception {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
// 压缩每个文件
|
||||
for (String objectName : objectNames) {
|
||||
try (InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build())) {
|
||||
|
||||
// 添加 ZipEntry
|
||||
zos.putNextEntry(new ZipEntry(objectName));
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
zos.write(buffer, 0, len);
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
zos.finish();
|
||||
|
||||
// 上传 ZIP 文件到 MinIO
|
||||
try (ByteArrayInputStream zipInputStream = new ByteArrayInputStream(baos.toByteArray())) {
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(zipFileName)
|
||||
.stream(zipInputStream, zipInputStream.available(), -1)
|
||||
.contentType("application/zip")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
// 返回压缩文件的下载 URL
|
||||
return getFileUrl(bucketName, zipFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的临时访问 URL,指定过期时间
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 存储对象名称(文件名)
|
||||
* @param expiryTimeInSeconds URL 的有效时长(秒)
|
||||
* @return 文件的临时访问 URL
|
||||
* @throws Exception 若生成 URL 过程中发生异常
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public String getFileUrl(String bucketName, String objectName, int expiryTimeInSeconds) {
|
||||
try{
|
||||
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.expiry(expiryTimeInSeconds)
|
||||
.method(Method.GET)
|
||||
.build());
|
||||
}catch (Exception e){
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件bast64
|
||||
* @param bucketName
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public String getMinioBast64(String bucketName,String path) {
|
||||
InputStream inputStream= minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(path).build());
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
byte[] bytes = outputStream.toByteArray();
|
||||
String bast64= Base64.getEncoder().encodeToString(bytes);
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
return bast64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param bucketName 存储桶
|
||||
* @param objectName 文件名称
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public void removeFile(String bucketName, String objectName) {
|
||||
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||
}
|
||||
/**
|
||||
* 上传文件到指定路径
|
||||
* @param bucketName
|
||||
* @param file
|
||||
* @param objectName
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file,String objectName) {
|
||||
String contentType = file.getContentType();
|
||||
InputStream inputStream = file.getInputStream();
|
||||
ObjectWriteResponse object= minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(), -1).build());
|
||||
inputStream.close();
|
||||
return object;
|
||||
}
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param bucketName
|
||||
* @param imageBase64
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String path) {
|
||||
if (!StringUtils.isEmpty(imageBase64)) {
|
||||
InputStream in = base64ToInputStream(imageBase64);
|
||||
return uploadFile(bucketName, path, in);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static InputStream base64ToInputStream(String base64) {
|
||||
ByteArrayInputStream stream = null;
|
||||
try {
|
||||
byte[] bytes = Base64.getEncoder().encode(base64.trim().getBytes());
|
||||
stream = new ByteArrayInputStream(bytes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过流上传文件
|
||||
*
|
||||
* @param bucketName 存储桶
|
||||
* @param objectName 文件对象
|
||||
* @param inputStream 文件流
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows(Exception.class)
|
||||
public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {
|
||||
return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());
|
||||
}
|
||||
/**
|
||||
* 获取文件的临时访问 URL,默认过期时间为 7 天
|
||||
* @param bucketName 存储桶名称
|
||||
* @param objectName 存储对象名称(文件名)
|
||||
* @return 文件的临时访问 URL
|
||||
* @throws Exception 若生成 URL 过程中发生异常
|
||||
*/
|
||||
public String getFileUrl(String bucketName, String objectName) {
|
||||
// 604800 秒 = 7 天
|
||||
return getFileUrl(bucketName, objectName, 604800);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定的对象
|
||||
* @param objectName 存储对象名称(文件名)
|
||||
* @throws Exception 若删除过程中发生异常
|
||||
*/
|
||||
public void deleteObject( String objectName) throws Exception {
|
||||
minioClient.removeObject(RemoveObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.object(objectName)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
*
|
||||
* @param bucketName
|
||||
* @param objectName
|
||||
* @return
|
||||
*/
|
||||
public boolean isObjectExist(String bucketName, String objectName) {
|
||||
boolean exist = true;
|
||||
try {
|
||||
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||
} catch (Exception e) {
|
||||
exist = false;
|
||||
}
|
||||
return exist;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建文件夹(通过上传带有路径的文件)
|
||||
*
|
||||
* @param folderPath 文件夹路径(例如 "folder1/subfolder/")
|
||||
*/
|
||||
public void createFolder(String folderPath) {
|
||||
try {
|
||||
if (!folderPath.endsWith("/")) {
|
||||
folderPath += "/";
|
||||
}
|
||||
// 创建一个空文件内容,模拟文件夹
|
||||
// 空文件内容
|
||||
String emptyFileContent = "";
|
||||
InputStream emptyFileStream = new ByteArrayInputStream(emptyFileContent.getBytes());
|
||||
|
||||
// 上传一个空文件到指定路径,从而模拟文件夹创建
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
// 使用文件夹路径 + 文件名
|
||||
.object(folderPath + "empty.txt")
|
||||
.stream(emptyFileStream, 0, -1)
|
||||
.contentType("application/text")
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
// 使用 LOGGER 打印异常日志
|
||||
LOGGER.error("Error occurred while fetching files from bucket: {}",minioConfig.getBucketName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定路径的所有对象,从而删除整个文件夹及其子文件夹。
|
||||
*
|
||||
* @param folderPath 文件夹路径(例如 "folder1/subfolder/")
|
||||
*/
|
||||
public void deleteFolder(String folderPath) {
|
||||
try {
|
||||
if (!folderPath.endsWith("/")) {
|
||||
folderPath += "/";
|
||||
}
|
||||
// 列出指定文件夹路径下的所有对象(包括子文件夹中的对象)
|
||||
Iterable<Result<Item>> objects = minioClient.listObjects(
|
||||
ListObjectsArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.prefix(folderPath) // 设置路径前缀,列出该路径下的所有对象
|
||||
.recursive(true) // 递归列出所有子文件夹中的对象
|
||||
.build()
|
||||
);
|
||||
|
||||
// 遍历所有对象并删除它们
|
||||
for (Result<Item> result : objects) {
|
||||
Item item = result.get();
|
||||
String objectName = item.objectName();
|
||||
// 删除对象
|
||||
minioClient.removeObject(
|
||||
RemoveObjectArgs.builder()
|
||||
.bucket(minioConfig.getBucketName())
|
||||
.object(objectName)
|
||||
.build()
|
||||
);
|
||||
System.out.println("Deleted object: " + objectName);
|
||||
}
|
||||
System.out.println("Folder and all subfolders deleted successfully at path: " + folderPath);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error deleting folder and its contents at path: " + folderPath);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue