一、背景
项目中多地方有“头像上传”、“附件上传”、“图片上传”、“根据url直接预览文件”等需求,虽然手写文件上传、下载等功能可以实现,但是后期文件管理,功能扩展起来会相当麻烦,因此准备引入开源且功能完善强大的文件存储服务系统minio。
二、安装教程
#创建相关文件夹
mkdir -p /home/minio
mkdir -p /home/minio/bin
mkdir -p /home/minio/data
#进入上面创建的bin目录下
cd /home/minio/bin
#下载minio(选择适合自己系统的版本,本文使用的是Linux版本)
wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio
下载完成后在目录/home/minio/bin下会有个minio,如下图:
继续执行命令授权
#进入/home/minio/bin目录
cd /home/minio/bin
#对刚刚下载的minio文件进行授权
chmod +x minio
执行命令将minio添加程Linux系统服务,这样以后就可以支持systemctl命令启动
#进入系统目录
cd /etc/systemd/system
#创建文件minio.service
vim minio.service
#编辑文件,将以下内容拷贝到minio.service文件中
[Unit]
Description=Minio
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/home/minio/bin/minio
[Service]
WorkingDirectory=/home/minio/
PermissionsStartOnly=true
ExecStart=/home/minio/bin/minio server /home/minio/data
ExecReload=/bin/ki11-S HUP $MAINPID
ExecStop=/bin/ki11 -S QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
完成上述步骤后,可通过以下命令启停minio等
#启动minio
systemctl start minio
#停止minio
systemctl stop minio
#查看minio状态
systemctl status minio
至此minio安装配置完成;接下来便是在springboot项目中集成minio,继续往下看
mino后台管理访问地址:ip:43041;默认账号:minioadmin/minioadmin
注意:如果无法访问以上地址,请确认服务器端口是否开放,如若未开放,执行命令
firewall-cmd --add-port=43041/tcp 开放43041端口
三、springboot项目集成minio
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.yml文件配置
spring:
servlet:
minio:
accesskey: minioadmin
secretkey: minioadmin
miniourl: http://ip:9000
#ip请替换为安装服务的ip,确保9000端口开放
3.minio配置类
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* minio配置类
*
* @author
*/
@Data
@Configuration
@ConfigurationProperties(value = "spring.servlet.minio")
public class MinioConfig
{
private String accesskey;
private String secretkey;
private String miniourl;
@Bean
public MinioClient minioClient(){
return MinioClient.builder()
.endpoint(miniourl)
.credentials(accesskey,secretkey)
.build();
}
}
至此,minio文件系统便搭建完成及配置完成,接下来便可使用了
4.相关minio的一些工具方法封装
/**
* 文件上传工具类
* @author hongwentao
*/
@Component
public class MinioUtils
{
@Resource
private MinioClient minioClient;
@Autowired
private MinioConfig minioConfig;
/**
* @param name
* 名字
* @Description 判断bucket是否存在,不存在则创建
*/
public boolean existBucket(String name)
{
boolean exists;
try
{
exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
if (!exists)
{
minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
exists = true;
}
}
catch (Exception e)
{
e.printStackTrace();
exists = false;
}
return exists;
}
/**
* @param bucketName
* 存储bucket名称
* @Description 创建存储bucket
*/
public Boolean makeBucket(String bucketName)
{
if(this.existBucket(bucketName)){
return true;
}
try
{
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
return true;
}
/**
* @param bucketName
* 存储bucket名称
* @Description 删除存储bucket
*/
public Boolean removeBucket(String bucketName)
{
if(!this.existBucket(bucketName)){
return true;
}
try
{
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
return true;
}
/**
* @param fileName
* 文件名称
* @param time
* 时间
* @Description 获取上传临时签名
*/
@SneakyThrows
public Map getPolicy(String fileName, ZonedDateTime time, String bucketName)
{
PostPolicy postPolicy = new PostPolicy(bucketName, time);
postPolicy.addEqualsCondition("key", fileName);
try
{
Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
HashMap<String, String> map1 = new HashMap<>();
map.forEach((k, v) -> {
map1.put(k.replaceAll("-", ""), v);
});
map1.put("host", minioConfig.getMiniourl() + "/" + bucketName);
return map1;
}
catch (Exception e)
{
throw new Exception(ExceptionEnums.ERROR_500.getMessage());
}
}
/**
* @param objectName
* 对象名称
* @param method
* 方法
* @param time
* 时间
* @param timeUnit
* 时间单位
* @Description 获取上传文件的url
*/
@SneakyThrows
public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit, String bucketName)
{
try
{
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(method)
.bucket(bucketName).object(objectName).expiry(time, timeUnit).build());
}
catch (Exception e)
{
throw new Exception(ExceptionEnums.ERROR_500.getMessage());
}
}
/**
* @param file
* 文件
* @param fileName
* 文件名称
* @Description 上传文件
*/
public void upload(MultipartFile file, String fileName, String bucketName) throws Exception
{
// 使用putObject上传一个文件到存储桶中。
InputStream inputStream = file.getInputStream();
// if (StringUtils.isNotBlank(path))
// {
// fileName = path + "/" + fileName;
// }
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName)
.stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build());
}
/**
* @param objectName
* 对象名称
* @param time
* 时间
* @param timeUnit
* 时间单位
* @Description 根据filename获取文件访问地址
*/
@SneakyThrows
public String getUrl(String objectName, int time, TimeUnit timeUnit, String bucketName)
{
String url = null;
try
{
url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET)
.bucket(bucketName).object(objectName).expiry(time, timeUnit).build());
}
catch (Exception e)
{
throw new Exception(ExceptionEnums.ERROR_500.getMessage());
}
return url;
}
/**
* @Description description: 下载文件
*/
public void download(String bucket, String fileName, HttpServletResponse response) throws Exception
{
InputStream inputStream = minioClient
.getObject(GetObjectArgs.builder().bucket(bucket).object(fileName).build());
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) > 0)
{
outputStream.write(bytes, 0, len);
}
outputStream.close();
}
/**
* @param objectFile
* 对象文件
*/
public String getFileUrl(String objectFile, String bucketName)
{
try
{
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET)
.bucket(bucketName).object(objectFile).build());
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* 创建文件夹
*
* @param bucketName
* @param path
* 记得路径最后加一个/ 例如 bucket/folder/
*/
public void createFolder(String bucketName, String path) throws Exception
{
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(path)
.stream(new ByteArrayInputStream(new byte[] {}), 0, -1).build());
}
/**
* 删除文件
*
* @param bucketName
* 库名称
* @param fileName
* 文件名称
* @return
*/
public void removeObject(String bucketName, String fileName) throws Exception
{
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
}
/**
* 文件夹删除
*
* @param bucketName
* @param fileName
* @throws Exception
*/
public void removeDirectory(String bucketName, String fileName) throws Exception
{
Iterable<Result<Item>> results = minioClient
.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(fileName).recursive(false).build());
for (Result<Item> item : results)
{
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(item.get().objectName()).build());
}
}
}