MinIO使用基础教程

MinIO使用基础教程一款开源 强大的云存储工具 MinIO 使用教程 minio 使用教程

大家好,欢迎来到IT知识分享网。

一、背景

在这里插入图片描述

对于网站系统,若为降低成本投入,将文件存储服务和网站系统部署在同一台服务器中,访问量不大,基本不会有问题,但访问量逐渐升高,网站文件资源读取逐渐频繁,单机服务器可能难以承载较大的请求量,可能会出现网站打不开,甚至系统异常等问题。

解决方案:采用云存储服务,将访问很频繁的文件资源服务,由本地改成云厂商提供的文件存储服务,比如阿里云 OSS、七牛云、腾讯云、百度云等等,迁移之后,网站的访问压力会得到极大的释放,服务也会变得更加稳定。

但是,这些云存储服务大部分都是收费的,以阿里云为例,数据存储通常按照 0.12 元/GB/月的标准来收费,日积月累也是一笔巨款。

采用免费开源的 fastDFS 工具来作为文件存储服务器,虽然性能不错,但软件安装环境非常复杂,且没有完整的技术文档,大部分都是公司或者网友自己总结的文档,维护起来非常困难。

直到 MinIO应运而生,云存储服务工具便多一个新的可选项。

MinIO 是一款号称世界上速度最快的对象存储服务,专为大规模数据存储和分析而设计。支持在各种环境中部署,包括物理服务器、虚拟机、容器等,最关键的是它的技术文档非常完善,非常容易上手;同时,对个人用户是完全开源免费的。

二、快速安装

2.1 虚拟机安装

Centos7安装Minio笔记

docker启动minio命令:

docker run \ -p 9000:9000 \ -p 9001:9001 \ --name minio1 \ -v D:\minio\data:/data \ -e "MINIO_ROOT_USER=ROOTUSER" \ -e "MINIO_ROOT_PASSWORD=CHANGEME123" \ quay.io/minio/minio server /data --console-address ":9001" 

相关参数解读:

docker run:表示启动运行容器 -p:表示为容器绑定一个本地的端口 -name:表示为容器创建一个本地的名字 -v:表示将文件路径设置为容器使用的持久卷位置。当 MinIO 将数据写入 /data时,该数据会镜像到本地路径~/minio/data, 使其能够在容器重新启动时保持持久化。您可以设置任何具有读取、写入和删除权限的文件路径来使用。 -e:表示设置登陆控制台的用户名和密码。其中控制台的访问地址为http://本机ip:9001,api 的访问地址为http://本机ip:9000

2.2 Windows安装

2.2.1 下载MinIO服务器

下载地址:

https://dl.minio.org.cn/server/minio/release/windows-amd64/minio.exe 

ps:不能双击文件来运行,下一步包括运行可执行文件的指令。

2.2.2 启动 MinIO Server

在PowerShell或命令提示符中,cd命令进到可执行文件的位置,或添加minio.exe文件所在路径 至windows系统环境变量 $PATH 中。

.\minio.exe server D:\tool\minio --console-address :9090 

控制台窗口会输出打印内容:

API: http://192.0.2.10:9000  http://127.0.0.1:9000
RootUser: minioadmin
RootPass: minioadmin

Console: http://192.0.2.10:9090 http://127.0.0.1:9090
RootUser: minioadmin
RootPass: minioadmin

Command-line: https://minio.org.cn/docs/minio/linux/reference/minio-mc.html
   $ mc alias set myminio http://192.0.2.10:9000 minioadmin minioadmin

Documentation: https://minio.org.cn/docs/minio/linux/index.html

WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables. 

该服务与当前PowerShell 或命令提示符窗口相绑定。 关闭窗口将停止服务器并结束该服务

2.2.3 通过浏览器访问MinIO服务控制台

访问 MinIO控制台:

http://127.0.0.1:9090 

MinIO使用监听的端口为 9000 端口,这个端口使用API与MinIO服务器进行通信和进行SDK调用,通过浏览器访问 9000 端口会自动跳转至MinIO控制台。

登录MinIO 控制台可以使用默认的 Root用户名/密码 登录: minioadmin / minioadmin 。
就可以显示相关控制台的详细信息。
在这里插入图片描述

三、使用介绍

在对象存储服务里面,所有的文件都是以桶的形式来组织的。简单说,可以将桶看作是目录,这个目录下有很多的文件或者文件夹,这和其它云存储服务基本一致。

3.1 创建存储桶

所有的文件必须要存储到桶中,因此需要先创建存储桶。
在这里插入图片描述
若要修改存储桶信息,点击左侧的Buckets菜单,即可展示存储桶配置信息。

3.2 上传和下载文件

点击Object Browser菜单,可看到刚刚创建的存储桶public-bucket,点击进入,上传想要存储的文件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
若想下载文件或者预览文件,点击文件,右侧会弹出相关的操作按钮,点击相应的操作按钮即可。

3.3 设置文件公开访问

默认创建的存储桶,均为私有桶,无法被公开访问。
在这里插入图片描述
以 api 方式直接访问,会提示无权限:

127.0.0.1:9000/public-bucket/sso流程图.png 

在这里插入图片描述
通常而言,要将数据写入操作进行控制;而读操作,很多不涉及安全问题,希望能被互联网公开访问,以便加快文件的访问速度。

可以在存储桶里面配置,将数据读取权限设置为公开访问:
在这里插入图片描述
再次访问:
在这里插入图片描述
此时文件可以公开访问。

四、实战SpringBoot + Minio实现文件上传和查询

引入依赖:

<!-- 操作minio的java客户端--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.5.2</version> </dependency> <!-- 操作minio的java客户端--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.2.1</version> </dependency> <!-- jwt鉴权相应依赖--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> </dependency> 

获取API访问凭证:
在这里插入图片描述
在这里插入图片描述
编写配置文件:

server: port: 8080 spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB #minio配置 minio: access-key: dAMaxkWaXUD1CV1JHbqw secret-key: AXt3SD0JFkDENFbMeJKOOQb5wj8KvabZWu33Rs84 url: http://192.168.18.14:9090 #访问地址 bucket-name: public-bucket 

创建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; @Data @Configuration @ConfigurationProperties(prefix = "spring.minio") public class MinioConfig { 
    private String accessKey; private String secretKey; private String url; private String bucketName; @Bean public MinioClient minioClient(){ 
    return MinioClient.builder() .endpoint(url) .credentials(accessKey,secretKey) .build(); } } 

创建Minio的工具类:

import com.xiaohui.config.MinioConfig; import io.minio.*; import io.minio.errors.*; import io.minio.http.Method; import lombok.SneakyThrows; import org.apache.tomcat.util.http.fileupload.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; / * @Description Minio工具类 */ @Component public class MinioUtils { 
    @Autowired private MinioClient minioClient; @Autowired private MinioConfig configuration; / * @param name 名字 * @Description 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) { 
    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) { 
    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) { 
    PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), 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", configuration.getUrl() + "/" + configuration.getBucketName()); return map1; } catch (ErrorResponseException e) { 
    e.printStackTrace(); } catch (InsufficientDataException e) { 
    e.printStackTrace(); } catch (InternalException e) { 
    e.printStackTrace(); } catch (InvalidKeyException e) { 
    e.printStackTrace(); } catch (InvalidResponseException e) { 
    e.printStackTrace(); } catch (IOException e) { 
    e.printStackTrace(); } catch (NoSuchAlgorithmException e) { 
    e.printStackTrace(); } catch (ServerException e) { 
    e.printStackTrace(); } catch (XmlParserException e) { 
    e.printStackTrace(); } return null; } / * @param objectName 对象名称 * @param method 方法 * @param time 时间 * @param timeUnit 时间单位 * @Description 获取上传文件的url */ public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) { 
    try { 
    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(method) .bucket(configuration.getBucketName()) .object(objectName) .expiry(time, timeUnit).build()); } catch (ErrorResponseException e) { 
    e.printStackTrace(); } catch (InsufficientDataException e) { 
    e.printStackTrace(); } catch (InternalException e) { 
    e.printStackTrace(); } catch (InvalidKeyException e) { 
    e.printStackTrace(); } catch (InvalidResponseException e) { 
    e.printStackTrace(); } catch (IOException e) { 
    e.printStackTrace(); } catch (NoSuchAlgorithmException e) { 
    e.printStackTrace(); } catch (XmlParserException e) { 
    e.printStackTrace(); } catch (ServerException e) { 
    e.printStackTrace(); } return null; } / * @param file 文件 * @param fileName 文件名称 * @Description 上传文件 */ public void upload(MultipartFile file, String fileName) { 
    // 使用putObject上传一个文件到存储桶中。 try { 
    InputStream inputStream = file.getInputStream(); minioClient.putObject(PutObjectArgs.builder() .bucket(configuration.getBucketName()) .object(fileName) .stream(inputStream, file.getSize(), -1) .contentType(file.getContentType()) .build()); } catch (ErrorResponseException e) { 
    e.printStackTrace(); } catch (InsufficientDataException e) { 
    e.printStackTrace(); } catch (InternalException e) { 
    e.printStackTrace(); } catch (InvalidKeyException e) { 
    e.printStackTrace(); } catch (InvalidResponseException e) { 
    e.printStackTrace(); } catch (IOException e) { 
    e.printStackTrace(); } catch (NoSuchAlgorithmException e) { 
    e.printStackTrace(); } catch (ServerException e) { 
    e.printStackTrace(); } catch (XmlParserException e) { 
    e.printStackTrace(); } } / * @param objectName 对象名称 * @param time 时间 * @param timeUnit 时间单位 * @Description 根据filename获取文件访问地址 */ public String getUrl(String objectName, int time, TimeUnit timeUnit) { 
    String url = null; try { 
    url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(configuration.getBucketName()) .object(objectName) .expiry(time, timeUnit).build()); } catch (ErrorResponseException e) { 
    e.printStackTrace(); } catch (InsufficientDataException e) { 
    e.printStackTrace(); } catch (InternalException e) { 
    e.printStackTrace(); } catch (InvalidKeyException e) { 
    e.printStackTrace(); } catch (InvalidResponseException e) { 
    e.printStackTrace(); } catch (IOException e) { 
    e.printStackTrace(); } catch (NoSuchAlgorithmException e) { 
    e.printStackTrace(); } catch (XmlParserException e) { 
    e.printStackTrace(); } catch (ServerException e) { 
    e.printStackTrace(); } return url; } / * @Description description: 下载文件 */ public ResponseEntity<byte[]> download(String fileName) { 
    ResponseEntity<byte[]> responseEntity = null; InputStream in = null; ByteArrayOutputStream out = null; try { 
    in = minioClient.getObject(GetObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).build()); out = new ByteArrayOutputStream(); IOUtils.copy(in, out); //封装返回值 byte[] bytes = out.toByteArray(); HttpHeaders headers = new HttpHeaders(); try { 
    headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); } catch (UnsupportedEncodingException e) { 
    e.printStackTrace(); } headers.setContentLength(bytes.length); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setAccessControlExposeHeaders(Arrays.asList("*")); responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.SUCCESS); } catch (Exception e) { 
    e.printStackTrace(); } finally { 
    try { 
    if (in != null) { 
    try { 
    in.close(); } catch (IOException e) { 
    e.printStackTrace(); } } if (out != null) { 
    out.close(); } } catch (IOException e) { 
    e.printStackTrace(); } } return responseEntity; } / * @param objectFile 对象文件 */ public String getFileUrl(String objectFile) { 
    try { 
    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(configuration.getBucketName()) .object(objectFile) .build() ); } catch (Exception e) { 
    e.printStackTrace(); } return null; } } 
/ * @Description http请求状态 */ public class HttpStatus { 
    / * 操作成功 */ public static final int SUCCESS = 200; / * 对象创建成功 */ public static final int CREATED = 201; / * 请求已经被接受 */ public static final int ACCEPTED = 202; / * 操作已经执行成功,但是没有返回数据 */ public static final int NO_CONTENT = 204; / * 资源已被移除 */ public static final int MOVED_PERM = 301; / * 重定向 */ public static final int SEE_OTHER = 303; / * 资源没有被修改 */ public static final int NOT_MODIFIED = 304; / * 参数列表错误(缺少,格式不匹配) */ public static final int BAD_REQUEST = 400; / * 未授权 */ public static final int UNAUTHORIZED = 401; / * 访问受限,授权过期 */ public static final int FORBIDDEN = 403; / * 资源,服务未找到 */ public static final int NOT_FOUND = 404; / * 不允许的http方法 */ public static final int BAD_METHOD = 405; / * 资源冲突,或者资源被锁 */ public static final int CONFLICT = 409; / * 不支持的数据,媒体类型 */ public static final int UNSUPPORTED_TYPE = 415; / * 系统内部错误 */ public static final int ERROR = 500; / * 接口未实现 */ public static final int NOT_IMPLEMENTED = 501; / * 系统警告消息 */ public static final int WARN = 601; } 

通用常量信息:

import io.jsonwebtoken.Claims; / * @Description 通用常量信息 */ public class Constants { 
    / * UTF-8 字符集 */ public static final String UTF8 = "UTF-8"; / * GBK 字符集 */ public static final String GBK = "GBK"; / * www主域 */ public static final String WWW = "www."; / * http请求 */ public static final String HTTP = "http://"; / * https请求 */ public static final String HTTPS = "https://"; / * 通用成功标识 */ public static final String SUCCESS = "0"; / * 通用失败标识 */ public static final String FAIL = "1"; / * 登录成功 */ public static final String LOGIN_SUCCESS = "Success"; / * 注销 */ public static final String LOGOUT = "Logout"; / * 注册 */ public static final String REGISTER = "Register"; / * 登录失败 */ public static final String LOGIN_FAIL = "Error"; / * 验证码有效期(分钟) */ public static final Integer CAPTCHA_EXPIRATION = 2; / * 令牌 */ public static final String TOKEN = "token"; / * 令牌前缀 */ public static final String TOKEN_PREFIX = "Bearer "; / * 令牌前缀 */ public static final String LOGIN_USER_KEY = "login_user_key"; / * 用户ID */ public static final String JWT_USERID = "userid"; / * 用户名称 */ public static final String JWT_USERNAME = Claims.SUBJECT; / * 用户头像 */ public static final String JWT_AVATAR = "avatar"; / * 创建时间 */ public static final String JWT_CREATED = "created"; / * 用户权限 */ public static final String JWT_AUTHORITIES = "authorities"; / * 资源映射路径 前缀 */ public static final String RESOURCE_PREFIX = "/profile"; / * RMI 远程方法调用 */ public static final String LOOKUP_RMI = "rmi:"; / * LDAP 远程方法调用 */ public static final String LOOKUP_LDAP = "ldap:"; / * LDAPS 远程方法调用 */ public static final String LOOKUP_LDAPS = "ldaps:"; / * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) */ public static final String[] JOB_WHITELIST_STR = { 
    "com.ruoyi" }; / * 定时任务违规的字符 */ public static final String[] JOB_ERROR_STR = { 
    "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" }; } 

创建Ajax请求工具类:

/ * @Description ajax结果 */ public class AjaxResult extends HashMap<String, Object> { 
    private static final long serialVersionUID = 1L; / 状态码 */ public static final String CODE_TAG = "code"; / 返回内容 */ public static final String MSG_TAG = "msg"; / 数据对象 */ public static final String DATA_TAG = "data"; / * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 */ public AjaxResult() { 
    } / * 初始化一个新创建的 AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 */ public AjaxResult(int code, String msg) { 
    super.put(CODE_TAG, code); super.put(MSG_TAG, msg); } / * 初始化一个新创建的 AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 * @param data 数据对象 */ public AjaxResult(int code, String msg, Object data) { 
    super.put(CODE_TAG, code); super.put(MSG_TAG, msg); if (data!=null) { 
    super.put(DATA_TAG, data); } } / * 返回成功消息 * * @return 成功消息 */ public static AjaxResult success() { 
    return AjaxResult.success("操作成功"); } / * 返回成功数据 * * @return 成功消息 */ public static AjaxResult success(Object data) { 
    return AjaxResult.success("操作成功", data); } / * 返回成功消息 * * @param msg 返回内容 * @return 成功消息 */ public static AjaxResult success(String msg) { 
    return AjaxResult.success(msg, null); } / * 返回成功消息 * * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 */ public static AjaxResult success(String msg, Object data) { 
    return new AjaxResult(HttpStatus.SUCCESS, msg, data); } / * 返回警告消息 * * @param msg 返回内容 * @return 警告消息 */ public static AjaxResult warn(String msg) { 
    return AjaxResult.warn(msg, null); } / * 返回警告消息 * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ public static AjaxResult warn(String msg, Object data) { 
    return new AjaxResult(HttpStatus.WARN, msg, data); } / * 返回错误消息 * * @return 错误消息 */ public static AjaxResult error() { 
    return AjaxResult.error("操作失败"); } / * 返回错误消息 * * @param msg 返回内容 * @return 错误消息 */ public static AjaxResult error(String msg) { 
    return AjaxResult.error(msg, null); } / * 返回错误消息 * * @param msg 返回内容 * @param data 数据对象 * @return 错误消息 */ public static AjaxResult error(String msg, Object data) { 
    return new AjaxResult(HttpStatus.ERROR, msg, data); } / * 返回错误消息 * * @param code 状态码 * @param msg 返回内容 * @return 错误消息 */ public static AjaxResult error(int code, String msg) { 
    return new AjaxResult(code, msg, null); } / * 方便链式调用 * * @param key 键 * @param value 值 * @return 数据对象 */ @Override public AjaxResult put(String key, Object value) { 
    super.put(key, value); return this; } } 

创建Minio文件操作接口层:

import com.xiaohui.utils.AjaxResult; import com.xiaohui.utils.MinioUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.HashMap; / * @Description minio文件上传控制器 */ @CrossOrigin @RestController @RequestMapping("/api") public class MinioFileUploadController { 
    @Autowired private MinioUtils minioUtils; / * @param file 文件 * @param fileName 文件名称 * @Description 上传文件 */ @GetMapping("/upload") public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, String fileName) { 
    minioUtils.upload(file, fileName); return AjaxResult.success("上传成功"); } / * @param fileName 文件名称 * @Description dowload文件 */ @GetMapping("/dowload") public ResponseEntity dowloadFile(@RequestParam("fileName") String fileName) { 
    return minioUtils.download(fileName); } / * @param fileName 文件名称 * @Description 得到文件url */ @GetMapping("/getUrl") public AjaxResult getFileUrl(@RequestParam("fileName") String fileName){ 
    HashMap map=new HashMap(); map.put("FileUrl",minioUtils.getFileUrl(fileName)); return AjaxResult.success(map); } } 

五、测试

六、小结

minio 用来做个人云存储工具完全是开源免费的,若当前需要一个云存储工具,首推minio。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/142149.html

(0)
上一篇 2025-05-12 15:10
下一篇 2025-05-12 15:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信