1.minio下载
windods
https://docs.min.io/cn/minio-quickstart-guide.html linux
minio
http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
mc
http://dl.minio.org.cn/client/mc/release/linux-amd64/mc
linxu安装
chmod +x minio
./minio server /usr/local/minio/data #关闭后Minio也会关闭
nohup /usr/local/minio/minio server /usr/local/minio/data > /usr/local/minio/data/minio.log 2>&1 & #后台启动
docker 安装minio
#获取镜像
docker pull minio/minio
#在服务器上创建minio文件上传目录
mkdir -p /data/docker/minio
#修改挂载目录权限
chown -R 1000:1000 /data/docker/minio
chmod -R 755 /data/docker/minio
#启动服务
docker run -d -p 9000:9000 -p 9001:9001 --restart=always --privileged=true --name minio -e "MINIO_ROOT_USER=minio" -e "MINIO_ROOT_PASSWORD=miniotest" -v /data/docker/minioFiles:/data minio/minio server /data --console-address ":9001"
在Windows下将minio注册为本地服务
通过winsw注册服务的方式,把minio注册成服务运行
- 下载 https://github.com/winsw/winsw/releases
- 将WinSW.NET461.exe更名为minio-server.exe
- 同目录下创建minio-server.xml。特别注意,xml和exe必须同名
- 配置minio-server.xml文件
- 使用minio-server.exe install安装服务
- 安装完后,去服务中启动服务。
minio-server.exe uninstall卸载服务
<service>
<id>minio-server</id>
<name>minio-server</name>
<description>minio文件存储服务器</description>
<!-- 可设置环境变量 -->
<env name="HOME" value="%BASE%"/>
<executable>%BASE%\minio.exe</executable>
<arguments>server "%BASE%\data"</arguments>
<!-- <logmode>rotate</logmode> -->
<logpath>%BASE%\logs</logpath>
<log mode="roll-by-size-time">
<sizeThreshold>10240</sizeThreshold>
<pattern>yyyyMMdd</pattern>
<autoRollAtTime>00:00:00</autoRollAtTime>
<zipOlderThanNumDays>5</zipOlderThanNumDays>
<zipDateFormat>yyyyMMdd</zipDateFormat>
</log>
</service>
访问地址:127.0.0.1:9000
accessKey: minioadmin
secretKey: minioadmin
SpringBoot 集成MinIO
jar包
<!-- 访问图片服务器 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.0.2</version>
</dependency>
@Getter
@Setter
@NoArgsConstructor
@ConfigurationProperties(prefix ="minio")
public class MinioConfig {
@ApiModelProperty("endPoint是一个URL,域名,IPv4或者IPv6地址")
private String endpoint;
@ApiModelProperty("TCP/IP端口号")
private int port;
@ApiModelProperty("accessKey类似于用户ID,用于唯一标识你的账户")
private String accessKey;
@ApiModelProperty("secretKey是你账户的密码")
private String secretKey;
@ApiModelProperty("如果是true,则用的是https而不是http,默认值是true")
private Boolean secure;
@ApiModelProperty("默认存储桶")
private String bucketName;
@Bean
public MinioClient getMinioClient() throws InvalidPortException, InvalidEndpointException {
//MinioClient.endpoint(endpoint,port,secure).credentials(accessKey,secretKey).build()
MinioClient minioClient = new MinioClient(endpoint,port,accessKey,secretKey,secure) ;
return minioClient;
}
@Configuration
public class MinioUtil {
@Autowired
MinioClient minioClient;
private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
public MinioUtil() {
}
private static class MinioUtilHoler {
private static MinioUtil INSTANCE = new MinioUtil();
}
public static MinioUtil getInstance() {
return MinioUtilHoler.INSTANCE;
}
/**
* 检查桶是否存在
*/
@SneakyThrows
public boolean bucketExists(String bucketName) {
return minioClient.bucketExists(bucketName);
}
/**
* 创建储存桶
*/
@SneakyThrows
public boolean makeBucket(String bucketName) {
if (!bucketExists(bucketName)) {
minioClient.makeBucket(bucketName);
//设置桶的权限
StringBuilder builder = new StringBuilder();
builder.append("{\n");
builder.append(" \"Statement\": [\n");
builder.append(" {\n");
builder.append(" \"Action\": [\n");
builder.append(" \"s3:GetBucketLocation\",\n");
builder.append(" \"s3:ListBucket\"\n");
builder.append(" ],\n");
builder.append(" \"Effect\": \"Allow\",\n");
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::"+bucketName+"\"\n");
builder.append(" },\n");
builder.append(" {\n");
builder.append(" \"Action\": \"s3:GetObject\",\n");
builder.append(" \"Effect\": \"Allow\",\n");
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::"+bucketName+"/*\"\n");
builder.append(" }\n");
builder.append(" ],\n");
builder.append(" \"Version\": \"2012-10-17\"\n");
builder.append("}\n");
minioClient.setBucketPolicy(bucketName,builder.toString());
return true;
}
return false;
}
/**
* 查询所有桶名称
*/
@SneakyThrows
public List<String> listBucketNames() {
List<Bucket> bucketList = listBuckets();
List<String> bucketNameList = bucketList.stream().map(Bucket::name).collect(Collectors.toList());
return bucketNameList;
}
/**
* 查询所有储存桶
*/
@SneakyThrows
public List<Bucket> listBuckets() {
return minioClient.listBuckets();
}
/**
* 删除储存桶
*/
@SneakyThrows
public boolean removeBucket(String bucketName) {
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<Item>> listObjects = listObjects(bucketName);
for (Result<Item> result : listObjects) {
Item item = result.get();
if (item.size() > 0) {
return false;
}
}
//删除储存桶 只有储存桶为空时才能删除成功
minioClient.removeBucket(bucketName);
flag = bucketExists(bucketName);
return !flag;
}
return false;
}
/**
* 查询储存桶里的所有对象名称
*/
@SneakyThrows
public List<String> listObjectNames(String bucketName) {
boolean flag = bucketExists(bucketName);
List<String> listObjectNames = new ArrayList<>();
if (flag) {
Iterable<Result<Item>> listObjects = listObjects(bucketName);
for (Result<Item> result : listObjects) {
Item item = result.get();
listObjectNames.add(item.objectName());
}
}
return listObjectNames;
}
/**
* 查询储存桶中的所有对象
*/
@SneakyThrows
public Iterable<Result<Item>> listObjects(String bucketName) {
boolean flag = bucketExists(bucketName);
if (flag) {
return minioClient.listObjects(bucketName);
}
return null;
}
/**
* 通过文件上传到对象
*/
@SneakyThrows
public boolean uploadObject(String bucketName, String objectName, String fileName) {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.putObject(bucketName, objectName, fileName, null);
ObjectStat statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.length() > 0) {
return true;
}
}
return false;
}
/**
* 文件上传
*/
@SneakyThrows
public boolean putObject(String bucketName, MultipartFile multipartFile, String filename) {
boolean flag = bucketExists(bucketName);
if (flag) {
PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
putObjectOptions.setContentType(multipartFile.getContentType());
minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);
ObjectStat statObject = statObject(bucketName, filename);
if (statObject != null && statObject.length() > 0) {
return true;
}
}
return false;
}
/**
* 流上传
*/
@SneakyThrows
public boolean putObject(String bucketName, String objectName, InputStream stream) {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1));
ObjectStat statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.length() > 0) {
return true;
}
}
return false;
}
/**
* 流的方式获取文件
*/
@SneakyThrows
public InputStream getObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.length() > 0) {
InputStream stream = minioClient.getObject(bucketName, objectName);
return stream;
}
}
return null;
}
/**
* 流方式获取文件对象(断点下载)
*/
@SneakyThrows
public InputStream getObject(String bucketName, String objectName, long offset, Long length) {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.length() > 0) {
InputStream stream = minioClient.getObject(bucketName, objectName, offset, length);
return stream;
}
}
return null;
}
/**
* 下载并将文件保存到本地
*/
@SneakyThrows
public boolean getObject(String bucketName, String objectName, String fileName) {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.length() > 0) {
minioClient.getObject(bucketName, objectName, fileName);
return true;
}
}
return false;
}
/**
* 删除一个对象
*/
@SneakyThrows
public boolean removeObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.removeObject(bucketName, objectName);
//获取对象的元数据
ObjectStat statObject = statObject(bucketName, objectName);
//没有就是删除成功
if (statObject == null || statObject.length() == 0) {
return true;
}
}
return flag;
}
/**
* 删除指定桶的多个文件对象,返回错误的对象列表 全部删除成功 返回空列表
*/
@SneakyThrows
public List<String> removeObject(String bucketName, List<String> objectNames) {
List<String> deleteErrorNames = new ArrayList<>();
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
deleteErrorNames.add(error.objectName());
}
} else {
//没有桶数据 全部判断失败
deleteErrorNames.addAll(objectNames);
}
return deleteErrorNames;
}
/**
* 生成一个http get请求用的url
* 可以用这个url进行下载 即使所在的存储桶是私有的 失效时间默认七天 以秒为单位 最长七天
*/
@SneakyThrows
public String presignedGetObject(String bucketName,String objectName,Integer expires){
boolean flag = bucketExists(bucketName);
String url = "";
if(flag){
//没有设置过期时间就按默认的
if(expires==null){
minioClient.presignedGetObject(bucketName, objectName);
}else{
if(expires<1|| expires>DEFAULT_EXPIRY_TIME){
throw new BusinessException(ResMsg.EXPIRES_DATE_ERROR);
}
minioClient.presignedGetObject(bucketName, objectName, expires);
}
}
return url;
}
/**
* 生成一个http put请求用的url
* 浏览器可以用客户端可以用这个url进行上传 即使桶是私有的 失效时间默认七天 以秒为单位 最长七天
*/
@SneakyThrows
public String presignedPutObject(String bucketName,String objectName,Integer expires){
boolean flag = bucketExists(bucketName);
String url = "";
if(flag){
//没有设置过期时间就按默认的
if(expires==null){
minioClient.presignedPutObject(bucketName, objectName);
}else{
if(expires<1|| expires>DEFAULT_EXPIRY_TIME){
throw new BusinessException(ResMsg.EXPIRES_DATE_ERROR);
}
minioClient.presignedPutObject(bucketName, objectName, expires);
}
}
return url;
}
/**
* 文件访问路径
*/
@SneakyThrows
public String getObjectUrl(String bucketName,String objectName){
boolean flag = bucketExists(bucketName);
String url = "";
if(flag){
url = minioClient.getObjectUrl(bucketName, objectName);
}
return url;
}
/**
* 获取对象的元数据
*/
@SneakyThrows
public ObjectStat statObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = minioClient.statObject(bucketName, objectName);
return statObject;
}
return null;
}
}
创建多用户、多策略
- 使用wget命令安装mc命令
wget https://dl.min.io/client/mc/release/linux-amd64/mc -P /usr/local/bin/
- 给路径下的mc添加执行权限
chmod +x /usr/local/bin/mc
- 绑定Minio服务
mc config host add minio http://127.0.0.1:9000 minioadmin minioadmin --api S3v4
//测试是否绑定Minio服务
mc ls minio
- 查看配置信息
mc alias list
- 查看minio当前策略的权限
mc admin policy list minio
- 自定义策略权限
cd /usr/local/minio/custom_strategy
touch test.json
vi test.json
//test.json
{
"Version": "2012-10-17", // 版本
"Statement": [
{
"Effect": "Allow", // Allow或者deny,允许或者拒绝下面配置的访问权限
"Action": [ // 配置权限,上传,删除,下载等等的权限
"s3:GetBucketLocation", // 授予权限以返回 Amazon S3 存储桶所在的区域 文章底下会详解
"s3:GetBucketPolicy", // 授予权限以返回指定存储桶的策略 文章底下会详解
"s3:ListBucket", // 查看桶权限
"s3:GetObject", // 下载权限
"s3:PutObject", // 上传权限
"s3:DeleteObject" // 删除权限
],
"Resource": [ // 配置权限的作用范围
"arn:aws:s3:::test-zl/*","arn:aws:s3:::test-xx/*" // arn:aws:s3不用动,*表示权限作用于test-zl这个桶下的所有数据,加逗号可以写多个桶
]
}
]
}
- 给Minio增加自定义策略
mc admin policy add minio test /usr/local/minio/custom_strategy/test.json
//Minio增加策略后检查是否加入
mc admin policy list minio
- minio增加用户
mc admin user add minio admintest admintest
//minio查询用户
mc admin user list minio
- 给用户增加权限
mc admin policy set minio test user=admintest