SpringBoot整合MinIO实现文件的分片上传、秒传、续传!

概述

Spring Boot整合Minio后,前端的文件上传有两种方式:

  1. 文件上传到后端,由后端保存到Minio

    这种方式好处是完全由后端集中管理,可以很好的做到、身份验证、权限控制、文件与处理等,并且可以做一些额外的业务逻辑,比如生成缩略图、提取元数据等。

    缺点也很明显:

    所以,实际上我们不会把文件传到后端,而是直接传给Minio,其实这也符合OSS服务的使用方式。

    • 延迟时间高了,本来花费上传一次文件的时间,现在多了后端保存到Minio的时间

    • 后端资源占用,后端本来可以只处理业务请求,现在还要负责文件流,增加了性能压力

    • 单点故障,Minio即便做了集群,但是如果后端服务器故障,也会导致Minio不可用

  2. 文件向后端申请上传凭证,然后直接上传到Minio

    为了避免Minio被攻击,我们需要结合后端,让后端生成并返回一个有时效的上传凭证,前端拿着这个凭证才能去上传,通过这种方式,我们可以做到一定程度的权限控制,本文要分享的就是这种方式。

环境准备

部署好的Minio环境:http://mylocalhost:9001

Spring Boot整合Minio

先引入Minio依赖

pom.xml
<dependency>
????<groupId>io.minio</groupId>
????<artifactId>minio</artifactId>
????<version>7.1.0</version>
</dependency>

然后定义配置信息

application.yml
minio:
??endpoint:?http://mylocalhost:9001
??accessKey:?minio
??secretKey:?minio123
??bucket:?demo

定义一个属性类

@Component
@ConfigurationProperties(prefix?=?"minio")
public?class?MinioProperties?{
????/**
?????*?对象存储服务的URL
?????*/
????private?String?endpoint;
????/**
?????*?Access?key就像用户ID,可以唯一标识你的账户
?????*/
????private?String?accessKey;
????/**
?????*?Secret?key是你账户的密码
?????*/
????private?String?secretKey;

????/**
?????*?默认文件桶
?????*/
????private?String?bucket;
????
????...
}

定义Minio配置类

@Configuration
public?class?MinioConfig?{
????@Bean
????public?MinioClient?minioClient(MinioProperties?properties){
????????try?{
????????????MinioClient.Builder?builder?=?MinioClient.builder();
????????????builder.endpoint(properties.getEndpoint());
????????????if?(StringUtils.hasLength(properties.getAccessKey())?&&?StringUtils.hasLength(properties.getSecretKey()))?{
????????????????builder.credentials(properties.getAccessKey(),properties.getSecretKey());
????????????}
????????????return?builder.build();
????????}?catch?(Exception?e)?{
????????????return?null;
????????}
????}
}

现在启动服务即可。

上传凭证

写一个接口,返回上传凭证

@RequestMapping(value?=?"/presign",?method?=?{RequestMethod.POST})
public?Map<String,?String>?presign(@RequestBody?PresignParam?presignParam)?{
????//?如果前端不指定桶,那么给一个默认的
????if?(StringUtils.isEmpty(presignParam.getBucket()))?{
????????presignParam.setBucket("demo");
????}

????//?前端不指定文件名称,就给一个UUID
????if?(StringUtils.isEmpty(presignParam.getFilename()))?{
????????presignParam.setFilename(UUID.randomUUID().toString());
????}

????//?如果想要以子目录的方式保存,就在前面加上斜杠来表示
????//????????presignParam.setFilename("/2023/"?+?presignParam.getFilename());

????//?设置凭证过期时间
????ZonedDateTime?expirationDate?=?ZonedDateTime.now().plusMinutes(10);
????//?创建一个凭证
????PostPolicy?policy?=?new?PostPolicy(presignParam.getBucket(),?presignParam.getFilename(),?expirationDate);
????//?限制文件大小,单位是字节byte,也就是说可以设置如:只允许10M以内的文件上传
????//????????policy.setContentRange(1,?10?*?1024);
????//?限制上传文件请求的ContentType
????//????????policy.setContentType("image/png");

????try?{
????????//?生成凭证并返回
????????final?Map<String,?String>?map?=?minioClient.presignedPostPolicy(policy);
????????for?(Map.Entry<String,?String>?entry?:?map.entrySet())?{
????????????System.out.println(entry.getKey()?+?"?=?"?+?entry.getValue());
????????}
????????return?map;
????}?catch?(MinioException?|?InvalidKeyException?|?IOException?|?NoSuchAlgorithmException?e)?{
????????e.printStackTrace();
????}

????return?null;
}

上面的示例代码可以知道,我们还可以加一些权限认证,以判断用户是否有以下权限:

  • 上传权限

  • 可上传的文件大小

  • 可上传的文件类型

请求参数类:

public?class?PresignParam?{
????//?桶名
????private?String?bucket;

????//?文件名
????private?String?filename;
????
????...
}

这个接口的返回结果是:

bucket:?demo
x-amz-date:?20230831T042351Z
好的,我来为您介绍一下Spring Boot整合MinIO实现分片上传的代码实现: 1. 首先,在pom.xml中添加MinIO依赖: ```xml <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.4.3</version> </dependency> ``` 2. 配置MinIO客户端: ```java @Configuration public class MinioConfig { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.accessKey}") private String accessKey; @Value("${minio.secretKey}") private String secretKey; @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } } ``` 3. 创建分片上传控制器: ```java @RestController @RequestMapping("/minio") public class MinioController { @Autowired private MinioClient minioClient; @PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) throws Exception { String bucketName = "your-bucket-name"; String objectName = file.getOriginalFilename(); String uploadId = minioClient.getUploadId( GetUploadIdArgs.builder() .bucket(bucketName) .object(objectName) .build()); // 分片大小设置为5MB long partSize = 5 * 1024 * 1024; long fileSize = file.getSize(); int parts = (int) (fileSize / partSize); if (fileSize % partSize != 0) { parts++; } List<Part> partList = new ArrayList<>(); for (int i = 1; i <= parts; i++) { long offset = (i - 1) * partSize; long length = (i * partSize) > fileSize ? (fileSize - (i - 1) * partSize) : partSize; InputStream is = file.getInputStream(); is.skip(offset); UploadPartResponse uploadPartResponse = minioClient.uploadPart( UploadPartArgs.builder() .bucket(bucketName) .object(objectName) .uploadId(uploadId) .partNumber(i) .stream(is, length, -1) .build()); partList.add(new Part(i, uploadPartResponse.etag())); } minioClient.completeMultipartUpload( CompleteMultipartUploadArgs.builder() .bucket(bucketName) .object(objectName) .uploadId(uploadId) .parts(partList) .build()); return "Upload Success"; } } ``` 这段代码实现了以下功能: 1. 使用MinIO客户端配置Bean。 2. 创建一个上传接口,接收文件并开始分片上传。 3. 获取文件大小并计算分片数量。 4. 循环上传每个分片。 5. 上传完成后,调用completeMultipartUpload完成整个文件上传。 使用这种方法,您可以实现文件上传,同时也能提高上传的稳定性和效率。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值