1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot + Minio 實(shí)現(xiàn)文件切片極速上傳技術(shù)

        共 57959字,需瀏覽 116分鐘

         ·

        2024-07-01 11:41

        來(lái)源:juejin.cn/post/7304539173972983860

        一. 概述

        提示:請(qǐng)不要多個(gè)博客來(lái)回跳著看,此文章之詳細(xì)絕無(wú)僅有,融合多家之長(zhǎng),如果遇見(jiàn)報(bào)錯(cuò),請(qǐng)仔細(xì)捋一遍文章,不要忽略!我在寫的時(shí)候因?yàn)樵S多文章不全面,來(lái)回跳遇見(jiàn)許多坑,希望大家可以避免,本文章中悉數(shù)做了標(biāo)注提醒!?。?/p>

        官網(wǎng)地址:

        https://min.io/

        文檔地址:

        https://docs.min.io/

        該文檔源碼地址(免費(fèi)資源):

        https://download.csdn.net/download/weixin_53742691/87856930

        Minio是一款開(kāi)源的對(duì)象存儲(chǔ)服務(wù)器,它可以運(yùn)行在多種操作系統(tǒng)上,包括Linux、Windows和MacOS等。它提供了一種簡(jiǎn)單、可擴(kuò)展、高可用的對(duì)象存儲(chǔ)解決方案,支持多種數(shù)據(jù)格式,包括對(duì)象、塊和文件等。

        以下是Minio的主要特點(diǎn):

        • 簡(jiǎn)單易用: Minio的安裝和配置非常簡(jiǎn)單,只需要下載并運(yùn)行相應(yīng)的二進(jìn)制文件即可。它提供了一個(gè)Web UI,可以通過(guò)界面管理存儲(chǔ)桶和對(duì)象。

        • 可擴(kuò)展性: Minio可以輕松地?cái)U(kuò)展到多個(gè)節(jié)點(diǎn),以提供高可用性和容錯(cuò)能力。它支持多種部署模式,包括單節(jié)點(diǎn)、主從復(fù)制和集群等。

        • 高可用性: Minio提供了多種機(jī)制來(lái)保證數(shù)據(jù)的可靠性和可用性,包括冗余備份、數(shù)據(jù)復(fù)制和故障轉(zhuǎn)移等。

        • 安全性: Minio提供了多種安全機(jī)制來(lái)保護(hù)數(shù)據(jù)的機(jī)密性和完整性,包括SSL/TLS加密、訪問(wèn)控制和數(shù)據(jù)加密等。

        • 多語(yǔ)言支持: Minio支持多種編程語(yǔ)言,包括Java、Python、Ruby和Go等。

        • 社區(qū)支持: Minio是一個(gè)開(kāi)源項(xiàng)目,擁有龐大的社區(qū)支持和貢獻(xiàn)者。它的源代碼可以在GitHub上獲得,并且有一個(gè)活躍的郵件列表和論壇。

        • 對(duì)象存儲(chǔ): Minio的核心功能是對(duì)象存儲(chǔ)。它允許用戶上傳和下載任意數(shù)量和大小的對(duì)象,并提供了多種API和SDK來(lái)訪問(wèn)這些對(duì)象。

        • 塊存儲(chǔ): Minio還支持塊存儲(chǔ),允許用戶上傳和下載大型文件(例如圖像或視頻)。塊存儲(chǔ)是一種快速、高效的方式來(lái)處理大型文件。

        • 文件存儲(chǔ): Minio還支持文件存儲(chǔ),允許用戶上傳和下載單個(gè)文件。文件存儲(chǔ)是一種簡(jiǎn)單、快速的方式來(lái)處理小型文件。

        總之,Minio是一款強(qiáng)大、靈活、可擴(kuò)展的對(duì)象存儲(chǔ)服務(wù)器,適用于各種應(yīng)用場(chǎng)景,包括云存儲(chǔ)、大數(shù)據(jù)存儲(chǔ)和物聯(lián)網(wǎng)等。

        二.  應(yīng)用場(chǎng)景

        MinIO是一種高性能、擴(kuò)展性好的對(duì)象存儲(chǔ)系統(tǒng),它可以適用于許多應(yīng)用場(chǎng)景,其中包括但不限于以下幾種:

        • 大規(guī)模數(shù)據(jù)存儲(chǔ): 由于MinIO使用分布式環(huán)境來(lái)存儲(chǔ)數(shù)據(jù),因此可以輕松擴(kuò)展以滿足需要管理大量數(shù)據(jù)的組織和企業(yè)的需求。

        • 圖像和媒體存儲(chǔ): 由于MinIO對(duì)原始二進(jìn)制數(shù)據(jù)進(jìn)行了優(yōu)化,因此非常適合存儲(chǔ)圖像、音頻和視頻等媒體文件。它還支持WebP、JPEG和PNG等格式,可在多種設(shè)備和瀏覽器上工作。

        • 云原生應(yīng)用程序: MinIO是一個(gè)云原生的對(duì)象存儲(chǔ)系統(tǒng),可以與Kubernetes、Docker Swarm和Mesosphere等容器編排工具無(wú)縫集成,可以很好地滿足基于云的應(yīng)用程序的需求。

        • 數(shù)據(jù)保護(hù)和災(zāi)難恢復(fù): MinIO的多副本寫入功能和內(nèi)置的糾刪碼支持,使得數(shù)據(jù)備份和恢復(fù)變得簡(jiǎn)單而強(qiáng)大。

        • 分布式計(jì)算和機(jī)器學(xué)習(xí): MinIO提供STS(S3 Select)和HDFS接口,支持在數(shù)據(jù)倉(cāng)庫(kù)中直接運(yùn)行SQL查詢和MapReduce等并行處理框架。這使得它成為用于Big Data、AI和ML等分布式計(jì)算任務(wù)的理想選擇。

        需要注意的是,以上列出的應(yīng)用場(chǎng)景并不是MinIO所有可適用的場(chǎng)景。具體取決于每個(gè)使用情況的細(xì)節(jié)和需求。

        三.  Minio實(shí)現(xiàn)分片上傳的主要步驟

        使用SpringBoot和MinIO實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳主要包含以下幾個(gè)步驟:

        • 前端選擇文件并對(duì)其進(jìn)行切割: 可以使用JavaScript等前端技術(shù)將文件切成多個(gè)片段,并為每個(gè)片段生成唯一標(biāo)識(shí)。

        • 將每個(gè)分片上傳到MinIO對(duì)象存儲(chǔ): 調(diào)用MinIO的Java SDK將每個(gè)分片上傳到MinIO中,每個(gè)分片的KEY名稱包含基礎(chǔ)名稱和片段ID。

        • 將所有分片合并成最終文件: 在前端完成所有分片的上傳之后,在后臺(tái)開(kāi)發(fā)一個(gè)接口,按照唯一標(biāo)識(shí)將所有分片合并成最終文件。合并過(guò)程可以在應(yīng)用服務(wù)器上完成,也可以使用MinIO Object Storage本身的合并功能完成。

        • 實(shí)現(xiàn)秒傳: 在前端上傳分片之前,通過(guò)請(qǐng)求后臺(tái)接口來(lái)根據(jù)文件名稱和文件MD5值判斷該文件是否已經(jīng)存在,如果存在則可以直接返回文件URL,即可實(shí)現(xiàn)秒傳。

        • 實(shí)現(xiàn)續(xù)傳: 在前端上傳分片時(shí)出現(xiàn)了網(wǎng)絡(luò)問(wèn)題或客戶端故障導(dǎo)致文件上傳被中斷,這時(shí)候只需記錄已上傳的分片序列號(hào)和狀態(tài)標(biāo)志,從下一個(gè)分片重新開(kāi)始上傳即可。

        • 處理錯(cuò)誤和異常: 在文件上傳過(guò)程中可能會(huì)遇到各種問(wèn)題,比如服務(wù)故障、網(wǎng)絡(luò)中斷、客戶端處理超時(shí)等。因此需要加入錯(cuò)誤和異常處理,保證整個(gè)上傳過(guò)程順利進(jìn)行。

        總體而言,使用SpringBoot和MinIO實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳的難度不算大,可以根據(jù)上述步驟進(jìn)行開(kāi)發(fā)和實(shí)現(xiàn)。

        四. Centos7安裝Minio

        創(chuàng)建目標(biāo)文件夾

        mkdir minio

        使用docker查看目標(biāo)鏡像狀況

        大家需要注意,此處我們首先需要安裝docker,對(duì)于相關(guān)安裝教程,大家可以查看我之前的文章,按部就班就可以,此處不再贅述!??!

        docker search minio

        使用docker拉去鏡像

        docker pull minio/minio

        查看鏡像是否拉取成功

        docker images

        啟動(dòng)Minio容器

        docker run -p 9000:9000 -p 9090:9090      --net=host      --name minio      -d --restart=always      -e "MINIO_ACCESS_KEY=IT@WangHui"      -e "MINIO_SECRET_KEY=IT@WangHui"            minio/minio server      /data --console-address ":9000" -address ":9090"

        注意一下,對(duì)于密碼強(qiáng)度是有要求的,不然報(bào)錯(cuò)

        這是一個(gè)運(yùn)行 MinIO 容器的 Docker 命令,具體參數(shù)解釋如下:

        • -p: 映射容器內(nèi)部的端口到宿主機(jī)上。其中 9000 和 9090 分別映射到宿主機(jī)的 9000 和 9090 端口上。

        • --net=host: 將容器加入到主機(jī)網(wǎng)絡(luò)中,共享宿主機(jī)的 IP 地址。

        • --name minio: 指定容器的名稱為 minio。

        • --restart=always: 設(shè)置容器在退出后自動(dòng)重新啟動(dòng)。

        • -e: 設(shè)置環(huán)境變量。這里設(shè)置了兩個(gè)環(huán)境變量:MINIO_ACCESS_KEYMINIO_SECRET_KEY,值分別為 IT@WangHuiIT@WangHui

        • --mount: 將容器內(nèi)部的目錄掛載到宿主機(jī)上。這里將容器內(nèi)的 /data 目錄掛載到了宿主機(jī)的 /data 目錄上。

        • --console-address: 指定容器的控制臺(tái)地址。這里設(shè)置為 :9000,表示可以通過(guò)宿主機(jī)上的 9000 端口訪問(wèn)容器的控制臺(tái)。

        • -address: 指定容器的網(wǎng)絡(luò)地址。這里設(shè)置為 :9090,表示可以通過(guò)宿主機(jī)上的 9090 端口訪問(wèn)容器的服務(wù)。

        提示:頁(yè)面訪問(wèn)9000,代碼里面9090

        提示:頁(yè)面訪問(wèn)9000,代碼里面9090

        提示:頁(yè)面訪問(wèn)9000,代碼里面9090

        報(bào)錯(cuò)警告
        原因:

        主要是因?yàn)樵趩?dòng)docker容器的時(shí)候或做docker配置的時(shí)候,還對(duì)防火墻設(shè)置重新啟動(dòng)等配置,這樣會(huì)清除docker的相關(guān)配置,導(dǎo)致在查詢防火墻規(guī)則的時(shí)候顯示不到docker的鏈。iptables -L查詢iptables鏈。

        解決:

        是由于firewalld重啟導(dǎo)致,而docker重啟又會(huì)將其注冊(cè)iptables鏈找回來(lái)。

        然后刪除剛才啟動(dòng)失敗的容器,不然會(huì)繼續(xù)報(bào)錯(cuò)容器已存在

        systemctl restart docker #重啟docker
        docker ps -a #查看運(yùn)行容器
        docker rm -f minio #根據(jù)容器名刪除容器(自己注意辨別自己的)

        當(dāng)啟動(dòng)后在瀏覽器訪問(wèn)http://localhost:9000就可以訪問(wèn)minio的圖形化界面了,如圖所示:

        用戶名密碼就是啟動(dòng)參數(shù)里面的數(shù)據(jù)

        如果訪問(wèn)失敗,那就是防火墻問(wèn)題或者是啟動(dòng)參數(shù)最后兩項(xiàng)沒(méi)有添加,再不會(huì)有其他的,除非容器沒(méi)有啟動(dòng)成功

        查看放行端口可以使用如下命令

         firewall-cmd --list-ports

        要放行CentOS 7上的9000端口和9090端口,您可以按照以下步驟操作:

        1.檢查防火墻狀態(tài)

        使用以下命令檢查防火墻狀態(tài):

        systemctl status firewalld

        如果防火墻已停止,則啟動(dòng)它:

        systemctl start firewalld
        2.允許9000端口通過(guò)防火墻

        使用以下命令允許TCP流量通過(guò)9000端口:

        firewall-cmd --zone=public --add-port=9000/tcp --permanent
        firewall-cmd --zone=public --add-port=9090/tcp --permanent

        這將向防火墻添加一個(gè)規(guī)則,以允許TCP流量通過(guò)9000端口。要永久保存此更改,請(qǐng)運(yùn)行以下命令:

        firewall-cmd --reload
        3.重新啟動(dòng)防火墻服務(wù)shell

        使用以下命令重新啟動(dòng)防火墻服務(wù):

        systemctl restart firewalld

        現(xiàn)在,您已經(jīng)成功地放行了CentOS 7上的9000和9090端口。

        五. 搭建springboot 環(huán)境

        代碼結(jié)構(gòu)

        引入項(xiàng)目依賴

        <!-- 操作minio的java客戶端-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.2</version>
        </dependency>
        <!-- 操作minio的java客戶端-->
         <dependency>
            <groupId>io.minio</groupId>
             <artifactId>minio</artifactId>
             <version>8.2.1</version>
        </dependency>
        <!--        jwt鑒權(quán)相應(yīng)依賴-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.2</version>
        </dependency>

        創(chuàng)建容器桶

        獲取API訪問(wèn)憑證

        編寫配置文件

        server:
            port: 8080
        spring:
            servlet:
                multipart:
                    max-file-size: 10MB
                    max-request-size: 10MB
            #minio配置
            minio:
                access-key: dAMaxkWaXUD1CV1JHbqw
                secret-key: AXt3SD0JFkDENFbMeJKOOQb5wj8KvabZWu33Rs84
                url: http://192.168.18.14:9090  #訪問(wèn)地址
                bucket-name: wanghui

        首先是服務(wù)器的配置:

        • 端口號(hào)為8080,用于監(jiān)聽(tīng)請(qǐng)求。

        • 使用了一個(gè)Servlet來(lái)處理multipart/form-data類型的請(qǐng)求。

        • 在接收到multipart/form-data類型的請(qǐng)求時(shí),會(huì)將上傳的文件大小限制在10MB以內(nèi),并將請(qǐng)求大小限制在10MB以內(nèi)。

        接下來(lái)是minio的配置:

        • access-keysecret-key是訪問(wèn)minio服務(wù)的憑證,需要根據(jù)實(shí)際情況進(jìn)行填寫。

        • url是minio服務(wù)的地址,需要根據(jù)實(shí)際情況進(jìn)行填寫。

        • bucket-name是存儲(chǔ)文件的桶名,需要根據(jù)實(shí)際情況進(jìn)行填寫。

        http請(qǐng)求狀態(tài)

        package com.xiaohui.utils;

        /**
         * @Description http請(qǐng)求狀態(tài)
         * @Author IT小輝同學(xué)
         * @Date 2023/06/01
         */

        public class HttpStatus
        {
            /**
             * 操作成功
             */

            public static final int SUCCESS = 200;

            /**
             * 對(duì)象創(chuàng)建成功
             */

            public static final int CREATED = 201;

            /**
             * 請(qǐng)求已經(jīng)被接受
             */

            public static final int ACCEPTED = 202;

            /**
             * 操作已經(jīng)執(zhí)行成功,但是沒(méi)有返回?cái)?shù)據(jù)
             */

            public static final int NO_CONTENT = 204;

            /**
             * 資源已被移除
             */

            public static final int MOVED_PERM = 301;

            /**
             * 重定向
             */

            public static final int SEE_OTHER = 303;

            /**
             * 資源沒(méi)有被修改
             */

            public static final int NOT_MODIFIED = 304;

            /**
             * 參數(shù)列表錯(cuò)誤(缺少,格式不匹配)
             */

            public static final int BAD_REQUEST = 400;

            /**
             * 未授權(quán)
             */

            public static final int UNAUTHORIZED = 401;

            /**
             * 訪問(wèn)受限,授權(quán)過(guò)期
             */

            public static final int FORBIDDEN = 403;

            /**
             * 資源,服務(wù)未找到
             */

            public static final int NOT_FOUND = 404;

            /**
             * 不允許的http方法
             */

            public static final int BAD_METHOD = 405;

            /**
             * 資源沖突,或者資源被鎖
             */

            public static final int CONFLICT = 409;

            /**
             * 不支持的數(shù)據(jù),媒體類型
             */

            public static final int UNSUPPORTED_TYPE = 415;

            /**
             * 系統(tǒng)內(nèi)部錯(cuò)誤
             */

            public static final int ERROR = 500;

            /**
             * 接口未實(shí)現(xiàn)
             */

            public static final int NOT_IMPLEMENTED = 501;

            /**
             * 系統(tǒng)警告消息
             */

            public static final int WARN = 601;
        }

        通用常量信息

        package com.xiaohui.utils;

        import io.jsonwebtoken.Claims;

        /**
         * @Description 通用常量信息
         * @Author IT小輝同學(xué)
         * @Date 2023/06/01
         */

        public class Constants
        {
            /**
             * UTF-8 字符集
             */

            public static final String UTF8 = "UTF-8";

            /**
             * GBK 字符集
             */

            public static final String GBK = "GBK";

            /**
             * www主域
             */

            public static final String WWW = "www.";

            /**
             * http請(qǐng)求
             */

            public static final String HTTP = "http://";

            /**
             * https請(qǐng)求
             */

            public static final String HTTPS = "https://";

            /**
             * 通用成功標(biāo)識(shí)
             */

            public static final String SUCCESS = "0";

            /**
             * 通用失敗標(biāo)識(shí)
             */

            public static final String FAIL = "1";

            /**
             * 登錄成功
             */

            public static final String LOGIN_SUCCESS = "Success";

            /**
             * 注銷
             */

            public static final String LOGOUT = "Logout";

            /**
             * 注冊(cè)
             */

            public static final String REGISTER = "Register";

            /**
             * 登錄失敗
             */

            public static final String LOGIN_FAIL = "Error";
         
            /**
             * 驗(yàn)證碼有效期(分鐘)
             */

            public static final Integer CAPTCHA_EXPIRATION = 2;

            /**
             * 令牌
             */

            public static final String TOKEN = "token";

            /**
             * 令牌前綴
             */

            public static final String TOKEN_PREFIX = "Bearer ";

            /**
             * 令牌前綴
             */

            public static final String LOGIN_USER_KEY = "login_user_key";

            /**
             * 用戶ID
             */

            public static final String JWT_USERID = "userid";

            /**
             * 用戶名稱
             */

            public static final String JWT_USERNAME = Claims.SUBJECT;

            /**
             * 用戶頭像
             */

            public static final String JWT_AVATAR = "avatar";

            /**
             * 創(chuàng)建時(shí)間
             */

            public static final String JWT_CREATED = "created";

            /**
             * 用戶權(quán)限
             */

            public static final String JWT_AUTHORITIES = "authorities";

            /**
             * 資源映射路徑 前綴
             */

            public static final String RESOURCE_PREFIX = "/profile";

            /**
             * RMI 遠(yuǎn)程方法調(diào)用
             */

            public static final String LOOKUP_RMI = "rmi:";

            /**
             * LDAP 遠(yuǎn)程方法調(diào)用
             */

            public static final String LOOKUP_LDAP = "ldap:";

            /**
             * LDAPS 遠(yuǎn)程方法調(diào)用
             */

            public static final String LOOKUP_LDAPS = "ldaps:";

            /**
             * 定時(shí)任務(wù)白名單配置(僅允許訪問(wèn)的包名,如其他需要可以自行添加)
             */

            public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };

            /**
             * 定時(shí)任務(wù)違規(guī)的字符
             */

            public static final String[] JOB_ERROR_STR = { "java.net.URL""javax.naming.InitialContext""org.yaml.snakeyaml",
                    "org.springframework""org.apache""com.ruoyi.common.utils.file""com.ruoyi.common.config" };
        }

        創(chuàng)建Minio的配置類

        package com.xiaohui.config;

        import io.minio.MinioClient;
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;

        /**
         * @Description minio配置
         * @Author IT小輝同學(xué)
         * @Date 2023/06/02
         */

        @Data
        @Configuration
        @ConfigurationProperties(prefix = "spring.minio")
        public class MinioConfig {
            private String accessKey;

            private String secretKey;

            private String url;

            private String bucketName;

            @Bean
            public MinioClient minioClient(){
                return MinioClient.builder()
                        .endpoint(url)
                        .credentials(accessKey,secretKey)
                        .build();
            }
        }

        這段代碼是Java中的一個(gè)配置類,用于配置與MinIO(一個(gè)對(duì)象存儲(chǔ)服務(wù))相關(guān)的屬性。具體來(lái)說(shuō):

        • @Configuration注解表示這是一個(gè)配置類,用于將該類中定義的屬性注入到其他組件中使用。

        • @ConfigurationProperties注解表示該類使用了spring.minio.*前綴的屬性來(lái)配置Minio相關(guān)的屬性。

        • @Data注解表示自動(dòng)生成getter和setter方法,簡(jiǎn)化了代碼編寫。

        • accessKeysecretKey屬性分別表示訪問(wèn)密鑰和密鑰值,用于連接到MinIO服務(wù)。

        • url屬性表示MinIO服務(wù)的URL地址。

        • bucketName屬性表示存儲(chǔ)桶名稱。

        • @Bean注解表示將minioClient()方法返回的對(duì)象注冊(cè)為bean,以便在其他組件中使用。

        • minioClient()方法返回了一個(gè)MinioClient對(duì)象,用于連接到MinIO服務(wù)并操作存儲(chǔ)桶。其中,endpoint()方法用于設(shè)置MinIO服務(wù)的URL地址,credentials()方法用于設(shè)置訪問(wèn)密鑰和密鑰值。

        創(chuàng)建Minio的工具類

        package com.xiaohui.utils;


        import com.xiaohui.config.MinioConfig;
        import io.minio.*;
        import io.minio.errors.*;
        import io.minio.http.Method;
        import lombok.SneakyThrows;
        import org.apache.tomcat.util.http.fileupload.IOUtils;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.http.HttpHeaders;
        import org.springframework.http.MediaType;
        import org.springframework.http.ResponseEntity;
        import org.springframework.stereotype.Component;
        import org.springframework.web.multipart.MultipartFile;

        import java.io.ByteArrayOutputStream;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.UnsupportedEncodingException;
        import java.net.URLEncoder;
        import java.security.InvalidKeyException;
        import java.security.NoSuchAlgorithmException;
        import java.time.ZonedDateTime;
        import java.util.Arrays;
        import java.util.HashMap;
        import java.util.Map;
        import java.util.concurrent.TimeUnit;

        /**
         * @Description Minio工具類
         * @Author IT小輝同學(xué)
         * @Date 2023/06/02
         */


        @Component
        public class MinioUtils {

            @Autowired
            private MinioClient minioClient;

            @Autowired
            private MinioConfig configuration;

            /**
             * @param name 名字
             * @return boolean
             * @Description description: 判斷bucket是否存在,不存在則創(chuàng)建
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public boolean existBucket(String name) {
                boolean exists;
                try {
                    exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
                    if (!exists) {
                        minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
                        exists = true;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    exists = false;
                }
                return exists;
            }

            /**
             * @param bucketName 存儲(chǔ)bucket名稱
             * @return {@link Boolean }
             * @Description 創(chuàng)建存儲(chǔ)bucket
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public Boolean makeBucket(String bucketName) {
                try {
                    minioClient.makeBucket(MakeBucketArgs.builder()
                            .bucket(bucketName)
                            .build());
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
                return true;
            }

            /**
             * @param bucketName 存儲(chǔ)bucket名稱
             * @return {@link Boolean }
             * @Description 刪除存儲(chǔ)bucket
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public Boolean removeBucket(String bucketName) {
                try {
                    minioClient.removeBucket(RemoveBucketArgs.builder()
                            .bucket(bucketName)
                            .build());
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
                return true;
            }

            /**
             * @param fileName 文件名稱
             * @param time     時(shí)間
             * @return {@link Map }
             * @Description 獲取上傳臨時(shí)簽名
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            @SneakyThrows
            public Map getPolicy(String fileName, ZonedDateTime time) {
                PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
                postPolicy.addEqualsCondition("key", fileName);
                try {
                    Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
                    HashMap<String, String> map1 = new HashMap<>();
                    map.forEach((k, v) -> {
                        map1.put(k.replaceAll("-"""), v);
                    });
                    map1.put("host", configuration.getUrl() + "/" + configuration.getBucketName());
                    return map1;
                } catch (ErrorResponseException e) {
                    e.printStackTrace();
                } catch (InsufficientDataException e) {
                    e.printStackTrace();
                } catch (InternalException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (InvalidResponseException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (ServerException e) {
                    e.printStackTrace();
                } catch (XmlParserException e) {
                    e.printStackTrace();
                }
                return null;
            }

            /**
             * @param objectName 對(duì)象名稱
             * @param method     方法
             * @param time       時(shí)間
             * @param timeUnit   時(shí)間單位
             * @return {@link String }
             * @Description 獲取上傳文件的url
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {
                try {
                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(method)
                            .bucket(configuration.getBucketName())
                            .object(objectName)
                            .expiry(time, timeUnit).build());
                } catch (ErrorResponseException e) {
                    e.printStackTrace();
                } catch (InsufficientDataException e) {
                    e.printStackTrace();
                } catch (InternalException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (InvalidResponseException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (XmlParserException e) {
                    e.printStackTrace();
                } catch (ServerException e) {
                    e.printStackTrace();
                }
                return null;
            }


            /**
             * @param file     文件
             * @param fileName 文件名稱
             * @Description 上傳文件
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public void upload(MultipartFile file, String fileName) {
                // 使用putObject上傳一個(gè)文件到存儲(chǔ)桶中。
                try {
                    InputStream inputStream = file.getInputStream();
                    minioClient.putObject(PutObjectArgs.builder()
                            .bucket(configuration.getBucketName())
                            .object(fileName)
                            .stream(inputStream, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());
                } catch (ErrorResponseException e) {
                    e.printStackTrace();
                } catch (InsufficientDataException e) {
                    e.printStackTrace();
                } catch (InternalException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (InvalidResponseException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (ServerException e) {
                    e.printStackTrace();
                } catch (XmlParserException e) {
                    e.printStackTrace();
                }
            }

            /**
             * @param objectName 對(duì)象名稱
             * @param time       時(shí)間
             * @param timeUnit   時(shí)間單位
             * @return {@link String }
             * @Description 根據(jù)filename獲取文件訪問(wèn)地址
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public String getUrl(String objectName, int time, TimeUnit timeUnit) {
                String url = null;
                try {
                    url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(configuration.getBucketName())
                            .object(objectName)
                            .expiry(time, timeUnit).build());
                } catch (ErrorResponseException e) {
                    e.printStackTrace();
                } catch (InsufficientDataException e) {
                    e.printStackTrace();
                } catch (InternalException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (InvalidResponseException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (XmlParserException e) {
                    e.printStackTrace();
                } catch (ServerException e) {
                    e.printStackTrace();
                }
                return url;
            }

            /**
             * @param fileName
             * @return {@link ResponseEntity }<{@link byte[] }>
             * @Description description: 下載文件
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public ResponseEntity<byte[]> download(String fileName) {
                ResponseEntity<byte[]> responseEntity = null;
                InputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = minioClient.getObject(GetObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).build());
                    out = new ByteArrayOutputStream();
                    IOUtils.copy(in, out);
                    //封裝返回值
                    byte[] bytes = out.toByteArray();
                    HttpHeaders headers = new HttpHeaders();
                    try {
                        headers.add("Content-Disposition""attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    headers.setContentLength(bytes.length);
                    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                    headers.setAccessControlExposeHeaders(Arrays.asList("*"));
                    responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.SUCCESS);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (in != null) {
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (out != null) {
                            out.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return responseEntity;
            }

            /**
             * @param objectFile 對(duì)象文件
             * @return {@link String }
             * @Description 根據(jù)文件名和桶獲取文件路徑
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            public String getFileUrl(String objectFile) {
                try {

                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(configuration.getBucketName())
                            .object(objectFile)
                            .build()
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return null;
            }


        }

        該代碼是一個(gè)工具類,用于使用阿里云的對(duì)象存儲(chǔ)服務(wù)(OSS)進(jìn)行文件上傳和下載。具體功能如下:

        • getPolicy(String fileName, ZonedDateTime time):根據(jù)文件名和時(shí)間戳獲取上傳臨時(shí)簽名。

        • getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit):獲取上傳文件的url。

        • upload(MultipartFile file, String fileName):將文件上傳到OSS中。

        • getUrl(String objectName, int time, TimeUnit timeUnit):獲取文件的下載url。

        代碼中使用了枚舉類型來(lái)定義不同的上傳和下載方法。

        使用了注解@Autowired來(lái)自動(dòng)注入MinioClient對(duì)象。

        該工具類沒(méi)有提供異常處理機(jī)制,需要根據(jù)實(shí)際情況進(jìn)行補(bǔ)充。

        創(chuàng)建Ajax請(qǐng)求工具類


        /**
         * @Description ajax結(jié)果
         * @Author IT小輝同學(xué)
         * @Date 2023/06/01
         */

        public class AjaxResult extends HashMap<StringObject>
        {
            private static final long serialVersionUID = 1L;

            /** 狀態(tài)碼 */
            public static final String CODE_TAG = "code";

            /** 返回內(nèi)容 */
            public static final String MSG_TAG = "msg";

            /** 數(shù)據(jù)對(duì)象 */
            public static final String DATA_TAG = "data";

            /**
             * 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象,使其表示一個(gè)空消息。
             */

            public AjaxResult()
            
        {
            }

            /**
             * 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象
             *
             * @param code 狀態(tài)碼
             * @param msg 返回內(nèi)容
             */

            public AjaxResult(int code, String msg)
            
        {
                super.put(CODE_TAG, code);
                super.put(MSG_TAG, msg);
            }

            /**
             * 初始化一個(gè)新創(chuàng)建的 AjaxResult 對(duì)象
             *
             * @param code 狀態(tài)碼
             * @param msg 返回內(nèi)容
             * @param data 數(shù)據(jù)對(duì)象
             */

            public AjaxResult(int code, String msg, Object data)
            
        {
                super.put(CODE_TAG, code);
                super.put(MSG_TAG, msg);
                if (data!=null)
                {
                    super.put(DATA_TAG, data);
                }
            }

            /**
             * 返回成功消息
             *
             * @return 成功消息
             */

            public static AjaxResult success()
            
        {
                return AjaxResult.success("操作成功");
            }

            /**
             * 返回成功數(shù)據(jù)
             *
             * @return 成功消息
             */

            public static AjaxResult success(Object data)
            
        {
                return AjaxResult.success("操作成功", data);
            }

            /**
             * 返回成功消息
             *
             * @param msg 返回內(nèi)容
             * @return 成功消息
             */

            public static AjaxResult success(String msg)
            
        {
                return AjaxResult.success(msg, null);
            }

            /**
             * 返回成功消息
             *
             * @param msg 返回內(nèi)容
             * @param data 數(shù)據(jù)對(duì)象
             * @return 成功消息
             */

            public static AjaxResult success(String msg, Object data)
            
        {
                return new AjaxResult(HttpStatus.SUCCESS, msg, data);
            }

            /**
             * 返回警告消息
             *
             * @param msg 返回內(nèi)容
             * @return 警告消息
             */

            public static AjaxResult warn(String msg)
            
        {
                return AjaxResult.warn(msg, null);
            }

            /**
             * 返回警告消息
             *
             * @param msg 返回內(nèi)容
             * @param data 數(shù)據(jù)對(duì)象
             * @return 警告消息
             */

            public static AjaxResult warn(String msg, Object data)
            
        {
                return new AjaxResult(HttpStatus.WARN, msg, data);
            }

            /**
             * 返回錯(cuò)誤消息
             *
             * @return 錯(cuò)誤消息
             */

            public static AjaxResult error()
            
        {
                return AjaxResult.error("操作失敗");
            }

            /**
             * 返回錯(cuò)誤消息
             *
             * @param msg 返回內(nèi)容
             * @return 錯(cuò)誤消息
             */

            public static AjaxResult error(String msg)
            
        {
                return AjaxResult.error(msg, null);
            }

            /**
             * 返回錯(cuò)誤消息
             *
             * @param msg 返回內(nèi)容
             * @param data 數(shù)據(jù)對(duì)象
             * @return 錯(cuò)誤消息
             */

            public static AjaxResult error(String msg, Object data)
            
        {
                return new AjaxResult(HttpStatus.ERROR, msg, data);
            }

            /**
             * 返回錯(cuò)誤消息
             *
             * @param code 狀態(tài)碼
             * @param msg 返回內(nèi)容
             * @return 錯(cuò)誤消息
             */

            public static AjaxResult error(int code, String msg)
            
        {
                return new AjaxResult(code, msg, null);
            }

            /**
             * 方便鏈?zhǔn)秸{(diào)用
             *
             * @param key 鍵
             * @param value 值
             * @return 數(shù)據(jù)對(duì)象
             */

            @Override
            public AjaxResult put(String key, Object value)
            
        {
                super.put(key, value);
                return this;
            }
        }

        創(chuàng)建Minio文件操作接口層

        package com.xiaohui.controller;

        import com.xiaohui.utils.AjaxResult;
        import com.xiaohui.utils.MinioUtils;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.http.ResponseEntity;
        import org.springframework.web.bind.annotation.*;
        import org.springframework.web.multipart.MultipartFile;

        import java.util.HashMap;

        /**
         * @Description minio文件上傳控制器
         * @Author IT小輝同學(xué)
         * @Date 2023/06/02
         */

        @CrossOrigin
        @RestController
        @RequestMapping("/api")
        public class MinioFileUploadController {
            @Autowired
            private MinioUtils minioUtils;

            /**
             * @param file     文件
             * @param fileName 文件名稱
             * @return {@link AjaxResult }
             * @Description 上傳文件
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            @GetMapping("/upload")
            public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, String fileName) {

                minioUtils.upload(file, fileName);
                return AjaxResult.success("上傳成功");

            }

            /**
             * @param fileName 文件名稱
             * @return {@link ResponseEntity }
             * @Description dowload文件
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            @GetMapping("/dowload")
            public ResponseEntity dowloadFile(@RequestParam("fileName") String fileName) {
                return minioUtils.download(fileName);
            }

            /**
             * @param fileName 文件名稱
             * @return {@link AjaxResult }
             * @Description 得到文件url
             * @Author IT小輝同學(xué)
             * @Date 2023/06/02
             */

            @GetMapping("/getUrl")
            public AjaxResult getFileUrl(@RequestParam("fileName") String fileName){
                HashMap map=new HashMap();
                map.put("FileUrl",minioUtils.getFileUrl(fileName));
                return AjaxResult.success(map);
            }
        }

        六. 功能測(cè)試

        Minio大文件上傳

        Minio大文件地址


        程序汪接私活項(xiàng)目目錄,2023年總結(jié)

        Java項(xiàng)目分享  最新整理全集,找項(xiàng)目不累啦 07版

        程序汪10萬(wàn)接的無(wú)線共享充電寶項(xiàng)目,開(kāi)發(fā)周期3個(gè)月

        程序汪1萬(wàn)接的企業(yè)官網(wǎng)項(xiàng)目,開(kāi)發(fā)周期15天

        程序汪8萬(wàn)接的共享口罩項(xiàng)目,開(kāi)發(fā)周期1個(gè)月

        程序汪8萬(wàn)塊的飲水機(jī)物聯(lián)網(wǎng)私活項(xiàng)目經(jīng)驗(yàn)分享

        程序汪接的4萬(wàn)智慧餐飲項(xiàng)目

        程序汪接的酒店在線開(kāi)房項(xiàng)目,另外一個(gè)好聽(tīng)的名字叫智慧酒店


        歡迎添加程序汪個(gè)人微信 itwang008  進(jìn)粉絲群或圍觀朋友圈

        瀏覽 346
        3點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        3點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            看韩国黄色片 | 熟女人妻久久久一区二区蜜桃老牛 | 伊人网五月天在线 | 揉我胸 啊 嗯出奶了黄 | 性xxxxfreexxxxx高跟鞋 | 日产国产欧美一区二区三区app | 97精品久久久 | 在线无码国产一区二区三区性色 | 日韩无码1 | 国产wwwww |