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)文章
基于SpringBoot項目實現(xiàn)Docker容器化部署的主要步驟
部署SpringBoot項目到Docker容器涉及選擇Java運行時環(huán)境的基礎(chǔ)鏡像、構(gòu)建包含應(yīng)用程序的Docker鏡像、編寫Dockerfile、使用docker build命令構(gòu)建鏡像和使用docker run命令運行Docker容器等步驟2024-10-10springBoot Junit測試用例出現(xiàn)@Autowired不生效的解決
這篇文章主要介紹了springBoot Junit測試用例出現(xiàn)@Autowired不生效的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Java調(diào)用Pytorch實現(xiàn)以圖搜圖功能
這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用Pytorch實現(xiàn)以圖搜圖功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解一下2023-06-06在Spring Boot中使用Spark Streaming進行實時數(shù)據(jù)處理和流式計算的步驟
這篇文章主要介紹了在Spring Boot中使用Spark Streaming進行實時數(shù)據(jù)處理和流式計算,通過本文的介紹,我們了解了在Spring Boot中使用Spark Streaming進行實時數(shù)據(jù)處理和流式計算的詳細(xì)步驟,需要的朋友可以參考下2024-03-03