springboot整合minio的超詳細(xì)教程
一、前言
在很多互聯(lián)網(wǎng)產(chǎn)品應(yīng)用中,都涉及到各種與文件存儲相關(guān)的業(yè)務(wù),隨著技術(shù)的發(fā)展,關(guān)于如何解決分布式文件存儲也有了比較成熟的方案,比如私有云部署下可以考慮fastdfs,阿里云對象存儲oss,七牛云等,本篇將為你介紹另一種文件存儲方式,即MinIO 。
二、Minio 概述
2.1 Minio簡介
MinIO基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),可以做為云存儲的解決方案用來保存海量的圖片,視頻,文檔,是一款高性能、分布式的對象存儲系統(tǒng), 可以100%的運(yùn)行在標(biāo)準(zhǔn)硬件,即X86等低成本機(jī)器也能夠很好的運(yùn)行MinIO。
傳統(tǒng)的存儲和其他的對象存儲不同的是:
它一開始就針對性能要求更高的私有云標(biāo)準(zhǔn)進(jìn)行軟件架構(gòu)設(shè)計。因?yàn)镸inIO一開始就只為對象存儲而設(shè)計。所以他采用了更易用的方式進(jìn)行設(shè)計,它能實(shí)現(xiàn)對象存儲所需要的全部功能,在性能上也更加強(qiáng)勁,它不會為了更多的業(yè)務(wù)功能而妥協(xié),失去MinIO的易用性、高效性。 這樣的結(jié)果所帶來的好處是:它能夠更簡單的實(shí)現(xiàn)局有彈性伸縮能力的原生對象存儲服務(wù)。
2.2 Minio特點(diǎn)
Minio具有如下特點(diǎn)
- 性能高,準(zhǔn)硬件條件下它能達(dá)到55GB/s的讀、35GB/s的寫速率;
- 部署自帶管理界面;
- MinIO.Inc運(yùn)營的開源項(xiàng)目,社區(qū)活躍度高;
- 提供了所有主流開發(fā)語言的SDK;
- 基于Golang語言實(shí)現(xiàn),配置簡單,單行命令可以運(yùn)行起來;
- 兼容亞馬遜S3云存儲服務(wù)接口,適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),一個對象文件可以是任意大小,從幾kb到最大5T不等;
三、Minio 環(huán)境搭建
本文采用docker的方式快速搭建起Minio的環(huán)境,也可以通過官網(wǎng)下載安裝包部署,官網(wǎng)安裝包下載地址
3.1 部署過程
3.1.1 拉取鏡像
docker pull minio/minio
3.1.2 啟動容器
docker run -d -p 9000:9000 -p 9090:9090 \ --name minio \ -e "MINIO_ACCESS_KEY=minio" \ -e "MINIO_SECRET_KEY=minio" \ -v /home/minio/data:/data \ -v /home/minio/config:/root/.minio \ minio/minio server \ /data --console-address ":9090" -address ":9000"
3.1.3 訪問web頁面
容器啟動成功后,注意開發(fā)相關(guān)的防火墻端口即可,然后訪問地址:IP:9000,即可訪問Minio的web界面
輸入賬戶和密碼,登錄進(jìn)去之后,看到下面的效果說明Minio環(huán)境搭建完成
四、Minio基本使用
4.1 基本概念
在正式開始使用Minio之前,有必要先了解下幾個相關(guān)的概念
- bucket ,類比于文件系統(tǒng)的目錄;
- Object ,類比文件系統(tǒng)的文件;
- Keys ,類比文件名;
4.2 上傳文件演示
如下,點(diǎn)擊創(chuàng)建一個新的bucket,創(chuàng)建完成后就可以在列表上看到這個bucket;
給當(dāng)前這個bucket上傳一個文件
點(diǎn)擊文件夾圖標(biāo)
上傳一張本地文件,上傳完成后就可以看到這個文件了,也可以瀏覽上傳的文件
4.3 用戶管理
針對客戶端的操作,經(jīng)常需要維護(hù)相關(guān)的賬號來管理,比如賬戶的操作權(quán)限,訪問控制等;
點(diǎn)擊,創(chuàng)建用戶
填寫用戶信息,勾選權(quán)限保存即可
然后在用戶列表就可以看到這個用戶了
4.4 Java操作Minio
通過上面的環(huán)境搭建和操作,演示并了解了如何快速使用Minio,更多的功能可以參閱相關(guān)資料進(jìn)一步學(xué)習(xí)了解,下面我們編寫java代碼完成文件的上傳。
4.4.1 導(dǎo)入依賴
在當(dāng)前的maven工程中導(dǎo)入minio的依賴,客戶端具體版本可以根據(jù)你的實(shí)際需要選擇
<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.1.0</version> </dependency>
4.4.2 上傳文件到minio
通過下面這段代碼將本地的一張圖片文件上傳到minio的test這個bucket目錄下
public static void main(String[] args) { FileInputStream inputStream = null; try { inputStream = new FileInputStream("F:\\網(wǎng)盤\\Title-logo.png"); MinioClient client = MinioClient.builder().credentials("minio", "minio").endpoint("http://IP:9000").build(); PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object("logo.png") .contentType("image/png") .bucket("test") .stream(inputStream, inputStream.available(), -1) .build(); client.putObject(putObjectArgs); System.out.println("上傳成功"); } catch (Exception e) { e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
運(yùn)行這段代碼,上傳成功后,去到test的目錄下刷新之后可以看到文件已經(jīng)上傳
五、springboot整合Minio
接下來讓我們看看如何在springboot中集成Minio,參考下面的操作步驟
5.1 前置準(zhǔn)備
5.1.1 引入依賴
創(chuàng)建一個maven工程,引入如下相關(guān)的依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.1.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
5.1.2 核心配置文件
在配置文件中添加如下內(nèi)容
server: port: 8087 logging: level: root: info com.congge.model: debug minio: username: minio pwd: minio bucket: test endpoint: http://IP:9000 readPath: http://IP:9000
5.2 編碼過程
5.2.1 創(chuàng)建一個參數(shù)配置類
通過這種方式將配置文件中以minio開頭的那些配置加載到spring容器中管理,其他位置使用的時候直接注入即可
@Data @ConfigurationProperties(prefix = "minio") @Component public class MinIOConfigProperties implements Serializable { private String username; private String pwd; private String bucket; private String endpoint; private String readPath; }
5.2.2 創(chuàng)建minio配置類
通過這個全局的配置類,其他需要上傳文件的類中直接注入MinioClient即可
import io.minio.MinioClient; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Data @Configuration public class MinIOConfig { @Autowired private MinIOConfigProperties minIOConfigProperties; @Bean public MinioClient buildMinioClient() { return MinioClient .builder() .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey()) .endpoint(minIOConfigProperties.getEndpoint()) .build(); } }
5.2.3 創(chuàng)建minio文件服務(wù)類或工具類
在日常開發(fā)中,可以自定義一個minio的工具類,使用的時候就比較方便了,下面的代碼中列舉了常用的一些API操作方法,可以結(jié)合實(shí)際需要自定義更多的工具方法
import com.congge.config.MinIOConfig; import com.congge.config.MinIOConfigProperties; import com.congge.service.MinioFileService; import io.minio.*; import io.minio.messages.Bucket; import io.minio.messages.Item; import lombok.extern.slf4j.Slf4j; import org.apache.poi.util.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; @Slf4j @Import(MinIOConfig.class) @Service public class MinioFileServiceImpl implements MinioFileService { @Autowired private MinioClient minioClient; @Autowired private MinIOConfigProperties minIOConfigProperties; private final static String separator = "/"; /** * 下載文件 * * @param pathUrl 文件全路徑 * @return 文件流 */ @Override public void downLoadFile(String pathUrl, HttpServletResponse response) { String[] pathItems = pathUrl.split("/"); String originFileName = pathItems[pathItems.length - 1]; String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", ""); int index = key.indexOf(separator); //String bucket = key.substring(0,index); String filePath = key.substring(index + 1); InputStream inputStream = null; try { inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build()); response.setHeader("Content-Disposition", "attachment;filename=" + originFileName); response.setContentType("application/force-download"); response.setCharacterEncoding("UTF-8"); IOUtils.copy(inputStream, response.getOutputStream()); System.out.println("下載成功"); } catch (Exception e) { log.error("minio down file error. pathUrl:{}", pathUrl); e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } @Override public String uploadFile(MultipartFile file) throws Exception { String bucketName = minIOConfigProperties.getBucket(); String endpoint = minIOConfigProperties.getEndpoint(); // 檢查存儲桶是否已經(jīng)存在 boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); if (isExist) { System.out.println("Bucket already exists."); } else { minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); } String originalFilename = file.getOriginalFilename(); //拼接生成新的UUID形式的文件名 String objectName = new SimpleDateFormat("yyyy/MM/dd/").format(new Date()) + UUID.randomUUID().toString().replaceAll("-", "") + originalFilename.substring(originalFilename.lastIndexOf(".")); PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName) .bucket(bucketName) .contentType(file.getContentType()) .stream(file.getInputStream(), file.getSize(), -1).build(); minioClient.putObject(objectArgs); //組裝桶中文件的訪問url String resUrl = endpoint + "/" + bucketName + "/" + objectName; return resUrl; } /** * 刪除文件 * * @param pathUrl 文件全路徑 */ @Override public void delete(String pathUrl) { String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", ""); int index = key.indexOf(separator); String bucket = key.substring(0, index); String filePath = key.substring(index + 1); // 刪除Objects RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build(); try { minioClient.removeObject(removeObjectArgs); } catch (Exception e) { log.error("minio remove file error. pathUrl:{}", pathUrl); e.printStackTrace(); } } public List<Bucket> listBuckets() throws Exception { return minioClient.listBuckets(); } public boolean bucketExists(String bucketName) throws Exception { boolean flag = minioClient.bucketExists(bucketName); if (flag) { return true; } return false; } @Override public List<String> listBucketNames() throws Exception{ List<Bucket> bucketList = listBuckets(); List<String> bucketListName = new ArrayList<>(); for (Bucket bucket : bucketList) { bucketListName.add(bucket.name()); } return bucketListName; } @Override public boolean makeBucket(String bucketName) throws Exception{ boolean flag = bucketExists(bucketName); if (!flag) { minioClient.makeBucket(bucketName); return true; } else { return false; } } @Override public boolean removeBucket(String bucketName) throws Exception{ boolean flag = bucketExists(bucketName); if (flag) { Iterable<Result<Item>> myObjects = listObjects(bucketName); for (Result<Item> result : myObjects) { Item item = result.get(); // 有對象文件,則刪除失敗 if (item.size() > 0) { return false; } } // 刪除存儲桶,注意,只有存儲桶為空時才能刪除成功。 minioClient.removeBucket(bucketName); flag = bucketExists(bucketName); if (!flag) { return true; } } return false; } @Override public List<String> listObjectNames(String bucketName) throws Exception{ List<String> listObjectNames = new ArrayList<>(); boolean flag = bucketExists(bucketName); if (flag) { Iterable<Result<Item>> myObjects = listObjects(bucketName); for (Result<Item> result : myObjects) { Item item = result.get(); listObjectNames.add(item.objectName()); } } return listObjectNames; } @Override public boolean removeObject(String bucketName, String objectName) throws Exception{ boolean flag = bucketExists(bucketName); if (flag) { List<String> objectList = listObjectNames(bucketName); for (String s : objectList) { if(s.equals(objectName)){ minioClient.removeObject(bucketName, objectName); return true; } } } return false; } @Override public String getObjectUrl(String bucketName, String objectName) throws Exception{ boolean flag = bucketExists(bucketName); String url = ""; if (flag) { url = minioClient.getObjectUrl(bucketName, objectName); } return url; } public Iterable<Result<Item>> listObjects(String bucketName) throws Exception { boolean flag = bucketExists(bucketName); if (flag) { return minioClient.listObjects(bucketName); } return null; } }
5.2.4 編寫測試接口
為了方便測試,下面定義了一個測試接口
import com.congge.service.MinioFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.util.List; @RestController @Slf4j public class FileController { @Autowired private MinioFileService minioFileService; /** * 上傳文件 * @param file * @return * @throws Exception */ @PostMapping("/upload") public String upload(@RequestBody MultipartFile file) throws Exception { String url = minioFileService.uploadFile(file); return "文件上傳成功,文件路徑:" + url; } /** * 下載文件 * @param pathUrl * @param response */ @GetMapping("/download") public void download(@RequestParam("pathUrl") String pathUrl, HttpServletResponse response) { minioFileService.downLoadFile(pathUrl,response); } /** * 列出所有bucket名稱 * @return * @throws Exception */ @PostMapping("/list/bucket") public List<String> list() throws Exception { return minioFileService.listBucketNames(); } /** * 創(chuàng)建bucket * @param bucketName * @return * @throws Exception */ @PostMapping("/create/bucket") public boolean createBucket(@RequestParam("bucketName")String bucketName) throws Exception { return minioFileService.makeBucket(bucketName); } /** * 刪除bucket * @param bucketName * @return * @throws Exception */ @PostMapping("/delete/bucket") public boolean deleteBucket(@RequestParam("bucketName")String bucketName) throws Exception { return minioFileService.removeBucket(bucketName); } /** * 列出bucket的所有對象名稱 * @param bucketName * @return * @throws Exception */ @PostMapping("/list/object_names") public List<String> listObjectNames(@RequestParam("bucketName")String bucketName) throws Exception { return minioFileService.listObjectNames(bucketName); } /** * 刪除bucket中的某個對象 * @param bucketName * @param objectName * @return * @throws Exception */ @PostMapping("/remove/object") public boolean removeObject(@RequestParam("bucketName")String bucketName,@RequestParam("objectName") String objectName) throws Exception { return minioFileService.removeObject(bucketName, objectName); } /** * 獲取文件訪問路徑 * @param bucketName * @param objectName * @return * @throws Exception */ @PostMapping("/get/object/url") public String getObjectUrl(@RequestParam("bucketName")String bucketName, @RequestParam("objectName")String objectName) throws Exception { return minioFileService.getObjectUrl(bucketName, objectName); } }
5.2.5 接口測試
上傳文件測試
上傳成功后,返回了文件的完整路徑,方便后續(xù)使用
然后在控制臺的test這個bucket中檢查是否上傳上去了
下載文件測試
使用上一步返回的url,直接調(diào)用下載接口,下載完成后可以直接預(yù)覽
更多的接口有興趣的同學(xué)可以一一嘗試下,就不再贅述了。
六、寫在文末
本文詳細(xì)總結(jié)了Minio的搭建使用,以及與springboot整合的完整步驟,作為一款適用且輕量級的文件存儲服務(wù)器,可以私有化部署,也可以很方便進(jìn)行云上部署、容器化部署,為今后在實(shí)際項(xiàng)目中的技術(shù)選型提供一個參考,本篇到此結(jié)束,感謝觀看。
以上就是springboot整合minio的超詳細(xì)教程的詳細(xì)內(nèi)容,更多關(guān)于springboot整合minio的資料請關(guān)注腳本之家其它相關(guān)文章!
- minio的下載和springboot整合minio使用方法
- SpringBoot整合Minio實(shí)現(xiàn)圖片上傳功能
- SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能
- 可能是全網(wǎng)最詳細(xì)的springboot整合minio教程
- SpringBoot整合MinIO實(shí)現(xiàn)文件上傳的方法詳解
- Spring?Boot?3?整合?MinIO?實(shí)現(xiàn)分布式文件存儲的全過程
- SpringBoot+MinIO實(shí)現(xiàn)對象存儲方式
- Vue?+?SpringBoot?實(shí)現(xiàn)文件的斷點(diǎn)上傳、秒傳存儲到Minio的操作方法
- 在 Spring Boot 中集成 MinIO 對象存儲
相關(guān)文章
Springboot?手動分頁查詢分批批量插入數(shù)據(jù)的實(shí)現(xiàn)流程
這篇文章主要介紹了Springboot?手動分頁查詢分批批量插入數(shù)據(jù)的實(shí)現(xiàn)流程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07Java虛擬機(jī)JVM類加載機(jī)制(從類文件到虛擬機(jī))
所謂的類加載機(jī)制就是虛擬機(jī)將class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行驗(yàn)證,轉(zhuǎn)換解析和初始化,形成虛擬機(jī)可以直接使用的java類型,本文給大家介紹類加載機(jī)制過程從類文件到虛擬機(jī)的詳細(xì)說明,感興趣的朋友跟隨小編一起看看吧2021-06-06springboot使用JPA時間類型進(jìn)行模糊查詢的方法
這篇文章主要介紹了springboot使用JPA時間類型進(jìn)行模糊查詢的方法,需要的朋友可以參考下2018-03-03springboot實(shí)現(xiàn)小程序支付的項(xiàng)目實(shí)踐
本文主要介紹了springboot實(shí)現(xiàn)小程序支付的項(xiàng)目實(shí)踐,?可以通過調(diào)用微信支付?API?實(shí)現(xiàn)支付功能,具有一定的參考價值,感興趣的可以了解一下2023-09-09Mybatis-Plus的應(yīng)用場景描述及注入SQL原理分析
MyBatis-Plus是一個 MyBatis 的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生,本文重點(diǎn)給大家介紹Mybatis-Plus的應(yīng)用場景及注入SQL原理分析,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2021-05-05SpringMVC處理數(shù)據(jù)輸出的實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于SpringMVC處理數(shù)據(jù)輸出的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05