SpringBoot笔记:SpringBoot集成MinIO分布式文件系统
生活随笔
收集整理的這篇文章主要介紹了
SpringBoot笔记:SpringBoot集成MinIO分布式文件系统
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文章目錄
- 搭建MinIO集群
- SpringBoot集成
- 添加依賴
- 添加配置
- 獲取MinioClient
- MinioUtils完整工具類
- 測(cè)試代碼
搭建MinIO集群
首先搭建MinIO的分布式集群,集群搭建參考《CentOS7安裝筆記:minio分布式集群搭建》
SpringBoot集成
添加依賴
首先,添加如下依賴
<!-- Springoot集成Minio工具--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>7.1.0</version></dependency>添加配置
在yml中添加如下配置:
# minio 連接參數(shù) minio:# URL,域名,或者ip地址endpoint: minio-1# 端口號(hào)port: 9000# 用戶名accessKey: myminio# 密碼secretKey: Leo825Test# 默認(rèn)的存儲(chǔ)桶bucketName: testbucket獲取MinioClient
@Value("${minio.endpoint}")private String endpoint;@Value("${minio.port}")private Integer port;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Value("${minio.bucketName}")private String bucketName;/*** 定義一個(gè)單例的MinioClient對(duì)象*/private static MinioClient minioClient;public MinioClient getInstance() {if (minioClient == null) {minioClient = MinioClient.builder().endpoint(endpoint, port, false).credentials(accessKey, secretKey).build();}return minioClient;}以上就是核心代碼實(shí)現(xiàn)了,具體是怎么實(shí)現(xiàn)可以根據(jù)個(gè)人喜好。
MinioUtils完整工具類
package com.demo.util;import io.minio.*; import io.minio.errors.ErrorResponseException; import io.minio.errors.InvalidExpiresRangeException; import io.minio.messages.Bucket; import io.minio.messages.DeleteError; import io.minio.messages.Item; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List;/*** springboot集成MinIO工具類*/ @Slf4j @Component public class MinioUtils {@Value("${minio.endpoint}")private String endpoint;@Value("${minio.port}")private Integer port;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Value("${minio.bucketName}")private String bucketName;/*** 定義一個(gè)單例的MinioClient對(duì)象*/private static MinioClient minioClient;/*** 默認(rèn)超時(shí)時(shí)間*/private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;public MinioClient getInstance() {if (minioClient == null) {minioClient = MinioClient.builder().endpoint(endpoint, port, false).credentials(accessKey, secretKey).build();}return minioClient;}/*** 檢查存儲(chǔ)桶是否存在** @param bucketName 存儲(chǔ)桶名稱* @return*/@SneakyThrowspublic boolean bucketExists(String bucketName) {boolean flag = minioClient.bucketExists(bucketName);if (flag) {return true;}return false;}/*** 創(chuàng)建存儲(chǔ)桶** @param bucketName 存儲(chǔ)桶名稱*/@SneakyThrowspublic boolean makeBucket(String bucketName) {boolean flag = bucketExists(bucketName);if (!flag) {minioClient.makeBucket(bucketName);return true;} else {return false;}}/*** 列出所有存儲(chǔ)桶名稱** @return*/@SneakyThrowspublic List<String> listBucketNames() {List<Bucket> bucketList = listBuckets();List<String> bucketListName = new ArrayList<>();for (Bucket bucket : bucketList) {bucketListName.add(bucket.name());}return bucketListName;}/*** 列出所有存儲(chǔ)桶** @return*/@SneakyThrowspublic List<Bucket> listBuckets() {return minioClient.listBuckets();}/*** 刪除存儲(chǔ)桶** @param bucketName 存儲(chǔ)桶名稱* @return*/@SneakyThrowspublic boolean removeBucket(String bucketName) {boolean flag = bucketExists(bucketName);if (flag) {Iterable<Result<Item>> myObjects = listObjects(bucketName);for (Result<Item> result : myObjects) {Item item = result.get();// 有對(duì)象文件,則刪除失敗if (item.size() > 0) {return false;}}// 刪除存儲(chǔ)桶,注意,只有存儲(chǔ)桶為空時(shí)才能刪除成功。minioClient.removeBucket(bucketName);flag = bucketExists(bucketName);if (!flag) {return true;}}return false;}/*** 列出存儲(chǔ)桶中的所有對(duì)象名稱** @param bucketName 存儲(chǔ)桶名稱* @return*/@SneakyThrowspublic List<String> listObjectNames(String bucketName) {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;}/*** 列出存儲(chǔ)桶中的所有對(duì)象** @param bucketName 存儲(chǔ)桶名稱* @return*/@SneakyThrowspublic Iterable<Result<Item>> listObjects(String bucketName) {boolean flag = bucketExists(bucketName);if (flag) {return minioClient.listObjects(bucketName);}return null;}/*** 通過(guò)文件上傳到對(duì)象** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param fileName File name* @return*/@SneakyThrowspublic boolean putObject(String bucketName, String objectName, String fileName) {boolean flag = bucketExists(bucketName);if (flag) {minioClient.putObject(bucketName, objectName, fileName, null);ObjectStat statObject = statObject(bucketName, objectName);if (statObject != null && statObject.length() > 0) {return true;}}return false;}/*** MultipartFile格式文件上傳** @param bucketName* @param multipartFile*/@SneakyThrowspublic void putObject(String bucketName, MultipartFile multipartFile, String filename) {PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);putObjectOptions.setContentType(multipartFile.getContentType());minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);}/*** 通過(guò)InputStream上傳對(duì)象** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param stream 要上傳的流* @param stream 要上傳的文件類型 MimeTypeUtils.IMAGE_JPEG_VALUE* @return*/@SneakyThrowspublic boolean putObject(String bucketName, String objectName, InputStream stream, String contentType) {boolean flag = bucketExists(bucketName);if (flag) {PutObjectOptions putObjectOptions = new PutObjectOptions(stream.available(), -1);/*** 開(kāi)啟公共類功能設(shè)置setContentType*/if (!StringUtils.isEmpty(contentType)) {putObjectOptions.setContentType(contentType);}minioClient.putObject(bucketName, objectName, stream, putObjectOptions);ObjectStat statObject = statObject(bucketName, objectName);if (statObject != null && statObject.length() > 0) {return true;}}return false;}/*** 以流的形式獲取一個(gè)文件對(duì)象** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @return*/@SneakyThrowspublic InputStream getObject(String bucketName, String objectName) {boolean flag = bucketExists(bucketName);if (flag) {ObjectStat statObject = statObject(bucketName, objectName);if (statObject != null && statObject.length() > 0) {InputStream stream = minioClient.getObject(bucketName, objectName);return stream;}}return null;}/*** 以流的形式獲取一個(gè)文件對(duì)象(斷點(diǎn)下載)** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param offset 起始字節(jié)的位置* @param length 要讀取的長(zhǎng)度 (可選,如果無(wú)值則代表讀到文件結(jié)尾)* @return*/@SneakyThrowspublic InputStream getObject(String bucketName, String objectName, long offset, Long length) {boolean flag = bucketExists(bucketName);if (flag) {ObjectStat statObject = statObject(bucketName, objectName);if (statObject != null && statObject.length() > 0) {InputStream stream = minioClient.getObject(bucketName, objectName, offset, length);return stream;}}return null;}/*** 下載并將文件保存到本地** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param fileName File name* @return*/@SneakyThrowspublic boolean getObject(String bucketName, String objectName, String fileName) {boolean flag = bucketExists(bucketName);if (flag) {ObjectStat statObject = statObject(bucketName, objectName);if (statObject != null && statObject.length() > 0) {minioClient.getObject(bucketName, objectName, fileName);return true;}}return false;}/*** 刪除一個(gè)對(duì)象** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱*/@SneakyThrowspublic boolean removeObject(String bucketName, String objectName) {boolean flag = bucketExists(bucketName);if (flag) {minioClient.removeObject(bucketName, objectName);return true;}return false;}/*** 刪除指定桶的多個(gè)文件對(duì)象,返回刪除錯(cuò)誤的對(duì)象列表,全部刪除成功,返回空列表** @param bucketName 存儲(chǔ)桶名稱* @param objectNames 含有要?jiǎng)h除的多個(gè)object名稱的迭代器對(duì)象* @return*/@SneakyThrowspublic List<String> removeObject(String bucketName, List<String> objectNames) {List<String> deleteErrorNames = new ArrayList<>();boolean flag = bucketExists(bucketName);if (flag) {Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);for (Result<DeleteError> result : results) {DeleteError error = result.get();deleteErrorNames.add(error.objectName());}}return deleteErrorNames;}/*** 生成一個(gè)給HTTP GET請(qǐng)求用的presigned URL。* 瀏覽器/移動(dòng)端的客戶端可以用這個(gè)URL進(jìn)行下載,即使其所在的存儲(chǔ)桶是私有的。這個(gè)presigned URL可以設(shè)置一個(gè)失效時(shí)間,默認(rèn)值是7天。** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param expires 失效時(shí)間(以秒為單位),默認(rèn)是7天,不得大于七天* @return*/@SneakyThrowspublic String presignedGetObject(String bucketName, String objectName, Integer expires) {boolean flag = bucketExists(bucketName);String url = "";if (flag) {if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {throw new InvalidExpiresRangeException(expires,"expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);}url = minioClient.presignedGetObject(bucketName, objectName, expires);}return url;}/*** 生成一個(gè)給HTTP PUT請(qǐng)求用的presigned URL。* 瀏覽器/移動(dòng)端的客戶端可以用這個(gè)URL進(jìn)行上傳,即使其所在的存儲(chǔ)桶是私有的。這個(gè)presigned URL可以設(shè)置一個(gè)失效時(shí)間,默認(rèn)值是7天。** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @param expires 失效時(shí)間(以秒為單位),默認(rèn)是7天,不得大于七天* @return*/@SneakyThrowspublic String presignedPutObject(String bucketName, String objectName, Integer expires) {boolean flag = bucketExists(bucketName);String url = "";if (flag) {if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {throw new InvalidExpiresRangeException(expires,"expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);}url = minioClient.presignedPutObject(bucketName, objectName, expires);}return url;}/*** 獲取對(duì)象的元數(shù)據(jù)** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @return*/@SneakyThrowspublic ObjectStat statObject(String bucketName, String objectName) {boolean flag = bucketExists(bucketName);if (flag) {ObjectStat statObject = minioClient.statObject(bucketName, objectName);return statObject;}return null;}/*** 文件訪問(wèn)路徑** @param bucketName 存儲(chǔ)桶名稱* @param objectName 存儲(chǔ)桶里的對(duì)象名稱* @return*/@SneakyThrowspublic String getObjectUrl(String bucketName, String objectName) {boolean flag = bucketExists(bucketName);String url = "";if (flag) {url = minioClient.getObjectUrl(bucketName, objectName);}return url;}/*** web下載** @param bucketName 存儲(chǔ)桶名稱* @param fileName 文件名* @param originalName 原始文件名* @param response 輸出對(duì)象*/public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) {try {InputStream file = minioClient.getObject(bucketName, fileName);String filename = new String(fileName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);if (!StringUtils.isEmpty(originalName)) {filename = originalName;}response.setHeader("Content-Disposition", "attachment;filename=" + filename);ServletOutputStream servletOutputStream = response.getOutputStream();int len;byte[] buffer = new byte[1024];while ((len = file.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len);}servletOutputStream.flush();file.close();servletOutputStream.close();} catch (ErrorResponseException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}/*** @return java.util.List<io.minio.messages.Bucket>* @Description 獲取minio所有的桶**/@SneakyThrowspublic List<Bucket> getAllBucket() {// 獲取minio中所以的bucketList<Bucket> buckets = getInstance().listBuckets();for (Bucket bucket : buckets) {log.info("bucket 名稱: {} ,創(chuàng)建時(shí)間: {}", bucket.name(), DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(bucket.creationDate().withZoneSameInstant(ZoneId.of("Asia/Shanghai"))));}return buckets;}/*** @param inputStream: 輸入流* @param objectName: 存儲(chǔ)桶里的對(duì)象名稱* @return void* @Description 將圖片上傳到minio服務(wù)器**/@SneakyThrowspublic void uploadToMinio(InputStream inputStream, String objectName) {long start = System.currentTimeMillis();try {long size = inputStream.available();PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, size, -1).build();// 上傳到miniogetInstance().putObject(putObjectArgs);} catch (Exception e) {log.error("上傳異常:", e);} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {log.error("上傳文件關(guān)閉流異常", e);}}}long end = System.currentTimeMillis();log.info("上傳 {} 文件,總耗時(shí)為:{} ms", objectName, end - start);}/*** @param objectName: 存儲(chǔ)桶里的對(duì)象名稱* @return java.lang.String* @Description 根據(jù)指定的objectName獲取下載鏈接,需要bucket設(shè)置可下載的策略**/@SneakyThrowspublic String getUrlByObjectName(String objectName) {String objectUrl = null;try {objectUrl = getInstance().getObjectUrl(bucketName, objectName);} catch (Exception e) {log.error("獲取下載鏈接異常", e);}return objectUrl;}/*** @param objectName: 存儲(chǔ)桶里的對(duì)象名稱* @param fileName: 文件名稱* @param dir: 文件目錄* @return void* @Description 根據(jù)objectName從minio中下載文件到指定的目錄**/@SneakyThrowspublic void downloadFromMinioToFile(String objectName, String fileName, String dir) {long start = System.currentTimeMillis();GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(objectName).build();File file = new File(dir);if (!file.exists()) {file.mkdirs();}//使用BufferedInputStream和BufferedOutputStream可以提高IO效率try (BufferedInputStream bis = new BufferedInputStream(getInstance().getObject(objectArgs));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(dir, fileName.substring(fileName.lastIndexOf("/") + 1))))) {int length;//讀取內(nèi)容while ((length = bis.read()) != -1) {bos.write(length);bos.flush();//當(dāng)讀取的緩沖區(qū)到了8192字節(jié)后刷出到輸出文件}} catch (Exception e) {log.error("下載異常", e);}long end = System.currentTimeMillis();log.info("下載 {} 文件,總耗時(shí)為:{} ms", objectName, end - start);} }測(cè)試代碼
部分測(cè)試代碼如下所示:
package com.demo;import com.demo.util.MinioUtils; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream;@SpringBootTest @Slf4j class SpringbootMinioApplicationTests {@AutowiredMinioUtils minioUtils;@Testvoid contextLoads() {}@Testpublic void testGetAllBucket() {minioUtils.getAllBucket();}@Testpublic void testUploadToMinio() {String filePath = "D:\\SoftPackage\\apache-maven-3.6.3-bin.zip";try (InputStream inputStream = new FileInputStream(filePath)) {minioUtils.uploadToMinio(inputStream, "apache-maven");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}@Testpublic void testGetUrlByObjectName() {log.info(minioUtils.getUrlByObjectName("apache-maven"));}@Testpublic void testDownloadFromMinioToFile() {String objName = "apache-maven";String fileName = "test_apache-maven-3.6.3-bin.zip";String dir = "D:\\SoftPackage";minioUtils.downloadFromMinioToFile(objName, fileName, dir);} }總結(jié)
以上是生活随笔為你收集整理的SpringBoot笔记:SpringBoot集成MinIO分布式文件系统的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CentOS7安装笔记:minio分布式
- 下一篇: 普罗米修斯笔记:初识Prometheus