安装
Docker
docker run --name minio \
-d --restart=always \
-p 9000:9000 \
-p 9001:9001 \
--network tool-net --network-alias minio \
-e "MINIO_ACCESS_KEY=admin" \
-e "MINIO_SECRET_KEY=admin123456" \
-v minio_data:/data \
-v min_config:/root/.minio \
minio/minio server /data --console-address ":9001"
-
注意:
--console-address
当前最新版必须指定控制台端口(浏览器页面访问端口),如果不指定,将会随机生成端口,不方便服务器开启防火墙- Minio 默认api addres 的端口是9000,浏览器访问9000端口时,会跳转到控制台端口
--console-address
- 一定要将Minio的数据目录挂载到主机上,防止删除容器时,删除了储存的数据
控制台
进入控制台可以通过9000端口,他会自动跳转到控制台的9001端口,也可以直接通过9001端口进入控制台
登录
控台登录账户和密码是Docker 启动时的MINIO_ACCESS_KEY
参数和MINIO_SECRET_KEY
参数
桶
桶(Bucket):Minio 通过桶去存储文件,存储文件时需要指定目标桶才可以存储,
创建桶
点击Bucket->create bucket
配置桶
1. 基础信息
右侧有关于配置信息的解释
- Bucket Name: 桶名
- Version:开启统一对象多版本
- Object locking:对象锁:防止对象被删除,如果不设置
Retention
,那么文件将不能被删除 - Quota:配额,限制桶内的对象数量
- Retention:保留策略,设置文件再桶内存活的周期,开启后
Object locking
会自动开启,因为文件保留期间,对象是禁止删除的- Model:策略模式:1. Compliance:在
Validity
天后被删除 2. Governance 在Validity
天后删除在生命周期内未操作的对象 - Validity:生命周期:对象至少存活多少天
- Model:策略模式:1. Compliance:在
2. 桶内对象的操作策略
点击Bucket-->Manage--> Access Rules
上传后的对象名格式:
[Rule alias]_[Object Name].[文件后缀]
- Prefix:Rule 别名
- Access:决策
身份 Identity
身份管理
账户 Users
创建、管理Minio账户
账户组 Groups
对Minio用户进行分组
服务账户 Services Accounts
创建、管理服务账户
这里创建的账户,主要用于开发,也是最常用的
Create Service Account
- 点击
create service account
,创建Service Account
Minio会自动创建键账户和密码,如果开发这需要配置使用权限,可开启下方的Restrict beyond user policy
- 点击create,会提示你保存密钥信息,个人建议下载密钥i信息,因为密钥是随机值,不方便记忆
使用
Spring boot
依赖
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.1</version>
</dependency>
配置类
MinIOProperties.java
Minio 参数 Properties类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@Data
@ConfigurationProperties(prefix = "minio")
public class MinIOProperties {/*** 连接url*/private String endpoint;/*** Service Account——accesskey*/private String accessKey;/*** Service Account——secretKey*/private String secretKey;/*** 桶*/private String bucket;/*** 分片大小*/private long partSize=5 * 1024 * 1024;
}
MinIOHelper,java
Minio工具类,用于编写操作Minio的具体方法
该类在AutoConfig类中已注入到IOC容器中,方便开发者在service或controller中调用
import cn.hutool.core.util.ObjectUtil;
import io.minio.*;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;import java.io.FileNotFoundException;public class MinIOHelper {@Autowiredprivate MinioClient client;@Autowiredprivate MinIOProperties properties;/*** 创建桶** @param bucketName 通名称*/@SneakyThrowspublic void createBucket(String bucketName) {BucketExistsArgs bucket = BucketExistsArgs.builder().bucket(bucketName).build();if (!client.bucketExists(bucket)) {MakeBucketArgs make = MakeBucketArgs.builder().bucket(bucketName).build();client.makeBucket(make);}}/*** 上传文件** @param file 文件* @param bucketName 存储桶* @return*/public String uploadFile(MultipartFile file, String bucketName, FileRule rule) throws FileNotFoundException {// 判断上传文件是否为空if (ObjectUtil.isEmpty(file) || 0 == file.getSize()) {throw new FileNotFoundException();}//检查桶名if (ObjectUtil.isEmpty(bucketName)) {bucketName = properties.getBucket();if (ObjectUtil.isEmpty(bucketName)) {throw new MinioUploadExecption("Bucket 必填");}}if (ObjectUtil.isEmpty(rule)) {rule = FileRule.READ_WRITE;}try {// 判断存储桶是否存在createBucket(bucketName);// 文件名String originalFilename = file.getOriginalFilename();// 新的文件名 = 存储桶名称_时间戳.后缀名String fileName = rule.getLabel() + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));// 开始上传PutObjectArgs build = PutObjectArgs.builder().bucket(bucketName).object(fileName).contentType(file.getContentType()).stream(file.getInputStream(), file.getSize(), properties.getPartSize()).build();ObjectWriteResponse response = client.putObject(build);return bucketName + "/" + fileName;} catch (Exception e) {throw new MinioUploadExecption("上传失败");}}
}
FileRule.java
该枚举类实现的是Bucket Access Rules配置内容,方便开发者调用,不在用于记忆前缀
public enum FileRule {WRITE_ONLY(0, "w"),READ_ONLY(1, "r"),READ_WRITE(2,"r-w");private Integer value;private String label;FileRule(Integer value, String label) {this.value = value;this.label = label;}public Integer getValue() {return value;}public String getLabel() {return label;}
}
EnableOSS.java
Minio启动注解
将该类配置在对应服务的启动类上,即可
服务启动时spring 会自动去寻找@Import({MinIOAutoCondig.class})
的自动配置类,从而实现自动配置
import org.springframework.context.annotation.Import;import java.lang.annotation.*;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MinIOAutoCondig.class})
public @interface EnableOSS {
}
MinIOAutoCondig.java
Minio 自动配置类
因为Minio 本身就是未分布式微服务而设计的,所以必然存在多模块,而为了调用方便,所以本文使用启动注解加自动配置类的方式调用Minio
import cn.hutool.core.util.ObjectUtil;
import io.minio.MinioClient;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@ConditionalOnClass({MinioClient.class})
@Configuration
@EnableConfigurationProperties({MinIOProperties.class})
public class MinIOAutoCondig {@Autowiredprivate MinIOProperties minIOProperties;private MinioClient client;@Beanpublic MinioClient minioClient() {if (ObjectUtil.isEmpty(minIOProperties.getEndpoint())) {throw new BeanCreationException("minio.endpoint don't null");}if (ObjectUtil.isEmpty(minIOProperties.getAccessKey())) {throw new BeanCreationException("minio.access-key don't null");}if (ObjectUtil.isEmpty(minIOProperties.getSecretKey())) {throw new BeanCreationException("minio.secret-key don't null");}client= MinioClient.builder().endpoint(minIOProperties.getEndpoint()).credentials(minIOProperties.getAccessKey(), minIOProperties.getSecretKey()).build();return client;}@Beanpublic MinIOHelper minIOHelper(){return new MinIOHelper();}
}
调用
Properties
minio.access-key
、minio.secret-key
分别对应的是Services Accounts 中创建的账户
minio.endpoint=http://xx.xx.xx.xx:9000
minio.bucket=client
minio.access-key=gutgSnXxxxxH2zgxxx
minio.secret-key=EOiOz9KFxxxxmaC8uGLxxxxQlJINVPSxxx
Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.cxjfun.jdoc.client.server.vo.UploadFile;
import top.cxjfun.jdoc.common.CustomException;
import top.cxjfun.jdoc.common.db.oss.MinIOHelper;import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;@RestController
@RequestMapping("/file")
public class FileController {@Autowiredprivate MinIOHelper minIOHelper;@PostMapping("/upload")@ResponseBodypublic String upload(MultipartFile file, HttpServletRequest request) {try {String filePath = minIOHelper.uploadFile(file, null, null);return filePath;} catch (FileNotFoundException e) {throw new CustomException("FILE_NOT_FOUND", "文件未找到");}}
}
FAQ
io.minio.S3Base.(S3Base.java:105)
An attempt was made to call a method that does not exist. The attempt was made from the following location:io.minio.S3Base.<clinit>(S3Base.java:105)The following method did not exist:okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody;The method's class, okhttp3.RequestBody, is available from the following locations:jar:file:/D:/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar!/okhttp3/RequestBody.classThe class hierarchy was loaded from the following locations:okhttp3.RequestBody: file:/D:/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jarAction:Correct the classpath of your application so that it contains a single, compatible version of okhttp3.RequestBody
问题原因
Spring boot 和minio 依赖冲突产生的原因是因为spring boot 的okhttp 和minio 的okhttp冲突
解决办法
降低minio版本:8.3.0 —> 8.2.1