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

SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能

 更新時(shí)間:2024年07月17日 09:45:11   作者:NEIL_XU_  
最近有一個(gè)需求是關(guān)于視頻上傳播放的,需要設(shè)計(jì)一個(gè)方案,中間談到了Minio這個(gè)技術(shù),于是來學(xué)習(xí)一下,所以本文給大家介紹了SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下

最近公司有一個(gè)需求是關(guān)于視頻上傳播放的,需要設(shè)計(jì)一個(gè)方案,中間談到了Minio這個(gè)技術(shù),于是來學(xué)習(xí)一下

一、簡(jiǎn)介

1.分布式文件系統(tǒng)應(yīng)用場(chǎng)景

互聯(lián)網(wǎng)海量非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)需求

  • 電商網(wǎng)絡(luò):海量商品圖片
  • 視頻網(wǎng)站:海量視頻文件
  • 網(wǎng)盤:海量文件
  • 社交網(wǎng)站:海量圖片

2.Minio介紹

  • Go語言開發(fā),開源,免費(fèi)的對(duì)象存儲(chǔ)服務(wù),可以存儲(chǔ)海量非結(jié)構(gòu)化的數(shù)據(jù),一個(gè)對(duì)象文件可以是任意大小,從幾kb到最大5T不等

3.Minio優(yōu)點(diǎn)

  • 部署簡(jiǎn)單
  • 讀寫性能優(yōu)異
  • 支持海量存儲(chǔ)

二、docker部署(windows系統(tǒng))

這里我是用自己電腦(windows系統(tǒng))安裝了docker,然后使用docker來部署的

中文官網(wǎng)單節(jié)點(diǎn)多硬盤部署MinIO — MinIO中文文檔 | MinIO Container中文文檔

1.創(chuàng)建目錄

先進(jìn)入D盤,創(chuàng)建docker的工作目錄 docker_workplace,再創(chuàng)建minio的目錄minio,再創(chuàng)建兩個(gè)文件夾dataconfig,如圖所示

在這里插入圖片描述

拉取鏡像,創(chuàng)建容器并運(yùn)行

2.拉取鏡像

直接cmd,敲docker命令即可,和linux的語法一樣

在這里插入圖片描述

3.創(chuàng)建容器并運(yùn)行

多行:

docker run -d --name minio \
--privileged=true \
--restart=always \
-p 9000:9000 -p 50000:50000 \
-e "MINIO_ROOT_USER=minio" \
-e "MINIO_ROOT_PASSWORD=miniominio" \
-v D:/docker_workplace/data/minio/config:/root/.minio \
-v D:/docker_workplace/data/minio/data1:/data1 \
-v D:/docker_workplace/data/minio/data2:/data2 \
-v D:/docker_workplace/data/minio/data3:/data3 \
-v D:/docker_workplace/data/minio/data4:/data4 \
minio/minio \
server \
--console-address ":50000" /data{1...4}

單行:

docker run -p 9000:9000 -p 50000:50000 -d --name minio -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=miniominio" -v D:/docker_workplace/data/minio/config:/root/.minio -v D:/docker_workplace/data/minio/data1:/data1 -v D:/docker_workplace/data/minio/data2:/data2 -v D:/docker_workplace/data/minio/data3:/data3 -v D:/docker_workplace/data/minio/data4:/data4 --restart always minio/minio server --console-address ":50000" /data{1...4}

4.訪問控制臺(tái)

瀏覽器訪問:

http://localhost:50000/login

賬號(hào)/密碼(剛剛docker運(yùn)行命令設(shè)置的):minio/miniominio

這里我第一次訪問失敗了,看了下docker日志,發(fā)現(xiàn)是賬號(hào)密碼長(zhǎng)度不符合規(guī)范導(dǎo)致(一開始密碼是minio,達(dá)不到8個(gè)字符)

在這里插入圖片描述

于是改了密碼為miniominio,成功運(yùn)行

在這里插入圖片描述

5.初始化配置

創(chuàng)建一個(gè)桶 Bucket

在這里插入圖片描述

這里出現(xiàn)了一個(gè)報(bào)錯(cuò),原因是說需要分布式部署才能使用,解決辦法:掛載多個(gè)卷

在這里插入圖片描述

在這里插入圖片描述

配置桶權(quán)限為public

在這里插入圖片描述

到這里,minio單機(jī)版就部署好了

三、Spring Boot整合Minio

1.創(chuàng)建demo項(xiàng)目

新建一個(gè)spring boot項(xiàng)目

2.引入依賴

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.3.7</version>
</dependency>

3.配置

application.yml

spring:
  application:
    name: miniodemo
  servlet:
    multipart:
      # 文件上傳大小限制。超過該值直接報(bào)錯(cuò)
      max-file-size: 20MB
      # 文件最大請(qǐng)求限制,用于批量上傳
      max-request-size: 20MB
  datasource:
    url: jdbc:mysql://localhost:3306/minio?useSSL=false&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
# MinIO 配置
minio:
  endpoint: http://localhost:9000      # MinIO服務(wù)地址
  fileHost: http://localhost:9000      # 文件地址host
  bucketName: test                      # 存儲(chǔ)桶bucket名稱
  accessKey: minio                         # 用戶名
  secretKey: miniominio                     # 密碼
  imgSize: 20                           # 圖片大小限制,單位:m
  fileSize: 20                          # 文件大小限制,單位:m
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.xuyue.miniodemo.domain

4.編寫配置類

MinIOConfig.java

package com.xuyue.miniodemo.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
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;

    @Value("${minio.imgSize}")
    private Integer imgSize;
    @Value("${minio.fileSize}")
    private Integer fileSize;

}

5.MinIO工具類

MinIoUploadService.java

package com.xuyue.miniodemo.service;

import com.xuyue.miniodemo.config.MinIOConfig;
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.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
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
@Service
public class MinIoUploadService {

    @Resource
    private MinIOConfig minIOConfig;

    private MinioClient minioClient;

    private String endpoint;
    private String bucketName;
    private String accessKey;
    private String secretKey;
    private Integer imgSize;
    private Integer fileSize;


    private final String SEPARATOR = "/";

    @PostConstruct
    public void init() {
        this.endpoint = minIOConfig.getEndpoint();
        this.bucketName = minIOConfig.getBucketName();
        this.accessKey = minIOConfig.getAccessKey();
        this.secretKey = minIOConfig.getSecretKey();
        this.imgSize = minIOConfig.getImgSize();
        this.fileSize = minIOConfig.getFileSize();
        createMinioClient();
    }

    /**
     * 創(chuàng)建基于Java端的MinioClient
     */
    public void createMinioClient() {
        try {
            if (null == minioClient) {
                log.info("開始創(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 String getBasisUrl() {
        return endpoint + SEPARATOR + bucketName + SEPARATOR;
    }

    /******************************  Operate Bucket Start  ******************************/

    /**
     * 啟動(dòng)SpringBoot容器的時(shí)候初始化Bucket
     * 如果沒有Bucket則創(chuàng)建
     *
     * @throws Exception
     */
    private void createBucket(String bucketName) throws Exception {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 判斷Bucket是否存在,true:存在,false:不存在
     *
     * @return
     * @throws Exception
     */
    public boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }


    /**
     * 獲得Bucket的策略
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public String getBucketPolicy(String bucketName) throws Exception {
        String bucketPolicy = minioClient
                .getBucketPolicy(
                        GetBucketPolicyArgs
                                .builder()
                                .bucket(bucketName)
                                .build()
                );
        return bucketPolicy;
    }


    /**
     * 獲得所有Bucket列表
     *
     * @return
     * @throws Exception
     */
    public List<Bucket> getAllBuckets() throws Exception {
        return minioClient.listBuckets();
    }

    /**
     * 根據(jù)bucketName獲取其相關(guān)信息
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public 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 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 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 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 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 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 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 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 ObjectWriteResponse uploadFile(String bucketName, String objectName,
                                          String fileName) throws Exception {
        return minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .filename(fileName)
                        .build());
    }

    /**
     * 通過流上傳文件
     *
     * @param bucketName  存儲(chǔ)桶
     * @param objectName  文件對(duì)象
     * @param inputStream 文件流
     */
    public 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());
    }

    /**
     * 創(chuàng)建文件夾或目錄
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 目錄路徑
     */
    public 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());
    }

    /**
     * 獲取文件信息, 如果拋出異常則說明文件不存在
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名稱
     */
    public 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 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 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 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("批量刪除失??!error:{}", e);
            }
        });
    }

    /**
     * 獲取文件外鏈
     *
     * @param bucketName 存儲(chǔ)桶
     * @param objectName 文件名
     * @param expires    過期時(shí)間 <=7 秒 (外鏈有效時(shí)間(單位:秒))
     * @return url
     * @throws Exception
     */
    public 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 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 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  ******************************/


}

6.文件上傳

FileController.java

package com.xuyue.miniodemo.controller;

import com.xuyue.miniodemo.config.MinIOConfig;
import com.xuyue.miniodemo.service.MinIoUploadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@Slf4j
public class FileController {
    @Autowired
    private MinIoUploadService minIoUploadService;
    @Autowired
    private MinIOConfig minIOConfig;

    /**
     * 上傳文件,返回url
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("upload")
    public String upload(MultipartFile file) throws Exception {
        String fileName = file.getOriginalFilename();
        minIoUploadService.uploadFile(minIOConfig.getBucketName(), fileName, file.getInputStream());
        String imgUrl = minIOConfig.getFileHost()
                + "/"
                + minIOConfig.getBucketName()
                + "/"
                + fileName;

        return imgUrl;
    }

}

測(cè)試

啟動(dòng)項(xiàng)目

使用postman請(qǐng)求接口,返回文件地址

在這里插入圖片描述

訪問地址:

在這里插入圖片描述

查看minio控制臺(tái):

在這里插入圖片描述

以上就是SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Minio文件上傳讀取的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java怎么連接并訪問activemq

    java怎么連接并訪問activemq

    這篇文章主要介紹了java怎么連接并訪問activemq,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Java判斷對(duì)象是否為空的四種方法小結(jié)

    Java判斷對(duì)象是否為空的四種方法小結(jié)

    這篇文章主要介紹了Java判斷對(duì)象是否為空的四種方法,判斷對(duì)象是否為空有多種方法,包括使用==或!=運(yùn)算符直接比較對(duì)象與null,使用Objects.isNull()方法,以及用instanceof運(yùn)算符或Optional類進(jìn)行更安全的空值處理,需要的朋友可以參考下
    2024-10-10
  • Java常用集合之Set和Map的用法詳解

    Java常用集合之Set和Map的用法詳解

    這篇文章將通過一些示例為大家詳細(xì)介紹一下Java常用集合中Set和Map的用法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-07-07
  • 解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語句才能獲得結(jié)果

    解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerE

    這篇文章主要介紹了解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語句才能獲得結(jié)果,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 最新評(píng)論