<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 57959字,需瀏覽 116分鐘

           ·

          2024-07-01 11:41

          來源:juejin.cn/post/7304539173972983860

          一. 概述

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

          官網(wǎng)地址:

          https://min.io/

          文檔地址:

          https://docs.min.io/

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

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

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

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

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

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

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

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

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

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

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

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

          • 文件存儲: Minio還支持文件存儲,允許用戶上傳和下載單個文件。文件存儲是一種簡單、快速的方式來處理小型文件。

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

          二.  應(yīng)用場景

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          四. Centos7安裝Minio

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

          mkdir minio

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

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

          docker search minio

          使用docker拉去鏡像

          docker pull minio/minio

          查看鏡像是否拉取成功

          docker images

          啟動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"

          注意一下,對于密碼強(qiáng)度是有要求的,不然報錯

          這是一個運(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è)置容器在退出后自動重新啟動。

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

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

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

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

          提示:頁面訪問9000,代碼里面9090

          提示:頁面訪問9000,代碼里面9090

          提示:頁面訪問9000,代碼里面9090

          報錯警告
          原因:

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

          解決:

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

          然后刪除剛才啟動失敗的容器,不然會繼續(xù)報錯容器已存在

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

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

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

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

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

           firewall-cmd --list-ports

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

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

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

          systemctl status firewalld

          如果防火墻已停止,則啟動它:

          systemctl start firewalld
          2.允許9000端口通過防火墻

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

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

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

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

          使用以下命令重新啟動防火墻服務(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訪問憑證

          編寫配置文件

          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  #訪問地址
                  bucket-name: wanghui

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

          • 端口號為8080,用于監(jiān)聽請求。

          • 使用了一個Servlet來處理multipart/form-data類型的請求。

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

          接下來是minio的配置:

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

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

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

          http請求狀態(tài)

          package com.xiaohui.utils;

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

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

              public static final int SUCCESS = 200;

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

              public static final int CREATED = 201;

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

              public static final int ACCEPTED = 202;

              /**
               * 操作已經(jīng)執(zhí)行成功,但是沒有返回?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;

              /**
               * 資源沒有被修改
               */

              public static final int NOT_MODIFIED = 304;

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

              public static final int BAD_REQUEST = 400;

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

              public static final int UNAUTHORIZED = 401;

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

              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)部錯誤
               */

              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請求
               */

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

              /**
               * https請求
               */

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

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

              public static final String SUCCESS = "0";

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

              public static final String FAIL = "1";

              /**
               * 登錄成功
               */

              public static final String LOGIN_SUCCESS = "Success";

              /**
               * 注銷
               */

              public static final String LOGOUT = "Logout";

              /**
               * 注冊
               */

              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)建時間
               */

              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:";

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

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

              /**
               * 定時任務(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中的一個配置類,用于配置與MinIO(一個對象存儲服務(wù))相關(guān)的屬性。具體來說:

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

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

          • @Data注解表示自動生成getter和setter方法,簡化了代碼編寫。

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

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

          • bucketName屬性表示存儲桶名稱。

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

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

          創(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 存儲bucket名稱
               * @return {@link Boolean }
               * @Description 創(chuàng)建存儲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 存儲bucket名稱
               * @return {@link Boolean }
               * @Description 刪除存儲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     時間
               * @return {@link Map }
               * @Description 獲取上傳臨時簽名
               * @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 對象名稱
               * @param method     方法
               * @param time       時間
               * @param timeUnit   時間單位
               * @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上傳一個文件到存儲桶中。
                  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 對象名稱
               * @param time       時間
               * @param timeUnit   時間單位
               * @return {@link String }
               * @Description 根據(jù)filename獲取文件訪問地址
               * @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 對象文件
               * @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;
              }


          }

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

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

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

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

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

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

          使用了注解@Autowired來自動注入MinioClient對象。

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

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


          /**
           * @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ù)對象 */
              public static final String DATA_TAG = "data";

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

              public AjaxResult()
              
          {
              }

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

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

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

              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ù)對象
               * @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ù)對象
               * @return 警告消息
               */

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

              /**
               * 返回錯誤消息
               *
               * @return 錯誤消息
               */

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

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

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

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

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

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

              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ù)對象
               */

              @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);
              }
          }

          六. 功能測試

          Minio大文件上傳

          Minio大文件地址


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

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

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

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

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

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

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

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


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

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

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          3點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  特级日本欧美日韩亚洲精品综合免费在线 | 亚洲无免费码在线 | 色老板在线永久免费视频 | 极品美女后入 | 啪啪啪免费网站视频 |