diff --git a/bonus-admin/src/main/java/com/bonus/web/controller/file/FileUploadController.java b/bonus-admin/src/main/java/com/bonus/web/controller/file/FileUploadController.java
new file mode 100644
index 0000000..e798f75
--- /dev/null
+++ b/bonus-admin/src/main/java/com/bonus/web/controller/file/FileUploadController.java
@@ -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();
+ }
+}
diff --git a/bonus-admin/src/main/resources/application-file.yml b/bonus-admin/src/main/resources/application-file.yml
index 7995e7f..7d1c1db 100644
--- a/bonus-admin/src/main/resources/application-file.yml
+++ b/bonus-admin/src/main/resources/application-file.yml
@@ -4,4 +4,7 @@ minio:
endpoint: http://192.168.0.14:9090
access-key: minio
secret-key: bonus@admin123
- bucket-name: smart-bid
\ No newline at end of file
+ bucket-name: smart-bid
+# 文件上传前缀
+uploadSuffix:
+ main_database: main_database #主体库
\ No newline at end of file
diff --git a/bonus-common/pom.xml b/bonus-common/pom.xml
index 630143f..8751569 100644
--- a/bonus-common/pom.xml
+++ b/bonus-common/pom.xml
@@ -181,6 +181,12 @@
4.5.14
+
+ io.minio
+ minio
+ ${minio.version}
+
+
\ No newline at end of file
diff --git a/bonus-common/src/main/java/com/bonus/common/domain/file/vo/FileDetails.java b/bonus-common/src/main/java/com/bonus/common/domain/file/vo/FileDetails.java
new file mode 100644
index 0000000..300bfe6
--- /dev/null
+++ b/bonus-common/src/main/java/com/bonus/common/domain/file/vo/FileDetails.java
@@ -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;
+
+}
diff --git a/bonus-common/src/main/java/com/bonus/common/domain/file/vo/SysFile.java b/bonus-common/src/main/java/com/bonus/common/domain/file/vo/SysFile.java
new file mode 100644
index 0000000..4cb49ea
--- /dev/null
+++ b/bonus-common/src/main/java/com/bonus/common/domain/file/vo/SysFile.java
@@ -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();
+ }
+}
diff --git a/bonus-file/src/main/java/com/bonus/file/config/MinioConfig.java b/bonus-file/src/main/java/com/bonus/file/config/MinioConfig.java
new file mode 100644
index 0000000..248550a
--- /dev/null
+++ b/bonus-file/src/main/java/com/bonus/file/config/MinioConfig.java
@@ -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();
+ }
+}
diff --git a/bonus-file/src/main/java/com/bonus/file/service/FileUploadService.java b/bonus-file/src/main/java/com/bonus/file/service/FileUploadService.java
new file mode 100644
index 0000000..ae6c14e
--- /dev/null
+++ b/bonus-file/src/main/java/com/bonus/file/service/FileUploadService.java
@@ -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;
+ }
+
+}
diff --git a/bonus-file/src/main/java/com/bonus/file/util/FileUtil.java b/bonus-file/src/main/java/com/bonus/file/util/FileUtil.java
new file mode 100644
index 0000000..ca0e4da
--- /dev/null
+++ b/bonus-file/src/main/java/com/bonus/file/util/FileUtil.java
@@ -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("."));
+ }
+}
diff --git a/bonus-file/src/main/java/com/bonus/file/util/MinioUtil.java b/bonus-file/src/main/java/com/bonus/file/util/MinioUtil.java
new file mode 100644
index 0000000..eee40c7
--- /dev/null
+++ b/bonus-file/src/main/java/com/bonus/file/util/MinioUtil.java
@@ -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 partNames = new ArrayList<>();
+ // 创建线程池
+ ExecutorService executor = Executors.newFixedThreadPool(5);
+
+ List> 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 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 allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
+ allOf.join(); // 阻塞等待所有任务完成
+
+ // 合并所有分片
+ List 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 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> objects = minioClient.listObjects(
+ ListObjectsArgs.builder()
+ .bucket(minioConfig.getBucketName())
+ .prefix(folderPath) // 设置路径前缀,列出该路径下的所有对象
+ .recursive(true) // 递归列出所有子文件夹中的对象
+ .build()
+ );
+
+ // 遍历所有对象并删除它们
+ for (Result- 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();
+ }
+ }
+
+
+}
diff --git a/pom.xml b/pom.xml
index 3349f1e..4251e60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,7 @@
dev
8.0.33
+ 8.2.2