From 17badd7ea4d77c0aafbdfa65e05743cb7856489c Mon Sep 17 00:00:00 2001
From: chenhj <chenhj@lunor.cn>
Date: 星期五, 30 五月 2025 14:40:58 +0800
Subject: [PATCH] Merge pull request 'chen' (#12) from chen into master

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java |  306 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 306 insertions(+), 0 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java
new file mode 100644
index 0000000..4b87a2e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java
@@ -0,0 +1,306 @@
+package com.ruoyi.common.utils.file;
+
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.ruoyi.common.core.domain.MinioResult;
+import com.ruoyi.common.exception.UtilException;
+import com.ruoyi.common.exception.file.InvalidExtensionException;
+import io.minio.*;
+import io.minio.http.Method;
+import io.minio.messages.DeleteError;
+import io.minio.messages.DeleteObject;
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+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.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.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Component
+public class MinioUtils {
+    @Autowired
+    private MinioClient minioClient;
+
+    @Value("${minio.preview-expiry}")
+    private Integer previewExpiry;
+
+    /**
+     * -- GETTER --
+     *  鑾峰彇榛樿瀛樺偍妗跺悕绉�
+     *
+     * @return
+     */
+    @Getter
+    @Value("${minio.default-bucket}")
+    private String defaultBucket;
+
+    /**
+     * 鍒ゆ柇瀛樺偍妗舵槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯鍒涘缓
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     */
+    public void existBucket(String bucketName) {
+        try {
+            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
+            if (!exists) {
+                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 鍒涘缓瀛樺偍妗�
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @return 鏄惁鍒涘缓鎴愬姛
+     */
+    public Boolean makeBucket(String bucketName) {
+        try {
+            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鍒犻櫎瀛樺偍妗�
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    public Boolean removeBucket(String bucketName) {
+        try {
+            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @param originalFileName MinIO涓瓨鍌ㄥ璞″叏璺緞
+     * @return 瀵硅薄鏄惁瀛樺湪
+     */
+    public boolean existObject(String bucketName, String originalFileName) {
+        try {
+            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(originalFileName).build());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鏂囦欢涓婁紶
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @param file       鏂囦欢
+     * @return 妗朵腑浣嶇疆
+     */
+    public MinioResult upload(String bucketName, MultipartFile file, Boolean isPreviewExpiry) throws InvalidExtensionException {
+        MultipartFile[] fileArr = {file};
+        List<MinioResult> fileNames = upload(bucketName, fileArr, isPreviewExpiry);
+        return fileNames.isEmpty() ? null : fileNames.get(0);
+    }
+
+    /**
+     * 涓婁紶鏂囦欢
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @param fileList   鏂囦欢鍒楄〃
+     * @return 妗朵腑浣嶇疆鍒楄〃
+     */
+    public List<MinioResult> upload(String bucketName, List<MultipartFile> fileList, Boolean isPreviewExpiry) throws InvalidExtensionException {
+        MultipartFile[] fileArr = fileList.toArray(new MultipartFile[0]);
+        return upload(bucketName, fileArr, isPreviewExpiry);
+    }
+
+    /**
+     * description: 涓婁紶鏂囦欢
+     *
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @param fileArr    鏂囦欢鍒楄〃
+     * @return 妗朵腑浣嶇疆鍒楄〃
+     */
+    public List<MinioResult> upload(String bucketName, MultipartFile[] fileArr, Boolean isPreviewExpiry) throws InvalidExtensionException {
+        for (MultipartFile file : fileArr) {
+            FileUploadUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+        }
+        // 淇濊瘉妗朵竴瀹氬瓨鍦�
+        existBucket(bucketName);
+        // 鎵ц姝e父鎿嶄綔
+        List<MinioResult> bucketFileNames = new ArrayList<>(fileArr.length);
+        for (MultipartFile file : fileArr) {
+            // 鑾峰彇鍘熷鏂囦欢鍚嶇О
+            String originalFileName = file.getOriginalFilename();
+            // 鑾峰彇褰撳墠鏃ユ湡锛屾牸寮忎緥濡傦細2020-11
+            String datePath = new SimpleDateFormat("yyyy-MM").format(new Date());
+            // 鏂囦欢鍚嶇О
+            String uuid = IdWorker.get32UUID();
+            // 鑾峰彇鏂囦欢鍚庣紑
+            String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
+            String bucketFilePath = datePath + "/" + uuid + suffix;
+
+            // 鎺ㄩ�佹枃浠跺埌MinIO
+            try (InputStream in = file.getInputStream()) {
+                minioClient.putObject(PutObjectArgs.builder()
+                        .bucket(bucketName)
+                        .object(bucketFilePath)
+                        .stream(in, in.available(), -1)
+                        .contentType(file.getContentType())
+                        .build()
+                );
+            } catch (Exception e) {
+                throw new UtilException("MinioUtils锛氫笂浼犳枃浠跺伐鍏风被寮傚父:" + e);
+            }
+            MinioResult minioResult = new MinioResult();
+            minioResult.setBucketFileName(bucketFilePath);
+            // 杩斿洖姘镐箙棰勮鍦板潃
+            if (isPreviewExpiry) {
+                String previewUrl = getPreviewUrl(bucketFilePath, bucketName, isPreviewExpiry);
+                minioResult.setPreviewExpiry(previewUrl);
+            }
+            minioResult.setOriginalName(originalFileName);
+            bucketFileNames.add(minioResult);
+        }
+        return bucketFileNames;
+    }
+
+    /**
+     * 鏂囦欢涓嬭浇
+     *
+     * @param bucketName       瀛樺偍妗跺悕绉�
+     * @param bucketFileName   妗朵腑鏂囦欢鍚嶇О
+     * @param originalFileName 鍘熷鏂囦欢鍚嶇О
+     * @param response         response瀵硅薄
+     */
+    public void download(String bucketName, String bucketFileName, String originalFileName, HttpServletResponse response) {
+        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(bucketFileName).build();
+        try (GetObjectResponse objResponse = minioClient.getObject(objectArgs)) {
+            byte[] buf = new byte[1024];
+            int len;
+            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
+                while ((len = objResponse.read(buf)) != -1) {
+                    os.write(buf, 0, len);
+                }
+                os.flush();
+                byte[] bytes = os.toByteArray();
+                response.setCharacterEncoding("utf-8");
+                //璁剧疆寮哄埗涓嬭浇涓嶆墦寮�
+                response.setContentType("application/force-download");
+                // 璁剧疆闄勪欢鍚嶇О缂栫爜
+                originalFileName = new String(originalFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
+                // 璁剧疆闄勪欢鍚嶇О
+                response.addHeader("Content-Disposition", "attachment;fileName=" + originalFileName);
+                // 鍐欏叆鏂囦欢
+                try (ServletOutputStream stream = response.getOutputStream()) {
+                    stream.write(bytes);
+                    stream.flush();
+                }
+            }
+        } catch (Exception e) {
+            throw new UtilException("MinioUtils锛氫笂浼犳枃浠跺伐鍏风被寮傚父");
+        }
+    }
+
+    /**
+     * 鑾峰彇宸蹭笂浼犲璞$殑鏂囦欢娴侊紙鍚庣鍥犱负涓氬姟闇�瑕佽幏鍙栨枃浠舵祦鍙互璋冪敤璇ユ柟娉曪級
+     *
+     * @param bucketName     瀛樺偍妗跺悕绉�
+     * @param bucketFileName 妗朵腑鏂囦欢鍚嶇О
+     * @return 鏂囦欢娴�
+     */
+    public InputStream getFileStream(String bucketName, String bucketFileName) throws Exception {
+        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(bucketFileName).build();
+        return minioClient.getObject(objectArgs);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢瀵硅薄缁撴灉
+     *
+     * @param bucketName      瀛樺偍妗跺悕绉�
+     * @param bucketFileName 妗朵腑鏂囦欢鍚嶇О
+     * @return 鍒犻櫎缁撴灉
+     */
+    public DeleteError removeObjectsResult(String bucketName, String bucketFileName) {
+        List<DeleteError> results = removeObjectsResult(bucketName, Collections.singletonList(bucketFileName));
+        return !results.isEmpty() ? results.get(0) : null;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢瀵硅薄缁撴灉
+     *
+     * @param bucketName      瀛樺偍妗跺悕绉�
+     * @param bucketFileNames 妗朵腑鏂囦欢鍚嶇О闆嗗悎
+     * @return 鍒犻櫎缁撴灉
+     */
+    public List<DeleteError> removeObjectsResult(String bucketName, List<String> bucketFileNames) {
+        Iterable<Result<DeleteError>> results = removeObjects(bucketName, bucketFileNames);
+        List<DeleteError> res = new ArrayList<>();
+        for (Result<DeleteError> result : results) {
+            try {
+                res.add(result.get());
+            } catch (Exception e) {
+                throw new UtilException("MinioUtils锛氫笂浼犳枃浠跺伐鍏风被寮傚父");
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢瀵硅薄
+     *
+     * @param bucketName      瀛樺偍妗跺悕绉�
+     * @param bucketFileNames 妗朵腑鏂囦欢鍚嶇О闆嗗悎
+     */
+    private Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> bucketFileNames) {
+        List<DeleteObject> dos = bucketFileNames.stream().map(DeleteObject::new).collect(Collectors.toList());
+        return minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
+    }
+
+    /**
+     * 鏌ヨ棰勮url
+     * @param bucketFileName minio鏂囦欢鍚嶇О
+     * @param bucketName 瀛樺偍妗跺悕绉�
+     * @param isPreviewExpiry 鏄惁闇�瑕佽繃鏈熸椂闂� 榛樿24灏忔椂
+     * @return
+     */
+    public String getPreviewUrl(String bucketFileName, String bucketName, Boolean isPreviewExpiry) {
+        if (StringUtils.isNotBlank(bucketFileName)) {
+            try {
+                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(bucketFileName).build());
+                // 涓篺alse鍙敓鎴�24灏忔椂鏈夋晥鏃堕暱鐨剈rl閾炬帴锛屽彲浠ヨ闂鏂囦欢
+                if (isPreviewExpiry){
+                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(bucketFileName).build());
+                }else {
+                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(bucketFileName).expiry(previewExpiry, TimeUnit.HOURS).build());
+                }
+            } catch (Exception e) {
+                throw new UtilException("MinioUtils锛氫笂浼犳枃浠跺伐鍏风被寮傚父");
+            }
+        }
+        return null;
+    }
+
+}

--
Gitblit v1.9.3