欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Boot?3?整合?MinIO?實(shí)現(xiàn)分布式文件存儲(chǔ)的全過(guò)程

 更新時(shí)間:2025年03月10日 10:36:03   作者:別惹CC  
本文介紹了如何使用SpringBoot3和MinIO實(shí)現(xiàn)分布式文件存儲(chǔ),通過(guò)MinIO的分布式對(duì)象存儲(chǔ)系統(tǒng),可以解決傳統(tǒng)單機(jī)文件存儲(chǔ)方案在面對(duì)大規(guī)模數(shù)據(jù)和高并發(fā)訪問(wèn)時(shí)的不足,文章詳細(xì)講解了MinIO的安裝、配置和使用,感興趣的朋友一起看看吧

引言

文件存儲(chǔ)已成為一個(gè)做任何應(yīng)用都不可回避的需求。傳統(tǒng)的單機(jī)文件存儲(chǔ)方案在面對(duì)大規(guī)模數(shù)據(jù)和高并發(fā)訪問(wèn)時(shí)往往力不從心,而分布式文件存儲(chǔ)系統(tǒng)則提供了更好的解決方案。本篇文章我將基于Spring Boot 3 為大家講解如何基于MinIO來(lái)實(shí)現(xiàn)分布式文件存儲(chǔ)。

分布式存儲(chǔ)的出現(xiàn)

在探討核心內(nèi)容之前,我們不妨先回顧分布式存儲(chǔ)技術(shù)是如何伴隨系統(tǒng)架構(gòu)演變發(fā)展的。在單體架構(gòu)早期,文件直接存儲(chǔ)于應(yīng)用服務(wù)器中,這種方式簡(jiǎn)單直接,存取便捷。然而,隨著業(yè)務(wù)規(guī)模擴(kuò)大和用戶量激增,系統(tǒng)架構(gòu)逐步向分布式或微服務(wù)方向演進(jìn)。此時(shí),若仍將文件存儲(chǔ)在應(yīng)用服務(wù)器中,在負(fù)載均衡機(jī)制下可能導(dǎo)致文件訪問(wèn)異常 —— 用戶上傳的文件可能因路由到其他服務(wù)節(jié)點(diǎn)而無(wú)法訪問(wèn)。

面對(duì)這個(gè)挑戰(zhàn),我們可以借鑒"分層解決"的架構(gòu)思想:將文件存儲(chǔ)從應(yīng)用服務(wù)中剝離,集中在獨(dú)立的存儲(chǔ)服務(wù)中統(tǒng)一管理。這便是分布式文件存儲(chǔ)系統(tǒng)的雛形。

技術(shù)選型

在了解了分布式存儲(chǔ)的演進(jìn)背景后,讓我們來(lái)梳理當(dāng)前主流的分布式存儲(chǔ)解決方案。

其他

  • FastDFS -> 架構(gòu)老舊,社區(qū)活躍度低,文檔資料匱乏
  • Ambry -> 過(guò)度依賴 LinkedIn 技術(shù)棧,通用性不足
  • MooseFS -> 部署配置繁瑣,運(yùn)維門檻高
  • MogileFS -> 性能一般,擴(kuò)展性受限
  • LeoFS -> 更新維護(hù)緩慢,生態(tài)系統(tǒng)不完善
  • openstack -> 架構(gòu)復(fù)雜重量級(jí),不適合輕量級(jí)應(yīng)用
  • TFS -> 主要服務(wù)于阿里內(nèi)部,外部支持有限
  • ceph -> 學(xué)習(xí)曲線陡峭,配置調(diào)優(yōu)復(fù)雜
  • GlusterFS -> 架構(gòu)復(fù)雜,問(wèn)題定位困難
  • OSS -> 商業(yè)收費(fèi)服務(wù),成本隨數(shù)據(jù)量增長(zhǎng)

?MinIO

MinIO 是一款輕量級(jí)的分布式對(duì)象存儲(chǔ)系統(tǒng),完全兼容 Amazon S3 云存儲(chǔ)服務(wù)接口。其部署維護(hù)簡(jiǎn)單,性能卓越,成為我們的首選方案。

MinIO安裝

MinIO 提供了多種部署方式,包括單機(jī)部署和分布式部署。本文主要關(guān)注 Spring BootMinIO 的整合實(shí)踐,因此我們選擇使用Docker(Ps:沒(méi)安裝Docker的同學(xué)速速去安裝,或者用別的方式只要本地部署的能跑就行)進(jìn)行快速部署。

首先,通過(guò)命令拉取鏡像。

docker pull minio/minio

接著在 本地創(chuàng)建一個(gè)存儲(chǔ)文件的映射目錄 D:\minio\data(Ps:我當(dāng)前演示的環(huán)境是win系統(tǒng),大家根據(jù)自己的操作系統(tǒng)建個(gè)目錄就行),使用以下命令啟動(dòng) MinIO:

?? 補(bǔ)充一個(gè)小細(xì)節(jié):MinIO 的安全限制要求用戶名長(zhǎng)度至少需要 3 個(gè)字符,密碼長(zhǎng)度至少需要 8 個(gè)字符。

    docker run -d --name minio -p 9000:9000 -p 9001:9001 -v D:\minio\data:/data -e "MINIO_ROOT_USER=root" -e "MINIO_ROOT_PASSWORD=12345678" minio/minio server /data --console-address ":9001" --address ":9000"

參數(shù)說(shuō)明:

  • -d: 后臺(tái)運(yùn)行容器
  • --name: 容器名稱
  • -p: 端口映射,9000用于API訪問(wèn),9001用于控制臺(tái)訪問(wèn)
  • -v: 目錄映射,將本地目錄映射到容器的 /data
  • -e: 環(huán)境變量,設(shè)置管理員賬號(hào)和密碼
  • --console-address: 指定控制臺(tái)端口
  • --restart=always: 容器自動(dòng)重啟策略
  • --address ":9000": 顯式指定 API 端口

運(yùn)行成功后訪問(wèn) http://localhost:9001,使用執(zhí)行命令中的憑據(jù)(Ps:大家在使用時(shí)可以修改為自己的用戶名和密碼)登錄:

  • 用戶名:root
  • 密碼:12345678

登錄系統(tǒng)后,界面會(huì)提示創(chuàng)建。熟悉云服務(wù)商OSS服務(wù)的讀者對(duì)此概念應(yīng)該不陌生。對(duì)初次接觸的讀者,可以將理解為一個(gè)命名空間或文件夾,您可以創(chuàng)建多個(gè),每個(gè)內(nèi)還能包含多層級(jí)的文件夾和文件。

這里我演示下控制臺(tái)如何建桶和上傳文件,方便大家理解文件在MinIO上的存儲(chǔ)結(jié)構(gòu)。

只需要輸入名稱就可以,建好之后可以看到的使用狀態(tài)。

點(diǎn)擊它進(jìn)入的內(nèi)部,這里大家需要關(guān)注一個(gè)設(shè)置- Access Policy,默認(rèn)是Private。這個(gè)設(shè)置需要根據(jù)業(yè)務(wù)的實(shí)際情況來(lái),如果你的業(yè)務(wù)是需要提供一些不需要鑒權(quán)的公共訪問(wèn)的文件,就設(shè)為public;反之,就保持private。我這里把它修改為public。

然后點(diǎn)擊右上角的上傳按鈕進(jìn)入上傳頁(yè)可以向桶內(nèi)上傳文件。

上傳成功后可以在桶內(nèi)看到文件。

點(diǎn)擊文件可查看詳情,支持預(yù)覽、刪除、分享等多種功能。這些操作較為直觀,安裝后各位讀者可自行體驗(yàn)。本文重點(diǎn)關(guān)注不在控制臺(tái)的操作,就不做過(guò)多贅述了。

??這里再?gòu)?qiáng)調(diào)一點(diǎn):存儲(chǔ)在里的文件通過(guò)API訪問(wèn)的端口和控制臺(tái)是不一樣的。如果你對(duì)這里感覺(jué)迷惑,可以回看一下上面我貼上的docker運(yùn)行命令里配置了兩個(gè)端口-90009001。如果要通過(guò)API訪問(wèn)查看這個(gè)文件的話,通過(guò)拼接地址/端口號(hào)/桶名/文件路徑查看,那么剛測(cè)試上傳的文件的訪問(wèn)API就是http://localhost:9000/test/1.gif,在瀏覽器地址欄輸入后可以看到。

# Spring Boot整合MinIO

這部分對(duì)于新建項(xiàng)目就不贅述了,直接說(shuō)下我使用的 Spring boot 版本為3.2.3,供大家參考。

1.引入依賴

pom.xml引入minIO的依賴,版本大家自己使用你當(dāng)前最新的版本即可。

<!-- minio -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>${latest.version}</version>
</dependency>

2.添加配置

在yml配置文件中配置連接信息。

# minIO配置
minio:
  endpoint: http://127.0.0.1:9000     # MinIO服務(wù)地址
  fileHost: http://127.0.0.1:9000     # 文件地址host
  bucketName: wechat                  # 存儲(chǔ)桶bucket名稱
  accessKey: root                     # 用戶名
  secretKey: 12345678                 # 密碼

3.編寫配置類

import com.pitayafruits.utils.MinIOUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class MinIOConfig {
    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.fileHost}")
    private String fileHost;
    @Value("${minio.bucketName}")
    private String bucketName;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;
    @Bean
    public MinIOUtils creatMinioClient() {
        return new MinIOUtils(endpoint, fileHost, bucketName, accessKey, secretKey);
    }
}

4.引入工具類

這個(gè)工具類封裝了MinIO的核心功能,為您提供了很多開(kāi)箱即用的功能。通過(guò)引入它,可以輕松實(shí)現(xiàn)文件上傳、下載等操作,讓大家將更多精力集中在業(yè)務(wù)開(kāi)發(fā)上。

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
/**
 * MinIO工具類
 */
@Slf4j
public class MinIOUtils {
    private static MinioClient minioClient;
    private static String endpoint;
    private static String fileHost;
    private static String bucketName;
    private static String accessKey;
    private static String secretKey;
    private static final String SEPARATOR = "/";
    public MinIOUtils() {
    }
    public MinIOUtils(String endpoint, String fileHost, String bucketName, String accessKey, String secretKey) {
        MinIOUtils.endpoint = endpoint;
        MinIOUtils.fileHost = fileHost;
        MinIOUtils.bucketName = bucketName;
        MinIOUtils.accessKey = accessKey;
        MinIOUtils.secretKey = secretKey;
        createMinioClient();
    }
    /**
     * 創(chuàng)建基于Java端的MinioClient
     */
    public void createMinioClient() {
        try {
            if (null == minioClient) {
                log.info("開(kāi)始創(chuàng)建 MinioClient...");
                minioClient = MinioClient
                                .builder()
                                .endpoint(endpoint)
                                .credentials(accessKey, secretKey)
                                .build();
                createBucket(bucketName);
                log.info("創(chuàng)建完畢 MinioClient...");
            }
        } catch (Exception e) {
            log.error("MinIO服務(wù)器異常:{}", e);
        }
    }
    /**
     * 獲取上傳文件前綴路徑
     * @return
     */
    public static String getBasisUrl() {
        return endpoint + SEPARATOR + bucketName + SEPARATOR;
    }
    /******************************  Operate Bucket Start  ******************************/
    /**
     * 啟動(dòng)SpringBoot容器的時(shí)候初始化Bucket
     * 如果沒(méi)有Bucket則創(chuàng)建
     * @throws Exception
     */
    private static void createBucket(String bucketName) throws Exception {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }
    /**
     *  判斷Bucket是否存在,true:存在,false:不存在
     * @return
     * @throws Exception
     */
    public static boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }
    /**
     * 獲得Bucket的策略
     * @param bucketName
     * @return
     * @throws Exception
     */
    public static String getBucketPolicy(String bucketName) throws Exception {
        String bucketPolicy = minioClient
                                .getBucketPolicy(
                                        GetBucketPolicyArgs
                                                .builder()
                                                .bucket(bucketName)
                                                .build()
                                );
        return bucketPolicy;
    }
    /**
     * 獲得所有Bucket列表
     * @return
     * @throws Exception
     */
    public static List<Bucket> getAllBuckets() throws Exception {
        return minioClient.listBuckets();
    }
    /**
     * 根據(jù)bucketName獲取其相關(guān)信息
     * @param bucketName
     * @return
     * @throws Exception
     */
    public static Optional<Bucket> getBucket(String bucketName) throws Exception {
        return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }
    /**
     * 根據(jù)bucketName刪除Bucket,true:刪除成功; false:刪除失敗,文件或已不存在
     * @param bucketName
     * @throws Exception
     */
    public static void removeBucket(String bucketName) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }
    /******************************  Operate Bucket End  ******************************/
    /******************************  Operate Files Start  ******************************/
    /**
     * 判斷文件是否存在
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名
     * @return
     */
    public static 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 bucketName 存儲(chǔ)桶
     * @param objectName 文件夾名稱
     * @return
     */
    public static boolean isFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && objectName.equals(item.objectName())) {
                    exist = true;
                }
            }
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }
    /**
     * 根據(jù)文件前置查詢文件
     * @param bucketName 存儲(chǔ)桶
     * @param prefix 前綴
     * @param recursive 是否使用遞歸查詢
     * @return MinioItem 列表
     * @throws Exception
     */
    public static List<Item> getAllObjectsByPrefix(String bucketName,
                                                   String prefix,
                                                   boolean recursive) throws Exception {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
        if (objectsIterator != null) {
            for (Result<Item> o : objectsIterator) {
                Item item = o.get();
                list.add(item);
            }
        }
        return list;
    }
    /**
     * 獲取文件流
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名
     * @return 二進(jìn)制流
     */
    public static InputStream getObject(String bucketName, String objectName) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }
    /**
     * 斷點(diǎn)下載
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名稱
     * @param offset 起始字節(jié)的位置
     * @param length 要讀取的長(zhǎng)度
     * @return 二進(jìn)制流
     */
    public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .offset(offset)
                        .length(length)
                        .build());
    }
    /**
     * 獲取路徑下文件列表
     * @param bucketName 存儲(chǔ)桶
     * @param prefix 文件名稱
     * @param recursive 是否遞歸查找,false:模擬文件夾結(jié)構(gòu)查找
     * @return 二進(jìn)制流
     */
    public static Iterable<Result<Item>> listObjects(String bucketName, String prefix,
                                                     boolean recursive) {
        return minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive)
                        .build());
    }
    /**
     * 使用MultipartFile進(jìn)行文件上傳
     * @param bucketName 存儲(chǔ)桶
     * @param file 文件名
     * @param objectName 對(duì)象名
     * @param contentType 類型
     * @return
     * @throws Exception
     */
    public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file,
                                                 String objectName, String contentType) throws Exception {
        InputStream inputStream = file.getInputStream();
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .contentType(contentType)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }
    /**
     * 上傳本地文件
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 對(duì)象名稱
     * @param fileName 本地文件路徑
     */
    public static String uploadFile(String bucketName, String objectName,
                                                 String fileName, boolean needUrl) throws Exception {
        minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .filename(fileName)
                        .build());
        if (needUrl) {
            String imageUrl = fileHost
                    + "/"
                    + bucketName
                    + "/"
                    + objectName;
            return imageUrl;
        }
        return "";
    }
    /**
     * 通過(guò)流上傳文件
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件對(duì)象
     * @param inputStream 文件流
     */
    public static ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }
    public static String uploadFile(String bucketName, String objectName, InputStream inputStream, boolean needUrl) throws Exception {
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
        if (needUrl) {
            String imageUrl = fileHost
                    + "/"
                    + bucketName
                    + "/"
                    + objectName;
            return imageUrl;
        }
        return "";
    }
    /**
     * 創(chuàng)建文件夾或目錄
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 目錄路徑
     */
    public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
                        .build());
    }
    /**
     * 獲取文件信息, 如果拋出異常則說(shuō)明文件不存在
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名稱
     */
    public static String getFileStatusInfo(String bucketName, String objectName) throws Exception {
        return minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()).toString();
    }
    /**
     * 拷貝文件
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名
     * @param srcBucketName 目標(biāo)存儲(chǔ)桶
     * @param srcObjectName 目標(biāo)文件名
     */
    public static ObjectWriteResponse copyFile(String bucketName, String objectName,
                                               String srcBucketName, String srcObjectName) throws Exception {
        return minioClient.copyObject(
                CopyObjectArgs.builder()
                        .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                        .bucket(srcBucketName)
                        .object(srcObjectName)
                        .build());
    }
    /**
     * 刪除文件
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名稱
     */
    public static void removeFile(String bucketName, String objectName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }
    /**
     * 批量刪除文件
     * @param bucketName 存儲(chǔ)桶
     * @param keys 需要?jiǎng)h除的文件列表
     * @return
     */
    public static void removeFiles(String bucketName, List<String> keys) {
        List<DeleteObject> objects = new LinkedList<>();
        keys.forEach(s -> {
            objects.add(new DeleteObject(s));
            try {
                removeFile(bucketName, s);
            } catch (Exception e) {
                log.error("批量刪除失?。rror:{}",e);
            }
        });
    }
    /**
     * 獲取文件外鏈
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名
     * @param expires 過(guò)期時(shí)間 <=7 秒 (外鏈有效時(shí)間(單位:秒))
     * @return url
     * @throws Exception
     */
    public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
        return minioClient.getPresignedObjectUrl(args);
    }
    /**
     * 獲得文件外鏈
     * @param bucketName
     * @param objectName
     * @return url
     * @throws Exception
     */
    public static String getPresignedObjectUrl(String bucketName, String objectName) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                                                                    .bucket(bucketName)
                                                                    .object(objectName)
                                                                    .method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(args);
    }
    /**
     * 將URLDecoder編碼轉(zhuǎn)成UTF8
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
        String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        return URLDecoder.decode(url, "UTF-8");
    }
    /******************************  Operate Files End  ******************************/
}

5.開(kāi)發(fā)測(cè)試

我剛好在做練手項(xiàng)目,這里寫個(gè)上傳頭像的接口。

import com.pitayafruits.base.BaseInfoProperties;
import com.pitayafruits.config.MinIOConfig;
import com.pitayafruits.grace.result.GraceJSONResult;
import com.pitayafruits.grace.result.ResponseStatusEnum;
import com.pitayafruits.utils.MinIOUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("file")
public class FileController extends BaseInfoProperties {
    @Resource
    private MinIOConfig minIOConfig;
    @PostMapping("uploadFace")
    public GraceJSONResult upload(@RequestParam MultipartFile file,
                                 String userId) throws Exception {
        if (StringUtils.isBlank(userId)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
        }
        String filename = file.getOriginalFilename();
        if (StringUtils.isBlank(filename)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
        }
        filename = "face" +  "/" + userId + "/" + filename;
        MinIOUtils.uploadFile(minIOConfig.getBucketName(), filename, file.getInputStream());
        String faceUrl = minIOConfig.getFileHost()
                + "/"
                + minIOConfig.getBucketName()
                + "/"
                + filename;
        return GraceJSONResult.ok(faceUrl);
    }
}

可以看到通過(guò)工具類只需要一行代碼就可以實(shí)現(xiàn)上傳文件,我們只需要在調(diào)用的時(shí)候做好文件的業(yè)務(wù)隔離即可。完成了接口的開(kāi)發(fā),這里我來(lái)通過(guò)Apifox調(diào)用測(cè)試一下。

通過(guò)瀏覽器訪問(wèn)返回的圖片鏈接會(huì)自動(dòng)下載,我們?cè)俚卿浛刂婆_(tái)看對(duì)應(yīng)的桶下的這個(gè)路徑,也可以看到這個(gè)文件。

小結(jié)

我們?cè)诩傻谌椒?wù)時(shí)應(yīng)遵循一個(gè)核心原則:將API操作封裝成通用工具類。這不僅讓MinIO的集成更加優(yōu)雅,也讓代碼具備更好的復(fù)用性和可維護(hù)性。這種思維方式同樣適用于其他第三方服務(wù)的對(duì)接。

到此這篇關(guān)于Spring Boot 3 整合 MinIO 實(shí)現(xiàn)分布式文件存儲(chǔ)的文章就介紹到這了,更多相關(guān)Spring Boot  MinIO 分布式文件存儲(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性

    Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性

    今天小編就為大家分享一篇關(guān)于Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • Java使用代理進(jìn)行網(wǎng)絡(luò)連接方法示例

    Java使用代理進(jìn)行網(wǎng)絡(luò)連接方法示例

    這篇文章主要介紹了Java使用代理進(jìn)行網(wǎng)絡(luò)連接方法示例,內(nèi)容十分詳細(xì),需要的朋友可以參考下。
    2017-09-09
  • SpringBoot實(shí)現(xiàn)統(tǒng)一功能處理的教程詳解

    SpringBoot實(shí)現(xiàn)統(tǒng)一功能處理的教程詳解

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)統(tǒng)一功能處理,文中的示例代碼講解詳細(xì),對(duì)大家學(xué)習(xí)或工作有一定借鑒價(jià)值,感興趣的同學(xué)可以參考閱讀下
    2023-05-05
  • java實(shí)現(xiàn)九宮格游戲

    java實(shí)現(xiàn)九宮格游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)九宮格游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法

    Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法

    這篇文章主要給大家介紹了關(guān)于Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java內(nèi)部類及其特點(diǎn)的講解

    Java內(nèi)部類及其特點(diǎn)的講解

    今天小編就為大家分享一篇關(guān)于Java內(nèi)部類及其特點(diǎn)的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • springboot整合security和vue的實(shí)踐

    springboot整合security和vue的實(shí)踐

    本文主要介紹了springboot整合security和vue的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • SpringBoot框架RESTful接口設(shè)置跨域允許

    SpringBoot框架RESTful接口設(shè)置跨域允許

    這篇文章主要為大家詳細(xì)介紹了SpringBoot框架RESTful接口設(shè)置跨域允許,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Java?MethodHandles介紹與反射對(duì)比區(qū)別詳解

    Java?MethodHandles介紹與反射對(duì)比區(qū)別詳解

    這篇文章主要為大家介紹了Java?MethodHandles介紹與反射對(duì)比區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • java隨機(jī)驗(yàn)證碼生成實(shí)現(xiàn)實(shí)例代碼

    java隨機(jī)驗(yàn)證碼生成實(shí)現(xiàn)實(shí)例代碼

    這篇文章主要介紹了java隨機(jī)驗(yàn)證碼生成實(shí)現(xiàn)實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評(píng)論