MinIO的簡單使用實踐
阿新 • • 發佈:2021-09-20
MinIO是一款高效能高可用的檔案系統服務,可以用來替換FastDFS,這裡介紹一下簡單安裝與使用。部署方式採用單機單硬碟模式。
安裝與啟動
wget https://dl.minio.io/server/minio/release/linux-amd64/minio
nuhup /root/minio server /data > /data/minio/minio.log 2>&1 &
通過環境變數可以修改控制檯管理員密碼
export MINIO_ACCESS_KEY=root
export MINIO_SECRET_KEY=root_1234
幾個概念:
- bucket minio裡邊object儲存位置的最上一級目錄,object要儲存都要指定一個bucket
- objectName 如果只指定"檔名.副檔名"則直接存放在bucket目錄下,但還可以帶路徑、比如"/abc/檔名.副檔名"則會存放在bucket/abc/目錄下
- 一般客戶端另外配置使用者而不是直接使用控制檯管理員賬戶,使用控制檯建立使用者賬號並分配許可權(讀、寫、控制檯等)即可。
與spring搭配開發
簡單實現檔案的上傳、下載、預覽等功能。
引入依賴
implementation group: 'io.minio', name: 'minio', version: '7.1.0'
配置類與工具類:
@Configuration public class MinioConfig { @Value("${minio.ip}") private String ip; @Value("${minio.port}") private int port; @Value("${minio.access-key}") private String accessKey; @Value("${minio.secret-key}") private String secretKey; @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(ip, port, false) //https or not .credentials(accessKey, secretKey) .build(); } }
@Component
public class MinioUtil {
private Logger logger = LoggerFactory.getLogger(MinioUtil.class);
@Autowired
private MinioClient minioClient;
/**
* 建立bucket
* */
private void createBucket(String bucketName) throws Exception {
BucketExistsArgs existsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
if(!minioClient.bucketExists(existsArgs)) {
MakeBucketArgs makeArgs = MakeBucketArgs.builder().bucket(bucketName).build();
minioClient.makeBucket(makeArgs);
logger.info("bucket {} 不存在, 自動建立該bucket", bucketName);
}
}
/**
* 從給定輸入流中傳輸物件並放入bucket
* */
public ObjectWriteResponse putObject(String bucketName, String objectName, InputStream stream, long objectSize, String contentType) throws Exception {
if (StringUtils.isEmpty(bucketName)) {
throw new RuntimeException("儲存的bucketName為空");
}
createBucket(bucketName);
//long objSize = -1;
long partSize = -1; //objectSize已知,partSize設為-1意為自動設定
PutObjectArgs putArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(stream, objectSize, partSize)
.contentType(contentType)
.build();
ObjectWriteResponse response = minioClient.putObject(putArgs);
return response;
}
/**
* 從bucket獲取指定物件的輸入流,後續可使用輸入流讀取物件
* getObject與minio server連線預設保持5分鐘,
* 每隔15s由minio server向客戶端傳送keep-alive check,5分鐘後由客戶端主動發起關閉連線
* */
public InputStream getObject(String bucketName, String objectName) throws Exception{
GetObjectArgs args = GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build();
return minioClient.getObject(args);
}
/**
* 獲取物件的臨時訪問url,有效期5分鐘
* */
public String getObjectURL(String bucketName, String objectName) throws Exception{
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.expiry(5, TimeUnit.MINUTES)
.method(Method.GET)
.build();
return minioClient.getPresignedObjectUrl(args);
}
/**
* 刪除物件
* */
public void removeObject(String bucketName, String objectName) throws Exception {
RemoveObjectArgs args = RemoveObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build();
minioClient.removeObject(args);
logger.info("bucket:{}檔案{}已刪除", bucketName , objectName);
}
/**
* 上傳MultipartFile
* @param bucketName 檔案存放的bucket
* @param filePath 檔案在bucket裡的全目錄
* */
public ObjectWriteResponse uploadFile(String bucketName, String filePath, MultipartFile file) throws Exception{
return putObject(bucketName, filePath, file.getInputStream(), file.getSize(), file.getContentType());
}
/**
* 從minio下載檔案,直接通過response傳輸
* */
public void downloadFile(String bucketName, String filePath, HttpServletResponse response) throws Exception {
try (InputStream is = getObject(bucketName, filePath);
BufferedInputStream bis = new BufferedInputStream(is);
OutputStream os = response.getOutputStream()) {
//try {
/*InputStream is = getObject(bucketName, filePath);
BufferedInputStream bis = new BufferedInputStream(is);
OutputStream os = response.getOutputStream();*/
response.setContentType("application/force-download;charset=utf-8");// 設定強制下載而不是直接開啟
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filePath, "UTF-8"));// 設定檔名
byte[] buffer = new byte[1024*1024*1024]; //buffer 1M
int offset = bis.read(buffer);
while (offset != -1) {
os.write(buffer, 0, offset);
offset = bis.read(buffer);
}
os.flush();
} catch (Exception e) {
logger.error("下載檔案失敗"+e.getMessage(), e);
throw new RuntimeException("下載檔案失敗" , e);
}
}
}
記錄一下幾個問題:
1、springboot 2.1.13.RELEASE環境下集成了MinIO客戶端7.1.0版本,最新的版本貌似整合不進去
2、檔案下載也就是minioClient.getObject(args)
場景下,客戶端與MinIO server連線預設保持5分鐘,每隔15s由MinIO server向客戶端傳送keep-alive check,5分鐘後由客戶端主動發起關閉連線。
3、檔案下載時使用流的方式傳輸,上述程式碼裡使用try-with-resource的方式確保finally關閉流,但是通過wireshark觀測貌似直接普通try-catch最後也沒有造成連線的洩露,應該是底層的okio做了優化、5分鐘後直接發起了連線關閉。但作為好習慣還是應該主動去關閉流。