SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳
什么是minio
MinIO是一個(gè)基于Go實(shí)現(xiàn)的高性能、兼容S3協(xié)議的對(duì)象存儲(chǔ)。它采用GNU AGPL v3開源協(xié)議,項(xiàng)目地址是https://github.com/minio/minio。
引用官網(wǎng):
MinIO是根據(jù)GNU Affero通用公共許可證v3.0發(fā)布的高性能對(duì)象存儲(chǔ)。它與Amazon S3云存儲(chǔ)服務(wù)兼容。使用MinIO構(gòu)建用于機(jī)器學(xué)習(xí),分析和應(yīng)用程序數(shù)據(jù)工作負(fù)載的高性能基礎(chǔ)架構(gòu)。
官網(wǎng)地址:
https://min.io/
文檔地址:
https://docs.min.io/
一. 使用docker 搭建minio 服務(wù)
GNU / Linux和macOS
docker?run?-p?9000:9000?\
??--name?minio1?\
??-v?/mnt/data:/data?\
??-e?"MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE"?\
??-e?"MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"?\
??minio/minio?server?/data
windows
docker?run?-p?9000:9000?\
??--name?minio1?\
??-v?D:\data:/data?\
??-e?"MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE"?\
??-e?"MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"?\
??minio/minio?server?/data
MINIO_ROOT_USER:為用戶keyMINIO_ROOT_PASSWORD:為用戶密鑰
以上搭建的都是單機(jī)版的。想要了解分布式 的方式請(qǐng)查看官網(wǎng)文檔。

這就是在win的docker上運(yùn)行的。
更多開源項(xiàng)目:https://www.yoodb.com/projects/springboot-user-manger.html
當(dāng)啟動(dòng)后在瀏覽器訪問http://localhost:9000就可以訪問minio的圖形化界面了,如圖所示:


二. 下面開始搭建springboot 環(huán)境
初始化一個(gè)springboot項(xiàng)目大家都會(huì),這里不多做介紹。
主要是介紹需要引入的依賴:
??
????????????org.springframework.boot
????????????spring-boot-starter-thymeleaf
????????
?????????
????????????io.minio
????????????minio
????????????8.2.1
????????
?????????
????????????org.projectlombok
????????????lombok
????????????true
????????
依賴可以官方文檔里找:https://docs.min.io/docs/java-client-quickstart-guide.html
下面介紹配置文件:
spring:
??servlet:
????multipart:
??????max-file-size:?10MB
??????max-request-size:?10MB
#minio配置
??minio:
????access-key:?AKIAIOSFODNN7EXAMPLE??????#key就是docker初始化是設(shè)置的,密鑰相同
????secret-key:?wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
????url:?http://localhost:9000
????bucket-name:?wdhcr
??thymeleaf:
????cache:?false
創(chuàng)建minio的配置類:
@Configuration
@ConfigurationProperties(prefix?=?"spring.minio")
@Data
public?class?MinioConfiguration?{
????private?String?accessKey;
????private?String?secretKey;
????private?String?url;
????private?String?bucketName;
????@Bean
????public?MinioClient?minioClient()?{
????????return?MinioClient.builder()
????????????????.endpoint(url)
????????????????.credentials(accessKey,?secretKey)
????????????????.build();
????}
}
使用配置屬性綁定進(jìn)行參數(shù)綁定,并初始化一個(gè)minio client對(duì)象放入容器中。
下面就是我封裝的minio client 操作minio的簡(jiǎn)單方法的組件。
@Component
public?class?MinioComp?{
????@Autowired
????private?MinioClient?minioClient;
????@Autowired
????private?MinioConfiguration?configuration;
????/**
?????*?@description:?獲取上傳臨時(shí)簽名,公眾 號(hào)Java精選
?????*?@dateTime:?2021/5/13?14:12
?????*/
????public?Map?getPolicy(String?fileName,?ZonedDateTime?time)?{
????????PostPolicy?postPolicy?=?new?PostPolicy(configuration.getBucketName(),?time);
????????postPolicy.addEqualsCondition("key",?fileName);
????????try?{
????????????Map?map?=?minioClient.getPresignedPostFormData(postPolicy);
????????????HashMap?map1?=?new?HashMap<>();
????????????map.forEach((k,v)->{
???????????????map1.put(k.replaceAll("-",""),v);
???????????});
????????????map1.put("host",configuration.getUrl()+"/"+configuration.getBucketName());
????????????return?map1;
????????}?catch?(ErrorResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(InsufficientDataException?e)?{
????????????e.printStackTrace();
????????}?catch?(InternalException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidKeyException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}?catch?(NoSuchAlgorithmException?e)?{
????????????e.printStackTrace();
????????}?catch?(ServerException?e)?{
????????????e.printStackTrace();
????????}?catch?(XmlParserException?e)?{
????????????e.printStackTrace();
????????}
????????return?null;
????}
????/**
?????*?@description:?獲取上傳文件的url,公眾 號(hào)Java精選,有驚喜!
?????*?@dateTime:?2021/5/13?14:15
?????*/
????public?String?getPolicyUrl(String?objectName,?Method?method,?int?time,?TimeUnit?timeUnit)?{
????????try?{
????????????return?minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
????????????????????.method(method)
????????????????????.bucket(configuration.getBucketName())
????????????????????.object(objectName)
????????????????????.expiry(time,?timeUnit).build());
????????}?catch?(ErrorResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(InsufficientDataException?e)?{
????????????e.printStackTrace();
????????}?catch?(InternalException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidKeyException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}?catch?(NoSuchAlgorithmException?e)?{
????????????e.printStackTrace();
????????}?catch?(XmlParserException?e)?{
????????????e.printStackTrace();
????????}?catch?(ServerException?e)?{
????????????e.printStackTrace();
????????}
????????return?null;
????}
????/**
?????*?@description:?上傳文件
?????*?@dateTime:?2021/5/13?14:17
?????*/
????public?void?upload(MultipartFile?file,?String?fileName)?{
????????//?使用putObject上傳一個(gè)文件到存儲(chǔ)桶中。
????????try?{
????????????InputStream?inputStream?=?file.getInputStream();
????????????minioClient.putObject(PutObjectArgs.builder()
????????????????????.bucket(configuration.getBucketName())
????????????????????.object(fileName)
????????????????????.stream(inputStream,?file.getSize(),?-1)
????????????????????.contentType(file.getContentType())
????????????????????.build());
????????}?catch?(ErrorResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(InsufficientDataException?e)?{
????????????e.printStackTrace();
????????}?catch?(InternalException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidKeyException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}?catch?(NoSuchAlgorithmException?e)?{
????????????e.printStackTrace();
????????}?catch?(ServerException?e)?{
????????????e.printStackTrace();
????????}?catch?(XmlParserException?e)?{
????????????e.printStackTrace();
????????}
????}
??/**
?????*?@description:?根據(jù)filename獲取文件訪問地址
?????*?@dateTime:?2021/5/17?11:28
?????*/
????public?String?getUrl(String?objectName,?int?time,?TimeUnit?timeUnit)?{
????????String?url?=?null;
????????try?{
????????????url?=?minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
????????????????????.method(Method.GET)
????????????????????.bucket(configuration.getBucketName())
????????????????????.object(objectName)
????????????????????.expiry(time,?timeUnit).build());
????????}?catch?(ErrorResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(InsufficientDataException?e)?{
????????????e.printStackTrace();
????????}?catch?(InternalException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidKeyException?e)?{
????????????e.printStackTrace();
????????}?catch?(InvalidResponseException?e)?{
????????????e.printStackTrace();
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}?catch?(NoSuchAlgorithmException?e)?{
????????????e.printStackTrace();
????????}?catch?(XmlParserException?e)?{
????????????e.printStackTrace();
????????}?catch?(ServerException?e)?{
????????????e.printStackTrace();
????????}
????????return?url;
????}
}
簡(jiǎn)單說(shuō)明:
使用MultipartFile接收前端文件流,再上傳到minio。 構(gòu)建一個(gè)formData的簽名數(shù)據(jù),給前端,讓前端之前上傳到minio。 構(gòu)建一個(gè)可以上傳的臨時(shí)URL給前端,前端通過攜帶文件請(qǐng)求該URL進(jìn)行上傳。 使用filename請(qǐng)求服務(wù)端獲取臨時(shí)訪問文件的URL。(最長(zhǎng)時(shí)間為7 天,想要永久性訪問,需要其他設(shè)置,這里不做說(shuō)明。) 推薦,公眾 號(hào)Java精選,回復(fù)java面試,獲取面試資料,支持在線刷題。
下面展示頁(yè)面html,使用的是VUE+element-ui進(jìn)行渲染。
????"UTF-8">
????
????"stylesheet"?href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
????上傳圖片
"app">
????"2">
????????"8">
????????????"div-center-class">
????????????????"">
????????????????????傳統(tǒng)上傳
????????????????????????????????????????????????class="upload-demo"
????????????????????????????action="#"
????????????????????????????drag
????????????????????????????:http-request="uploadHandle">
????????????????????????"el-icon-upload">
????????????????????????"el-upload__text">將文件拖到此處,或點(diǎn)擊上傳
????????????????????????"el-upload__tip"?slot="tip">只能上傳jpg/png文件,且不超過500kb
????????????????????
????????????????????"imgUrl">
????????????????????????"imgUrl"?style="width:?40px;height:?40px">
????????????????????
????????????????
????????????
????????
????????"8">
????????????"div-center-class">
????????????????"">
????????????????????前端formData直傳
????????????????????????????????????????????????class="upload-demo"
????????????????????????????action="#"
????????????????????????????drag
????????????????????????????:http-request="httpRequestHandle">
????????????????????????"el-icon-upload">
????????????????????????"el-upload__text">將文件拖到此處,或點(diǎn)擊上傳
????????????????????????"el-upload__tip"?slot="tip">只能上傳jpg/png文件,且不超過500kb
????????????????????
????????????????????"directUrl">
????????????????????????"directUrl"?style="width:?40px;height:?40px">
????????????????????
????????????????
????????????
????????
????????"8">
????????????"div-center-class">
????????????????"">
????????????????????前端Url直傳
????????????????????????????????????????????????class="upload-demo"
????????????????????????????action="#"
????????????????????????????drag
????????????????????????????:http-request="UrlUploadHandle">
????????????????????????"el-icon-upload">
????????????????????????"el-upload__text">將文件拖到此處,或點(diǎn)擊上傳
????????????????????????"el-upload__tip"?slot="tip">只能上傳jpg/png文件,且不超過500kb
????????????????????
????????????????????"uploadUrl">
????????????????????????"uploadUrl"?style="width:?40px;height:?40px">
????????????????????
????????????????
????????????
????????
????

頁(yè)面的效果就如上圖所示。
可以分別體驗(yàn)不同的實(shí)現(xiàn)效果。
以上就是使用springboot搭建基于minio的高性能存儲(chǔ)服務(wù)的全部步驟了。
本項(xiàng)目地址:
https://gitee.com/jack_whh/minio-upload
