SpringBoot + MinIO 輕松構建對象存儲服務,支持私有化部署!
01、背景介紹
在實際的軟件系統開發過程中,經常避免不了需要用到文件存儲服務。
例如,對于小型的網站系統,通常會將文件存儲服務和網站系統部署在一臺服務器中,以實現低成本的資源投入,如果訪問量不大,基本上沒什么問題。當訪問量逐漸升高,此時網站的文件資源讀取越來越頻繁,單臺服務器可能難以承載較大的請求量,這個時候網站可能會出現打不開,甚至系統異常等問題。
當出現這個場景,很容易第一時間想到將文件采用云存儲服務來解決。所謂云存儲服務,簡單的說,就是將訪問很頻繁的文件資源服務,由本地改成云廠商提供的文件存儲服務,比如阿里云 OSS、七牛云、騰訊云、百度云等等,遷移之后,網站的訪問壓力會得到極大的釋放,服務也會變得更加穩定。但是,這些云存儲服務大部分都是收費的,以阿里云為例,數據存儲通常按照 0.12 元/GB/月的標準來收費,雖然便宜,但是日積月累下來也是一筆不小的開支啊。
為了節省成本,很多項目團隊會自己搭建一套云存儲服務,比如采用開源的 fastDFS 工具來作為文件存儲服務器,雖然能性能不錯,但是軟件安裝環境非常復雜,最重要的是沒有一個完整的技術文檔,大部分都是某某公司或者某某網友自己總結的文檔,每次維護起來很是麻煩。
直到出現了 MinIO,云存儲服務工具又多了一個新的可選項。
MinIO 是一款號稱世界上速度最快的對象存儲服務器,專為大規模數據存儲和分析而設計。它支持在各種環境中部署,包括物理服務器、虛擬機、容器等,最關鍵的是它的技術文檔非常完善,非常容易上手;同時,對個人用戶是完全開源免費的。
今天通過這篇文章,我們一起了解一下如何利用 MinIO 來搭建一套屬于自己的云存儲服務。
02、方案實踐
2.1、minio 快速安裝
minio 工具的安裝非常簡單,如果你本機安裝了 Docker 容器,可以通過 Docker 命令一鍵實現安裝操作。
以 windows 操作系統為例,安裝命令如下。
docker run \
-p 9000:9000 \
-p 9001:9001 \
--name minio1 \
-v D:\minio\data:/data \
-e "MINIO_ROOT_USER=ROOTUSER" \
-e "MINIO_ROOT_PASSWORD=CHANGEME123" \
quay.io/minio/minio server /data --console-address ":9001"
相關參數解讀:
- docker run:表示啟動運行容器
- -p:表示為容器綁定一個本地的端口
- -name:表示為容器創建一個本地的名字
- -v:表示將文件路徑設置為容器使用的持久卷位置。當 MinIO 將數據寫入 /data時,該數據會鏡像到本地路徑~/minio/data, 使其能夠在容器重新啟動時保持持久化。您可以設置任何具有讀取、寫入和刪除權限的文件路徑來使用。
- -e:表示設置登陸控制臺的用戶名和密碼。其中控制臺的訪問地址為http://本機ip:9001,api 的訪問地址為http://本機ip:9000。
如果沒有 docker 容器,可以采用軟件包方式進行安裝,具體實現方式可以參考官網文檔,地址如下。
https://minio.org.cn/docs/minio/container/index.html
服務啟動成功之后,在瀏覽器中訪問http://127.0.0.1:9001地址,會看到類似于如下界面。
圖片
輸入上文設置的用戶名和密碼,即可登陸!
2.2、minio 使用介紹
登陸成功之后,會看到類似于如下的主界面。
圖片
由于官方并沒有提供漢化版,如果想要實現中文展示,可以使用瀏覽器插件進行翻譯,翻譯之后的內容如下。
圖片
在對象存儲服務里面,所有的文件都是以桶的形式來組織的。簡單的說,你可以將桶看作是目錄,這個目錄下有很多的文件或者文件夾,這和其它云存儲服務基本一致。
下面我們一起來快速體驗一下!
2.2.1、創建存儲桶
所有的文件必須要存儲到桶中,因此我們需要先創建一個存儲桶。
圖片
如果想要修改存儲桶信息,點擊左側的Buckets菜單,就可以看到相關的存儲桶配置信息。
2.2.2、上傳和下載文件
存儲桶創建完成之后,就可以上傳文件了。
點擊Object Browser菜單,可以看到剛剛創建的存儲桶public-bucket,點擊進入,上傳我們想要存儲的文件了。
圖片
圖片
圖片
如果想要下載文件或者預覽文件,點擊文件,右側會彈出相關的操作按鈕,點擊相應的操作按鈕就可以了。
2.2.3、設置文件公開訪問
默認創建的存儲桶,都是私有桶,也就是說無法被公開訪問。
圖片
以上文的文件為例,如果以 api 的方式直接訪問,會提示無權限,示例如下:
圖片
通常來說,我們會將數據寫入操作進行控制;對于讀操作,很多不涉及安全問題的,我們希望能被互聯網公開訪問,以便加快文件的訪問速度,此時如何實現呢?
可以在存儲桶里面配置,將數據讀取權限設置為公開訪問,操作示例如下:
圖片
此時,我們再次以 api 的方式訪問,結果如下:
圖片
可以清晰的看到,此時文件可以公開訪問了。
2.3、springBoot 集成 minio 實現文件存儲
最后,我們一起來看看,如何在 Spring Boot 工程中集成 minio 客戶端以便實現文件存儲服務。
2.3.1、創建用戶訪問密鑰
MinIO 支持通過用戶、密碼來管理存儲桶,我們可以利用 minio 客戶端來實現文件的上傳和下載。
點擊Access Keys菜單,創建用戶名和密碼并將其保存,下文會用到。
圖片
2.3.2、引入依賴包
在 Spring Boot 工程,引入 minio 客戶端依賴包。
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.4</version>
</dependency>
2.3.3、添加相關配置
在application.properties文件中,添加 minio 相關的配置信息.
minio.endpoint=http://127.0.0.1:9000
minio.access-key=o1TJJL9noE69KIgZtKQ0
minio.secret-key=KAi91ZUYHXCzCn1XUiHJ3qQflp50XFqlTCFt6Ik3
minio.bucket-name=public-bucket
2.3.4、編寫 Minio 客戶端配置類
基于上文的配置信息,編寫 Minio 客戶端配置類。
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String minioEndpoint;
@Value("${minio.access-key}")
private String minioAccessKey;
@Value("${minio.secret-key}")
private String minioSecretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(minioEndpoint)
.credentials(minioAccessKey, minioSecretKey)
.build();
}
}
2.3.5、編寫上傳和文件預覽服務
接著利用 minioClient 客戶端,編寫上傳和文件預覽服務。
@RestController
public class FileController {
@Value("${minio.bucket-name}")
private String bucketName;
@Autowired
private MinioClient minioClient;
/**
* 文件上傳
* @param file
* @return
* @throws IOException
*/
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
try {
ObjectWriteResponse response = minioClient.putObject(
PutObjectArgs
.builder()
.bucket(bucketName)
.object(file.getOriginalFilename())
.stream(file.getInputStream(), file.getInputStream().available(), -1)
.contentType(file.getContentType())
.build()
);
return "upload file success,tagId:" + response.etag();
} catch (Exception e) {
e.printStackTrace();
return "upload file error";
}
}
/**
* 構建預覽地址
* @param fileName
* @return
* @throws Exception
*/
@GetMapping("/getPreviewUrl")
public String getPreviewUrl(@RequestParam("fileName") String fileName) throws Exception {
// 構建預覽地址,默認15秒過期,無論是私有桶還是公有桶,文件通過鏈接都可以訪問
String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName) //存儲桶
.object(fileName) //文件名
.expiry(15) // 設置過期時間,單位秒
.build());
return url;
}
/**
* 構建永久訪問地址
* @param fileName
* @return
* @throws Exception
*/
@GetMapping("/getPublicUrl")
public String getDownloadUrl(@RequestParam("fileName") String fileName) throws Exception {
// 構建永久訪問地址,前提是這個存儲桶允許公開訪問
String url = minioClient.getObjectUrl(bucketName, fileName);
return url;
}
}
2.3.6、編寫上傳頁面
在resources/static目錄下,創建index.html文件,編寫上傳頁面。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上傳</title>
</head>
<body>
<h1>文件上傳</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">上傳</button>
</form>
</body>
</html>
2.3.7、最后驗證一下服務
最后,將服務啟動,一起來驗證一下代碼的正確性。
1)上傳服務驗證
在瀏覽器端,訪問http://127.0.0.1:8080/,選擇文件并上傳,示例如下。
圖片
回到 minio 控制臺,可以看到剛剛上傳的文件信息。
圖片
2)文件預覽地址驗證
在瀏覽器端,訪問http://127.0.0.1:8080/getPreviewUrl?fileName=圖片.jpeg,會返回一段帶有簽名的文件預覽地址,示例如下。
圖片
將其地址復制出來直接訪問,可以清晰的看到圖片能正常展示。
圖片
通過getPresignedObjectUrl()方法生成的文件地址鏈接,無論是是公有桶還是私有桶,都可以正常訪問。與getObjectUrl()方法生成的文件預覽地址相比,它帶有過期時間,這樣設計的目的也是為了保護文件資源,避免頻繁竊取。
03、小結
最后總結一下,本文主要圍繞利用 minio 實現對象存儲服務,進行了一次知識內容的總結。
在實際的使用過程中,通常會這樣處理。
- 如果當前文件不包含隱私信息,比如圖片,可以配置公共訪問權限,構建永久訪問鏈接。
- 如果當前文件包含隱私信息,比如營業執照圖片,可以配置私有桶,構建帶有有效時長的訪問鏈接,比如配置過期時間1小時等。
示例代碼地址:
https://gitee.com/pzblogs/spring-boot-example-demo
04、參考
1.https://minio.org.cn/docs/minio/container/index.html