如何使用docker創(chuàng)建minio鏡像并上傳文件并提供demo
使用docker創(chuàng)建minio鏡像并上傳文件,提供demo
1. 整體描述
MinIO是一個對象存儲解決方案,它提供了一個Amazon Web Services S3兼容的API,并支持所有S3的核心特性。MinIO可以部署在任何地方——公共云或私有云、裸機基礎設施、編排環(huán)境和邊緣基礎設施。
本文檔介紹MinIO最新穩(wěn)定版本RELEASE.2023-09-04T19-57-37Z在Windows平臺上部署MinIO的操作、管理和開發(fā)。
上面是官網(wǎng)介紹,用有道翻譯的,官網(wǎng)地址: 鏈接。
2. 環(huán)境搭建
使用docker搭建minio環(huán)境,可以直接用官網(wǎng)下載minio鏡像,我們先用windows環(huán)境搭建一下。
2.1 windows環(huán)境搭建
在官網(wǎng)下載頁面,選擇windows,下載的是一個minion.exe文件。我放在了d:/minio目錄下,在此再創(chuàng)建一個data文件夾,用來儲存minio上傳的文件。然后在命令行執(zhí)行如下指令啟動minio:
setx MINIO_ROOT_USER minioadmin setx MINIO_ROOT_PASSWORD minioadmin D:\minio\minio.exe server D:\minio\data\ --console-address ":9001"
看到如下就說明啟動成功了:

然后通過瀏覽器訪問:http://localhost:9001/進入如下登錄頁面:默認用戶名和密碼都是minioadmin

2.2 docker部署
使用docker部署就更簡單了,首先拉取官方鏡像:
docker pull minio/minio
拉取成功之后,執(zhí)行創(chuàng)建和啟動容器:
docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"
看到如下就說明啟動成功:

同樣通過瀏覽器訪問:http://localhost:9001/進入如下登錄頁面:默認用戶名和密碼都是minioadmin
3. spring集成
通過springboot框架集成minio,實現(xiàn)上傳文件的目的。
3.1 添加依賴
首先創(chuàng)建一個springboot工程,添加如下依賴:
<!-- lombok 自動生成方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--io常用工具類 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!--常用工具類 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.6</version>
</dependency>3.2 配置文件
在springboot的yml配置文件中添加minio環(huán)境的配置:
#minio相關配置 minio: endpoint: http://127.0.0.1:9000 accessKey: minioadmin secretKey: minioadmin
3.3 創(chuàng)建config類
package com.thcb.miniodemo.config;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* MinioUtil
*
* @author thcb
* @date 2023-09-05
*/
@Component
public class MinioClientConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
/**
* 注入minio 客戶端
*
* @return
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}3.4 創(chuàng)建minio操作類
minio操作類,用來寫minio基礎方法
package com.thcb.miniodemo.minio;
import com.thcb.miniodemo.utils.*;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* MinioUtil
*
* @author thcb
* @date 2023-09-05
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class MinioUtil {
private final MinioClient minioClient;
/**
* 兩票數(shù)據(jù)桶
*/
public static String TEST_BUCKET = "test";
private static String POLICY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::%s\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::%s/*\"]}]}";
public void initMinIo() {
log.warn("start initMinIo.");
if (!bucketExists(TEST_BUCKET)) {
log.warn("start makeBucket {}.", TEST_BUCKET);
makeBucket(TEST_BUCKET);
log.warn("finish makeBucket {}.", TEST_BUCKET);
}
try {
log.warn("start setBucketPolicy {}.", TEST_BUCKET);
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(TEST_BUCKET).config(String.format(POLICY, TEST_BUCKET, TEST_BUCKET)).build());
log.warn("finish setBucketPolicy {}.", TEST_BUCKET);
} catch (Exception e) {
log.error("setBucketPolicy from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
}
}
/**
* 查看存儲bucket是否存在
*
* @return boolean
*/
public Boolean bucketExists(String bucketName) {
Boolean found;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
log.error("bucketExists from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
return false;
}
return found;
}
/**
* 創(chuàng)建存儲bucket
*
* @return Boolean
*/
public synchronized Boolean makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
log.error("makeBucket from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
return false;
}
return true;
}
/**
* 刪除存儲bucket
*
* @return Boolean
*/
public synchronized Boolean removeBucket(String bucketName) {
try {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
log.error("removeBucket from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
return false;
}
return true;
}
/**
* 獲取全部bucket
*/
public List<Bucket> getAllBuckets() {
try {
List<Bucket> buckets = minioClient.listBuckets();
return buckets;
} catch (Exception e) {
log.error("getAllBuckets from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
}
return null;
}
/**
* 文件上傳
*
* @param file 文件
* @param bucketName 桶名稱
* @return Boolean
*/
public synchronized String upload2Bucket(MultipartFile file, String bucketName) {
return String.format("/%s/%s", bucketName, upload(file, bucketName));
}
/**
* 文件上傳
*
* @param file 文件
* @param bucketName 桶名稱
* @return Boolean
*/
public synchronized String upload(MultipartFile file, String bucketName) {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
throw new CustomException("文件格式錯誤");
}
String fileName = UUIDUtil.UUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = DateUtils.dateTimeNow(DateUtils.YYYYMMDD) + "/" + fileName;
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
//文件名稱相同會覆蓋
minioClient.putObject(objectArgs);
} catch (Exception e) {
log.error("upload file to minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
return null;
}
return objectName;
}
/**
* 文件上傳
*
* @param file 文件
* @return Boolean
*/
public synchronized String upload(MultipartFile file) {
return upload(file, TEST_BUCKET);
}
/**
* 預覽
*
* @param fileName
* @return
*/
public String preview(String fileName) {
return preview(fileName, TEST_BUCKET);
}
/**
* 預覽
*
* @param fileName
* @param bucketName 桶名稱
* @return
*/
public String preview(String fileName, String bucketName) {
// 查看文件地址
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build();
try {
String url = minioClient.getPresignedObjectUrl(build);
return url;
} catch (Exception e) {
log.error("preview file to minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
}
return null;
}
/**
* 文件下載
*
* @param fileName 文件名稱
* @param originalFileName 原文件名稱
* @param res response
* @return Boolean
*/
public void download(String fileName, String originalFileName, HttpServletRequest req, HttpServletResponse res) {
download(fileName, TEST_BUCKET, req, res);
}
/**
* 文件下載
*
* @param fileName 文件名稱
* @param bucketName 桶名稱
* @param originalFileName 原文件名稱
* @param res response
* @return Boolean
*/
public void download(String fileName, String bucketName, String originalFileName, HttpServletRequest req, HttpServletResponse res) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName)
.object(fileName).build();
try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
while ((len = response.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.flush();
byte[] bytes = os.toByteArray();
res.setCharacterEncoding("utf-8");
String type = req.getHeader("User-Agent").toLowerCase();
String firefox = "firefox", chrome = "chrome";
String encodedFileName;
if (type.indexOf(firefox) > 0 || type.indexOf(chrome) > 0) {
encodedFileName = new String(originalFileName.getBytes(StandardCharsets.UTF_8), "iso8859-1");
} else {
encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name());
}
// 設置強制下載不打開
// res.setContentType("application/force-download");
// res.setContentType("application/octet-stream");
res.setContentType(FileDownloadUtils.getFileContentType(fileName));
res.addHeader("Content-Disposition", "attachment;fileName=" + encodedFileName + ";filename*=utf-8''" + encodedFileName);
res.addHeader("Content-Length", bytes.length + "");
try (ServletOutputStream stream = res.getOutputStream()) {
stream.write(bytes);
stream.flush();
}
}
res.flushBuffer();
} catch (Exception e) {
log.error("download file from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
}
}
/**
* 刪除
*
* @param fileName
* @return
* @throws Exception
*/
public boolean remove(String fileName) {
return remove(fileName, TEST_BUCKET);
}
/**
* 刪除
*
* @param fileName
* @return
* @throws Exception
*/
public synchronized boolean remove(String fileName, String bucketName) {
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
} catch (Exception e) {
log.error("remove file from minio occur exception. e={}", ExceptionUtil.getExceptionMessage(e));
return false;
}
return true;
}
}3.5 創(chuàng)建啟動類
在springboot啟動成功后連接minio
package com.thcb.miniodemo.listener;
import com.thcb.miniodemo.minio.MinioUtil;
import com.thcb.miniodemo.utils.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* ApplicationReadyListener
*
* @author thcb
* @date 2023-09-05
*/
@Component
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger log = LoggerFactory.getLogger(ApplicationReadyListener.class);
@Autowired
private MinioUtil minioUtil;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
doPostConstruct();
} catch (Exception e) {
log.error("e={}", ExceptionUtil.getExceptionMessage(e));
}
}
private void doPostConstruct() {
log.info("initMinIo");
initMinIo();
}
/**
* 初始化minio桶文件
*/
private void initMinIo() {
minioUtil.initMinIo();
}
}3.6 測試controller
寫一個測試的controller,測試minio相關功能
package com.thcb.miniodemo.controller;
import com.thcb.miniodemo.minio.MinioUtil;
import com.thcb.miniodemo.utils.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* TestController
*
* @author thcb
* @date 2023-09-05
*/
@RestController
@RequestMapping("/TestController")
public class TestController {
private static final Logger log = LoggerFactory.getLogger(TestController.class);
@Autowired
private MinioUtil minioUtil;
@RequestMapping("/test")
@ResponseBody
public String test() {
return "test success";
}
@PostMapping("/uploadFile")
public AjaxResult uploadFile(MultipartFile file) throws Exception {
try {
String pathUrl = minioUtil.upload2Bucket(file, MinioUtil.TEST_BUCKET);
return AjaxResult.success(pathUrl);
} catch (Exception e) {
return AjaxResult.error(e.toString());
}
}
}4. 測試操作
4.1 demo運行
運行工程,如下log說明連接成功:

4.2 頁面查看
運行完成,在頁面應該能看到我們創(chuàng)建的桶:

4.3 上傳文件
使用postman調(diào)用我們寫的測試接口,上傳一個文件到minio

上傳成功,在頁面上也可以看到這個文件:

4.4 預覽/下載文件
如果上傳的是圖片,通過返回的url,瀏覽器可以直接訪問預覽,如果是其他類型的文件,是可以通過這個返回的url進行下載的:http://localhost:9000/test/20230908/2b31664c4a004a5cb4b2934ebf5300cd.jpg
5. demo下載
minio的demo已經(jīng)上傳到csdn,需要的可以自行下載,在本文基本也把主要的核心代碼都貼出來了,這個demo使用的是springboot框架,加了一些工具類,可以直接拿來用,或者新工程改個名字就能用了。demo結構截圖:

demo工程地址:demo下載地址,傳到了gitcode上,應該是csdn弄的一個代碼倉庫,和git差不多。
6. 總結
minio還是很方便的,從部署到使用,都可以非??焖俚拇罱ǎ冶容^穩(wěn)定。
到此這篇關于使用docker創(chuàng)建minio鏡像并上傳文件,提供demo的文章就介紹到這了,更多相關docker創(chuàng)建minio鏡像內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
更改Docker默認數(shù)據(jù)目錄解決部署空間不足問題
隨著使用 Docker 的時間增加,存儲在默認數(shù)據(jù)目錄(通常是 /var/lib/docker)中的數(shù)據(jù)量也會不斷增大,最終可能導致服務器上的存儲空間不足,這篇文章將詳細介紹如何更改 Docker 的默認數(shù)據(jù)目錄,以便在服務器上釋放存儲空間并優(yōu)化資源利用,需要的朋友可以參考下2024-06-06

