chenhj
9 天以前 17badd7ea4d77c0aafbdfa65e05743cb7856489c
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);
        // æ‰§è¡Œæ­£å¸¸æ“ä½œ
        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());
                // ä¸ºfalse只生成24小时有效时长的url链接,可以访问该文件
                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;
    }
}