SpringBoot整合Minio實現(xiàn)上傳文件的完整步驟記錄
Minio
上傳文件如果不使用云服務(wù)的話,需要本地搭建,一般選擇 FastDFS 但是 FastDFS 安裝比較復(fù)雜,今天了解一款安裝使用更簡單的存儲系統(tǒng) MinIO
MinIO 是一款高性能、分布式的對象存儲系統(tǒng). 它是一款軟件產(chǎn)品, 可以100%的運行在標(biāo)準(zhǔn)硬件。即X86等低成本機器也能夠很好的運行MinIO。
MinIO與傳統(tǒng)的存儲和其他的對象存儲不同的是:它一開始就針對性能要求更高的私有云標(biāo)準(zhǔn)進行軟件架構(gòu)設(shè)計。因為MinIO一開始就只為對象存儲而設(shè)計。所以他采用了更易用的方式進行設(shè)計,它能實現(xiàn)對象存儲所需要的全部功能,在性能上也更加強勁,它不會為了更多的業(yè)務(wù)功能而妥協(xié),失去MinIO的易用性、高效性。 這樣的結(jié)果所帶來的好處是:它能夠更簡單的實現(xiàn)局有彈性伸縮能力的原生對象存儲服務(wù)。
MinIO在傳統(tǒng)對象存儲用例(例如輔助存儲,災(zāi)難恢復(fù)和歸檔)方面表現(xiàn)出色。同時,它在機器學(xué)習(xí)、大數(shù)據(jù)、私有云、混合云等方面的存儲技術(shù)上也獨樹一幟。當(dāng)然,也不排除數(shù)據(jù)分析、高性能應(yīng)用負(fù)載、原生云的支持。
在中國:阿里巴巴、騰訊、百度、中國聯(lián)通、華為、中國移動等等9000多家企業(yè)也都在使用MinIO產(chǎn)品
安裝 Minio
使用docker安裝
拉取鏡像
docker pull minio/minio
啟動
docker run -p 9000:9000 -p 9001:9001 -d --name minio -v /opt/docker/minio/data:/data -v /opt/docker/minio/config:/root/.minio -e "MINIO_ROOT_USER=minio" -e "MINIO_ROOT_PASSWORD=minio@123456" minio/minio server /data --console-address ":9000" --address ":9001"
使用9000端口 登錄控制臺

創(chuàng)建存儲桶

設(shè)置桶權(quán)限



創(chuàng)建 Java 客戶端
依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- minio依賴 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
<!-- hutool工具類 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.2</version>
</dependency>
<!-- 壓縮圖片 -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
<!-- 工具類依賴 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.github.davidcarboni</groupId>
<artifactId>encrypted-</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>配置文件
spring:
application:
name: minio-demo
servlet:
multipart:
max-file-size: 20MB
max-request-size: 200MB
server:
port: 8088
minio:
endpoint: http://你的ip:9001
accessKey: minio
secretKey: minio@123456
nginxHost: http://你的域名配置文件配置類
package com.sqm.minio_demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "minio")
@Component
@Data
public class MinioProperties {
/**
* 連接地址
*/
private String endpoint;
/**
* 用戶名
*/
private String accessKey;
/**
* 密碼
*/
private String secretKey;
/**
* 域名
*/
private String nginxHost;
}創(chuàng)建 minio 客戶端
package com.sqm.minio_demo.config;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient(){
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(),minioProperties.getSecretKey())
.build();
}
}文件地址返回路徑實體類
package com.sqm.minio_demo.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UploadResponse {
private String minIoUrl;
private String nginxUrl;
}上傳文件工具類
package com.sqm.minio_demo.util;
import cn.hutool.core.date.DateUtil;
import com.sqm.minio_demo.config.MinioProperties;
import com.sqm.minio_demo.entity.UploadResponse;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Optional;
import java.util.Random;
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioProperties minioProperties;
@Autowired
private MinioClient minioClient;
private final Long maxSize = (long) (1024 * 1024);
/**
* 創(chuàng)建bucket
*/
public void createBucket(String bucketName) throws Exception {
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 上傳文件
*/
public UploadResponse uploadFile(MultipartFile file, String bucketName) throws Exception {
//判斷文件是否為空
if (null == file || 0 == file.getSize()) {
return null;
}
//判斷存儲桶是否存在 不存在則創(chuàng)建
createBucket(bucketName);
//文件名
String originalFilename = file.getOriginalFilename();
//新的文件名 = 時間戳_隨機數(shù).后綴名
assert originalFilename != null;
long now = System.currentTimeMillis() / 1000;
String fileName = DateUtil.format(DateUtil.date(),"yyyyMMdd")+"_"+ now + "_" + new Random().nextInt(1000) +
originalFilename.substring(originalFilename.lastIndexOf("."));
//開始上傳
log.info("file壓縮前大小:{}",file.getSize());
if (file.getSize() > maxSize) {
FileItemFactory fileItemFactory = new DiskFileItemFactory();
FileItem fileItem = fileItemFactory.createItem(fileName, "text/plain", true, fileName);
OutputStream outputStream = fileItem.getOutputStream();
Thumbnails.of(file.getInputStream()).scale(1f).outputFormat(originalFilename.substring(originalFilename.lastIndexOf(".")+1)).outputQuality(0.25f).toOutputStream(outputStream);
file = new CommonsMultipartFile(fileItem);
}
log.info("file壓縮后大小:{}",file.getSize());
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
String url = minioProperties.getEndpoint() + "/" + bucketName + "/" + fileName;
String urlHost = minioProperties.getNginxHost() + "/" + bucketName + "/" + fileName;
return new UploadResponse(url, urlHost);
}
/**
* 獲取全部bucket
*
* @return
*/
public List<Bucket> getAllBuckets() throws Exception {
return minioClient.listBuckets();
}
/**
* 根據(jù)bucketName獲取信息
*
* @param bucketName bucket名稱
*/
public Optional<Bucket> getBucket(String bucketName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidResponseException, InternalException, ErrorResponseException, ServerException, XmlParserException, ServerException {
return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
}
/**
* 根據(jù)bucketName刪除信息
*
* @param bucketName bucket名稱
*/
public void removeBucket(String bucketName) throws Exception {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/**
* 獲取?件外鏈
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @param expires 過期時間 <=7
* @return url
*/
public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(expires).build());
}
/**
* 獲取?件
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @return ?進制流
*/
public InputStream getObject(String bucketName, String objectName) throws Exception {
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 上傳?件
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @param stream ?件流
* @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#putObject
*/
public void putObject(String bucketName, String objectName, InputStream stream) throws
Exception {
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, stream.available(), -1).contentType(objectName.substring(objectName.lastIndexOf("."))).build());
}
/**
* 上傳?件
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @param stream ?件流
* @param size ??
* @param contextType 類型
* @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#putObject
*/
public void putObject(String bucketName, String objectName, InputStream stream, long
size, String contextType) throws Exception {
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1).contentType(contextType).build());
}
/**
* 獲取?件信息
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @throws Exception https://docs.minio.io/cn/java-minioClient-api-reference.html#statObject
*/
public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 刪除?件
*
* @param bucketName bucket名稱
* @param objectName ?件名稱
* @throws Exception https://docs.minio.io/cn/java-minioClient-apireference.html#removeObject
*/
public void removeObject(String bucketName, String objectName) throws Exception {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/***
* 上傳視頻
* @param file
* @param bucketName
* @return
* @throws Exception
*/
public UploadResponse uploadVideo(MultipartFile file, String bucketName) throws Exception {
//判斷文件是否為空
if (null == file || 0 == file.getSize()) {
return null;
}
//判斷存儲桶是否存在 不存在則創(chuàng)建
createBucket(bucketName);
//文件名
String originalFilename = file.getOriginalFilename();
//新的文件名 = 時間戳_隨機數(shù).后綴名
assert originalFilename != null;
long now = System.currentTimeMillis() / 1000;
String fileName = DateUtil.format(DateUtil.date(),"yyyyMMdd")+"_"+ now + "_" + new Random().nextInt(1000) +
originalFilename.substring(originalFilename.lastIndexOf("."));
//開始上傳
log.info("file大小:{}",file.getSize());
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
file.getInputStream(), file.getSize(), -1)
.contentType("video/mp4")
.build());
String url = minioProperties.getEndpoint() + "/" + bucketName + "/" + fileName;
String urlHost = minioProperties.getNginxHost() + "/" + bucketName + "/" + fileName;
return new UploadResponse(url, urlHost);
}
}測試上傳文件 Controller
package com.sqm.minio_demo.controller;
import com.sqm.minio_demo.entity.ResultData;
import com.sqm.minio_demo.entity.UploadResponse;
import com.sqm.minio_demo.util.MinioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@Slf4j
public class TestController {
@Autowired
private MinioUtil minioUtil;
/**
* @author: xx
* @date: 2022/5/25 15:32
* @description: 上傳文件
*/
@PostMapping("/upload")
public ResultData minioUpload(@RequestParam(value = "file") MultipartFile file){
UploadResponse response = null;
try {
response = minioUtil.uploadFile(file, "bucket01");
} catch (Exception e) {
log.error("上傳失敗",e);
}
return ResultData.ok(response);
}
/**
* @author: xx
* @date: 2022/5/25 15:32
* @description: 上傳視頻
*/
@PostMapping("/uploadVideo")
public ResultData uploadVideo(@RequestParam(value = "file") MultipartFile file){
UploadResponse response = null;
try {
response = minioUtil.uploadVideo(file, "video-test");
} catch (Exception e) {
log.error("上傳失敗",e);
}
return ResultData.ok(response);
}
}測試上傳


控制臺也可以看到上傳的視頻

總結(jié)
到此這篇關(guān)于SpringBoot整合Minio實現(xiàn)上傳文件的文章就介紹到這了,更多相關(guān)SpringBoot整合Minio上傳文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解spring security之httpSecurity使用示例
這篇文章主要介紹了詳解spring security之httpSecurity使用示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
淺談Java中SimpleDateFormat 多線程不安全原因
SimpleDateFormat是Java中用于日期時間格式化的一個類,本文主要介紹了淺談Java中SimpleDateFormat 多線程不安全原因,感興趣的可以了解一下2024-01-01
MyBatis-Plus實現(xiàn)優(yōu)雅處理JSON字段映射
默認(rèn)情況下,MyBatis-Plus 是不支持直接映射 JSON 類型的,這時候就需要借助其他的方法,下面小編就來和大家講講MyBatis-Plus如何優(yōu)雅處理JSON字段映射吧2025-04-04
Spring?session?redis?修改默認(rèn)的序列化方法(案例)
這篇文章主要介紹了Spring?session?redis?修改默認(rèn)的序列化方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04

