minIO安装教程及代码使用
如果您看着CSDN格式觉得不舒服,可以移步我的语雀该篇文章:
《minIO》https://www.yuque.com/docs/share/d9cd6a86-da8a-41b3-af56-6f357fad96cb?#%20%E3%80%8AminIO%E3%80%8B
目录
1、安装
1.1、Linux安装
1.2、Docker安装
1.3、Docker纠删码模式安装
1.4、分布式集群安装
2、代码实现
3、使用MinIO
1、安装
- MinIO英文官网地址:MinIO High Performance Object Storage — MinIO Object Storage for Kubernetes
- MinIO中文官网地址:MinIO Quickstart Guide| Minio中文文档
安装请按照英文官网,中文官网更新不及时。或者看我也可以!
1.1、Linux安装
1、先新建个你喜欢的目录,例如:mkdir -p /usr/local/minio
2、执行:wget https://dl.min.io/server/minio/release/darwin-amd64/minio
3、给文件夹赋权:chmod +x minio
PS:正常的目录应该是白色,赋权后应该是绿色,反正不是白色就对了
4、可以运行了:./minio /xxxxxxxxx/data
PS:启动minio server服务,指定数据存储目录/xxxxxxxxx/data
5、启动成功后,会出现红色Warning,不要慌
它的大概意思是告诉你:
一、这种方式启动,端口是随机的,下次再启动minIO端口就不一定是啥了
二、建议你用别的用户名,密码
解决:
一、添加用户名密码到环境变量:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
PS:长度要在8位以上,至于为啥,往后看
二、指定端口号启动:
./minio server --console-address ":50000" /xxxxxxxxx/data
PS:相较于第四步多了--console-address
指定端口号启动
6、访问:http://xxxxx:50000/dashboard
1.2、Docker安装
1、新建挂载数据卷目录,例如:/mydata/minio/data
和/mydata/minio/config
2、拉取镜像:docker pull minio/minio
3、运行镜像
docker run -d -p 9000:9000 -p 50000:50000 --name minio \-v /mydata/minio/data:/data \-v /mydata/minio/config:/root/.minio \-e "MINIO_ROOT_USER=admin" \-e "MINIO_ROOT_PASSWORD=123456789" \minio/minio server --console-address ":50000" /data
解释为什么密码长度要最短8位,这里分享下我遇见的故障:
第一次运行的时候,也是使用-d
后台运行,镜像启动之后,执行docker ps -a
命令,看不到minio的运行端口号,执行docker ps
命令查看镜像启动失败。
所以我使用控制台输出信息方式运行镜像(就是去掉-d
命令)
它是告诉我,密码最少是8位。。。。
总结!!!以小窥大,告诉我们要养成看日志的习惯
4、访问:IP+端口号
1.3、Docker纠删码模式安装
docker run -d -p 9000:9000 -p 50000:50000 --name minio \
-v /mydata/minio/data1:/data1 \
-v /mydata/minio/data2:/data2 \
-v /mydata/minio/data3:/data3 \
-v /mydata/minio/data:/data4 \
-v /mydata/minio/data5:/data5 \
-v /mydata/minio/data:/data6 \
-v /mydata/minio/data7:/data7 \
-v /mydata/minio/data8:/data8 \
minio/minio server /data{1...8} --console-address ":50000"
1.4、分布式集群安装
自行百度吧,我买的腾讯云现成的。。。
2、代码实现
建议您呢,新建一个Spring Boot工程,复制下面我的代码,代码很简单,吸收了之后,再运用到你的项目
config:
package com.greedy.minio.config;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;/*** @Author: Greedy* @Date: Created in:2022-09-15* Description:*/
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {/*** 对象存储服务的 URL*/private String endpoint;/*** 用户名*/private String accessKey;/*** 密码*/private String secretKey;/*** 存储桶名称*/private String bucketName;/*** 预览到期时间(小时)*/private Integer previewExpiry;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}
}
controller:
package com.greedy.minio.controller;import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.service.MinioService;
import com.greedy.minio.utils.Msg;
import com.greedy.minio.vo.FileVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;
import java.util.List;/*** @Author: Greedy* @Date: Created in:2022-09-15* Description:*/
@RestController
@Slf4j
public class MinioController {private final MinioService minioService;public MinioController(MinioService minioService) {this.minioService = minioService;}/*** 上传文件** @param body* @return*/@PostMapping("/upload")public Msg upload(FileUploadBody body) {List<FileVo> list = null;if (ObjUtil.isNull(body.getFiles())) {return Msg.ERROR.setNewMsg("上传文件不能为空");}try {list = minioService.uploadFile(body);log.info("文件上传成功,文件名称:{},bucket名称:{}", body.getFileName(), body.getBucket());} catch (Exception e) {log.error("文件上传失败,文件名称:{},bucket名称:{},错误信息:", body.getFileName(), body.getBucket(), e);return Msg.UPLOAD_ERROR;}return Msg.UPLOAD_SUCCESS.setNewData(list);}/*** 获取预览地址** @param fileName 文件名* @param bucketName 桶名* @return*/@GetMapping("/getPreviewUrl")public Msg getPreviewUrl(@RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {String url = minioService.getPreviewUrl(fileName, bucketName);String previewUrl = null;try {if (url == null || StrUtil.isBlank(url)) {return Msg.SUCCESS.setNewMsg("不好意思,没查着该文件");}// 前端返回格式:ip:端口/桶名/文件名previewUrl = url.substring(0, url.indexOf("?"));} catch (Exception e) {log.error("预览文件地址错误,文件名为:{},bucket名为:{},错误信息为:", fileName, bucketName, e);}log.info("文件查找成功,文件预览地址为:{},文件名:{},bucket:{}", previewUrl, fileName, bucketName);return Msg.SUCCESS.setNewData(previewUrl);}/*** 下载文件** @param response* @param fileName 文件名* @param bucketName 桶名* @return*/@PostMapping("/download")public Msg download(HttpServletResponse response, @RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {try {minioService.downloadFile(response, fileName, bucketName);log.info("文件下载成功,文件名称:{},bucket名为:{}", fileName, bucketName);return Msg.DOWNLOAD_SUCCESS;} catch (Exception e) {log.error("文件下载失败,文件名称:{},错误信息:", fileName, e);return Msg.DOWNLOAD_ERROR;}}/*** 删除文件** @param fileName 文件名* @param bucketName 桶名* @return*/@DeleteMapping("/delFile")public Msg delFile(@RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {try {minioService.delFile(fileName, bucketName);log.info("文件删除成功,文件名称为:{},bucket为:{}", fileName, bucketName);return Msg.DELETE_SUCCESS.setNewData("删除文件:" + fileName + "成功!");} catch (Exception e) {log.error("删除文件失败,文件名称为:{},bucket为:{},错误信息:", bucketName, fileName, e);return Msg.DELETE_ERROR.setNewData("删除文件:" + fileName + "失败!");}}
}
pojo:
package com.greedy.minio.pojo;import lombok.Data;
import org.springframework.web.multipart.MultipartFile;import java.io.Serializable;/*** @Author: Greedy* @Date: Created in:2022-09-15* Description: 文件上传入参实体类*/
@Data
public class FileUploadBody implements Serializable {/*** 自定义文件名*/private String fileName;/*** 多文件*/private MultipartFile[] files;/*** 所属模块*/private String bucket;}
serviceImpl:
package com.greedy.minio.service.impl;import cn.hutool.core.util.StrUtil;
import com.greedy.minio.config.MinioConfig;
import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.service.MinioService;
import com.greedy.minio.vo.FileVo;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;/*** @Author: Greedy* @Date: Created in:2022-09-15* Description:*/
@Service
@Slf4j
public class MinioServiceImpl implements MinioService {@Autowiredprivate MinioConfig minioConfig;@Autowiredprivate MinioClient minioClient;/*** 上传文件* @param body* @return*/@Overridepublic List<FileVo> uploadFile(FileUploadBody body) {MultipartFile[] files=body.getFiles();if (Objects.nonNull(files) && files.length > 0) {String bucketName = StrUtil.isNotBlank(body.getBucket()) ? body.getBucket().replaceAll(",", "") : minioConfig.getBucketName();List<FileVo> resultList = new ArrayList<>();String fileName = null;for (MultipartFile file : files) {try {if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}fileName = file.getOriginalFilename();if (StrUtil.isNotBlank(body.getFileName())){fileName = body.getFileName();}StringBuffer fileNameSB = new StringBuffer();fileNameSB.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");if (StrUtil.isNotBlank(fileName)){fileNameSB.append(fileName.replaceAll(",", ""));}fileName = fileNameSB.toString();PutObjectArgs args = PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();minioClient.putObject(args);FileVo fileVo=new FileVo();fileVo.setFileName(fileName);fileVo.setBucket(bucketName);fileVo.setPreviewUrl(getPreviewUrl(fileName,bucketName));resultList.add(fileVo);log.info("文件上传成功,文件名称:{},bucket名称:{}", fileName, bucketName);}catch (Exception e){log.error("文件上传失败,文件名称:{},bucket名称:{},错误信息:", fileName, bucketName, e);}}return resultList;}return Collections.emptyList();}/*** 获取预览地址* @param fileName* @param bucketName* @return*/@Overridepublic String getPreviewUrl(String fileName, String bucketName) {if (StrUtil.isNotBlank(fileName)) {bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());if (null != minioConfig.getPreviewExpiry()){String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).expiry(minioConfig.getPreviewExpiry(), TimeUnit.HOURS).build());log.info("有时限文件预览地址为:{},文件名:{},bucket名:{},有效时间为:{}", presignedObjectUrl, fileName, bucketName, minioConfig.getPreviewExpiry());return presignedObjectUrl;}else {String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build());log.info("文件预览地址为:{},文件名:{},bucket名:{},有效时间为:永久", presignedObjectUrl, fileName, bucketName);return presignedObjectUrl;}} catch (Exception e) {log.error("预览文件地址错误,文件名为:{},bucket名为:{},错误信息为:", fileName, bucketName, e);}}return null;}/*** 下载文件* @param response* @param fileName* @param bucketName*/@Overridepublic void downloadFile(HttpServletResponse response, String fileName, String bucketName) {InputStream inputStream = null;if (StrUtil.isNotBlank(fileName)) {bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();try {StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));response.setContentType(objectStat.contentType());response.setCharacterEncoding("UTF-8");inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());IOUtils.copy(inputStream, response.getOutputStream());log.info("文件下载成功,文件名称:{},bucket名为:{}", fileName, bucketName);} catch (Exception e) {log.error("文件下载失败,文件名称:{},错误信息:", fileName, e);} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {log.error("输入流关闭失败,文件名:{},错误信息:", fileName, e);}}}}}/*** 删除文件* @param fileName* @param bucketName* @return*/@Overridepublic String delFile(String fileName, String bucketName) {if (StrUtil.isNotBlank(fileName)) {bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());log.info("文件删除成功,文件名称为:{},bucket为:{}", fileName, bucketName);return "success";}catch (Exception e) {log.error("删除文件失败,文件名称为:{},bucket为:{},错误信息:", bucketName, fileName, e);return "删除文件失败,请刷新后重试";}}return "文件不能为空";}
}
service:
package com.greedy.minio.service;import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.vo.FileVo;import javax.servlet.http.HttpServletResponse;
import java.util.List;/*** @Author: Greedy* @Date: Created in:2022/09/15* Description:*/
public interface MinioService {/*** 上传文件* @param body* @return*/List<FileVo> uploadFile(FileUploadBody body);/*** 获取预览地址* @param fileName* @param bucketName* @return*/String getPreviewUrl(String fileName, String bucketName);/*** 下载文件* @param response* @param fileName* @param bucketName*/void downloadFile(HttpServletResponse response, String fileName, String bucketName);/*** 删除文件* @param fileName* @param bucketName* @return*/String delFile(String fileName, String bucketName);
}
utils:这个统一结果返回实体类,在代码里换成你寄几的就行( •̀ ω •́ )✧
package com.greedy.minio.utils;import lombok.Data;/*** 统一返回结果集实体类* @param <T> 返回数据对象*/
@Data
public class Msg<T> {/*** 错误码*/private Integer Code;/*** 错误信息,一般为前端提示信息*/private String Msg;/*** 返回值,一般为成功后返回的数据*/private T data;/*** 错误详情,一般为失败后的详细原因,如空指针之类的*/private String Detail;public Msg() {}public Msg(Integer Code, String Msg) {this.Code = Code;this.Msg = Msg;}public Msg(Integer Code, String Msg, T data) {this.Code = Code;this.Msg = Msg;this.data = data;}/*** 配合静态对象直接设置 data 参数* @param data* @return*/public Msg setNewData(T data) {Msg error = new Msg();error.setCode(this.Code);error.setMsg(this.Msg);error.setDetail(this.Detail);error.setData(data);return error;}/*** 配合静态对象直接设置 errorMsg 参数* @param* @return*/public Msg setNewMsg(String Msg) {Msg error = new Msg();error.setCode(this.Code);error.setMsg(Msg);error.setDetail(this.Detail);error.setData(this.data);return error;}public static final Msg SUCCESS = new Msg(200, "成功");public static final Msg ERROR = new Msg(405, "失败");public static final Msg INSERT_SUCCESS = new Msg(200, "新增成功");public static final Msg UPDATE_SUCCESS = new Msg(200, "更新成功");public static final Msg DELETE_SUCCESS = new Msg(200, "删除成功");public static final Msg UPLOAD_SUCCESS = new Msg(200, "上传成功");public static final Msg DOWNLOAD_SUCCESS = new Msg(200, "下载成功");public static final Msg LOGIN_SUCCESS = new Msg(200, "登陆成功");public static final Msg LOGOUT_SUCCESS = new Msg(200, "登出成功");public static final Msg LOGIN_ERROR = new Msg(201, "登陆错误");public static final Msg LOGIN_EXPIRE = new Msg(202, "登陆过期");public static final Msg ACCESS_LIMITED = new Msg(301, "访问受限");public static final Msg ARGS_ERROR = new Msg(501, "参数错误");public static final Msg UNKOWN_ERROR = new Msg(502, "系统异常");public static final Msg INSERT_ERROR = new Msg(503, "新增错误");public static final Msg UPDATE_ERROR = new Msg(504, "更新错误");public static final Msg DELETE_ERROR = new Msg(506, "删除错误");public static final Msg UPLOAD_ERROR = new Msg(507, "上传错误");public static final Msg DOWNLOAD_ERROR = new Msg(508, "下载错误");public static final Msg OTHER_SYSTEM_ERROR = new Msg(509, "调用系统异常");// return ErrorMsg.SUCCESS; 成功返回
// return ErrorMsg.SUCCESS.setNewData(list); 成功带参返回
// return ErrorMsg.LOGIN_ERROR.setNewErrorMsg("用户名或密码不正确"); 错误返回并设定自定义错误信息}
vo:
package com.greedy.minio.vo;import lombok.Data;import java.io.Serializable;/*** @Author: Greedy* @Date: Created in:2022-09-15* Description: 展示给前端的具体信息*/
@Data
public class FileVo implements Serializable {/*** 文件名称*/private String fileName;/*** 预览地址*/private String previewUrl;/*** 所属模块*/private String bucket;
}
MinioApp:主启动类省略。。。
application.yaml:
pom:
<dependencies><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>去mvn中央仓库自己找</version></dependency><!-- 工具类依赖 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.6</version></dependency><!-- 可以自行扩展,例如显示进度条等依赖 -->
</dependencies>
3、使用MinIO
代码Controller里面几个方法注释写的都很详细了,就不用说了吧。。。
如果您坚持到了这里了都,不给个赞可说不过去熬
minIO安装教程及代码使用相关推荐
- 联盛德W806入门教程-CDK安装教程及代码下烧录
笔者使用的系统板如下图所示: 首先安装代码编译软件CDK: 硬件:⚫ W805/W806 开发板 ⚫ USB 转串口线 软件: Windows 端编译工具:CDK 安装包 链接:[https://pa ...
- minio安装教程 linux+windows
下载文件 这个网站毛病,下载资源不能直接点,要在路由后端拼接地址才能访问,否则no found . 点击下面的链接直接下载对应系统的minio,不过可能需要科学上网工具,否则 下载速度比较慢,如果下载 ...
- 独家 | 手把手教你用Python 3创建用于机器学习开发的Linux虚拟机(附安装教程代码)
原文标题:How to Create a Linux Virtual Machine For Machine Learning Development With Python 3 作者:Jason B ...
- 群晖NAS教程(十六)、利用Docker安装GitLab管理代码工具
为了更好的浏览体验,欢迎光顾勤奋的凯尔森同学个人博客 群晖NAS教程(十六).利用Docker安装GitLab管理代码工具 群晖DSM上安装GitLab有两种方式,一种是直接在群晖套件上安装,另一种是 ...
- Source Insight 3.5 Source Insight4.0 看代码神器 免费版 百度网盘下载,附详细安装教程。
链接:https://pan.baidu.com/s/1IIALTQHovV9Zp0xetRfYYQ 密码:0mtk 一.Source Insight 3.5 安装教程: 1.下载文件中附有 Sour ...
- vs安装一直在提取文件_Visual Studio 2019下载及安装教程
宸1分钟前 这可是我珍藏多年的资源啊. Visual Studio 2019 Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品.是目前最流行的Windows ...
- 这套完美的Java环境安装教程,完整,详细,清晰可观,让你一目了然,简单易懂。⊙﹏⊙...
JDK下载与安装教程 2017年06月18日 22:53:16 Danishlyy1995 阅读数:349980 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csd ...
- TensorFlow2.0 系列开篇: Windows下GPU版本详细安装教程
点击上方"Datawhale",选择"星标"公众号 第一时间获取价值内容 [导读]今年三月谷歌在TensorFlow开发者峰会上宣布TensorFlow 2.0 ...
- Centos7上安装oracle11g/12c的安装教程推荐及注意事项
Centos7上安装oracle11g的安装教程推荐及注意事项 历时一天半,终于在今天中午安装完oracle11g,成功后喜悦的心情自是溢于言表.总有些疑问,比如为何如此复杂的数据库为何还会有如此之多 ...
- Python2安装教程(以最终版本Python2.7.18为例)
写在这里的初衷,一是备忘,二是希望得到高人指点,三是希望能遇到志同道合的朋友. 之前一直用的python3.6.5进行学习,最新试运行一些代码进行学习,发现是基于python2的环境下,就想着尝试着安 ...
最新文章
- 设计模式实例(Lua)笔记之五(Bridge模式)
- mac环境下myeclipse上配置tomcat
- Eclipse启动时报错
- Hive的列分隔符和行分隔符
- object.prototype.call
- MySQL学习笔记_4_MySQL创建数据表(下)
- X86Windows 相关链接....持续更新中....
- java.util.NoSuchElementException: None.get的解决方法
- 简单的docker下载安装jenkins
- c语言输入m行m列的二维数组,编写一个函数,用于计算具有n行和m列的二维数组中指定列的平均值以及数组各行的和的最小值。...
- 英雄传奇-6.专用浏览器打不开.黑屏.白屏.插件丢失等怎么解决
- 小米无线网卡linux,NanoPi NEO安装小米随身WiFi
- 用图片替代cursor光标样式
- OBS+SRS+centos7搭建局域网直播推流服务器
- iOS动画——流光文字
- java gc 命令_Java 查看系统GC命令介绍
- 指南:清晰理解zkEVM、EVM 兼容性和Rollup
- 视频特征提取常用范式总结
- HTML哪个单位是角度,css 角度单位有哪些?
- 前端开发实习面试题(JavaScript篇)
热门文章
- synchdem matlab,数字高程模型(DEM)移动插值算法
- 小样本算法库LibFewShot
- win7(64位)+vs2010+orge1.8.1
- html古风颜色代码,数字报纸HTML版本
- vuex中subscribe的使用
- CSS / 清除浮动+切图+属性书写顺序+页面布局思路
- 2016网易春季校园招聘产品策划笔试
- 用html语言设计李白的一首诗,李白《赠汪伦》的教案设计
- mac os x excel 单元格换行
- 安装服务器系统后鼠标键盘没反应,安装Win7系统以后键盘鼠标不能用/失灵没反应的缘由以及解决方法...