前置知识:阅读这篇文章前,确保你已经会用Docker、SpringBoot、以及掌握了一些常见的开发规范。
注意:本文针对的是较小文件的上传,如图片等。如果是长视频等大文件,可能还需要用到文件分片、断点续传等,而对于这些,本文暂未提及。
1、搭建minio服务端(用Docker)
拉取镜像:
docker pull minio/minio
创建运行容器:
docker run -p 9000:9000 -p 9090:9090 \
--name minio \
-e "MINIO_ROOT_USER=账号" \
-e "MINIO_ROOT_PASSWORD=密码" \
-v /app/minio/data:/data \
-v /app/minio/config:/root/.minio \
-d minio/minio:latest \
server /data --console-address ":9090" --address ":9000"
参数及可选项说明:
注意:账号长度必须大于等于5,密码长度必须大于等于8位。
server /data:这是传递给MinIO程序的命令行参数,告诉MinIO以服务器模式运行,并且使用/data目录作为其数据存储位置。
--console-address ":9090":这个可选项指定MinIO控制台服务的端口。必须和server /data在同一行。
--address ":9000":这个可选项指定MinIO API服务的监听地址和端口。必须和server /data在同一行。
浏览器输入ip:9090,如:192.168.186.100:9090,即可访问minio服务端的控制台。
2、创建桶
可以直接在minio控制台创建桶,也可以之后在代码中创建桶。创建完不要忘记将桶的读写权限设为public。
3、项目中使用minIO
3.1、🍀引依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.1</version>
</dependency>
3.2、🍀application.yml中配置连接信息
注意:下面这段是自定义的配置,等下需要我们自己用@Value注解或者@ConfigurationProperties注解来读取yml配置。
minio:
endpoint: http://ip地址:9000 # 注意这里一定要加“http://”,否则可能出错
accessKey: 账号
secretKey: 密码
bucket: 桶名称
3.3、🍀读取yml配置
在properties包下新建MinioProperties类:
package com.daomi.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucket;
}
3.4、🍀配置类中声明minio的客户端对象
在config包下新建配置类MinioConfig:
package com.daomi.config;
import com.daomi.properties.MinioProperties;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient(){
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
}
3.5、🍀写工具类
添加下面的依赖:
<!--j256工具获取文件类型(mimetype)-->
<dependency>
<groupId>com.j256.simplemagic</groupId>
<artifactId>simplemagic</artifactId>
<version>1.17</version>
</dependency>
<!--Apache工具包,计算文件md5值-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.1</version>
</dependency>
util包下新建MinioUtil工具类(下面TODO的地方,可能是需要你根据自己项目的情况来改动的):
package com.aa.util;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioClient minioClient;
/**
* 上传文件到minio,并返回访问该文件的url
* @param bucket 桶名称
* @param multipartFile MultipartFile对象
* @return
*/
public String uploadFile(String bucket, MultipartFile multipartFile){
String localFileAbsolutePath = null;
String minioPath = null;
try {
// TODO 下面用this来调用的都是抽取出来的方法,我这里将它们都放在这个工具类下了。你也可以将这些方法放到其他工具类下
// 获取文件扩展名
String extension = this.getExtension(multipartFile);
// 获取mimeType
String mimeType = this.getMimeType(extension);
// 获取本地文件的路径(源路径)
File localFile = File.createTempFile("minio", ".temp");
multipartFile.transferTo(localFile);
localFileAbsolutePath = localFile.getAbsolutePath();
// 构造minio中的路径(目标路径)=年+月+日+md5值+扩展名
// TODO 下面的folder是上传后的文件在桶里面的路径。你也可以不指定,若不指定文件上传后就直接在桶下
String folder = "other/" + DateUtil.generateFolderOfCurrentDate();
// TODO 实际开发中,通常将文件的md5值作为文件名。当然你也可以用其他的作为文件名
String fileName = DigestUtils.md5Hex(new FileInputStream(localFile));
minioPath = folder + fileName + extension;
// 构造UploadObjectArgs对象
UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
.bucket(bucket)
.filename(localFileAbsolutePath)// 本地文件的路径(源路径)
.object(minioPath)// minio中的路径(目标路径)
.contentType(mimeType)
.build();
// 上传文件
minioClient.uploadObject(uploadObjectArgs);
} catch (Exception e) {
log.error("文件上传失败!本地源文件路径:{},minio目标文件路径:{},错误信息:{}", localFileAbsolutePath, minioPath, e.getMessage());
e.printStackTrace();
// TODO 这里你可以抛出你自定义的业务异常
// throw new FileUploadFailedException(MessageConstant.FILE_UPLOAD_FAILED);
}
log.info("文件上传成功!本地源文件路径:{},minio目标文件路径:{}", localFileAbsolutePath, minioPath);
// 返回访问该文件的url
return "/" + bucket + "/" + minioPath;
}
/**
* 根据MultipartFile对象获取其文件扩展名
* @param multipartFile MultipartFile对象
* @return
*/
private static String getExtension(MultipartFile multipartFile) {
String filename = multipartFile.getOriginalFilename();
String extension = filename.substring(filename.lastIndexOf("."));
return extension;
}
/**
* 根据扩展名获取文件类型(mimetype)
* @param extension 文件的扩展名,如:“.png”
* @return
*/
public static String getMimeType(String extension) {
if (extension == null){
extension = "";
}
// 根据文件扩展名获取文件类型
String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);
if (extensionMatch != null){
mimeType = extensionMatch.getMimeType();
}
return mimeType;
}
}
3.6、⚠注意事项
实际开发中,应该在上传文件到minio前,查询数据库中是否已经存了该文件的信息,并且为了保险起见,还应额外查minio中是否也已经存在了该文件。已存在就不用重复上传。
5261

被折叠的 条评论
为什么被折叠?



