简介:
minio 是一个基于apache license v2.0开源协议的对象存储服务,虽然轻量,却拥有着不错的性能。它兼容亚马逊s3云存储服务接口,非常适合于存储大容量非结构化的数据。
例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5t 不等。
最重要的是免费
说明:
docker如果想安装软件 , 必须先到docker镜像仓库下载镜像。
1、寻找minio镜像
2、下载minio镜像
# 下载镜像 docker pull minio/minio #查看镜像 docker images
命令 | 描述 |
---|---|
docker pull minio/minio | 下载最新版minio镜像 (其实此命令就等同于 : docker pull minio/minio:latest ) |
docker pull minio/minio:release.2023-11-20t22-40-07z.fips | 下载指定版本的minio镜像 (xxx指具体版本号) |
3、创建目录
一个用来存放配置,一个用来存储上传文件的目录
启动前需要先创建minio外部挂载的配置文件( /opt/minio/config),和存储上传文件的目录( /opt/minio/data)
mkdir -p /opt/minio/config mkdir -p /opt/minio/data
4、创建minio容器并运行
docker run \ -p 19000:9000 \ -p 9090:9090 \ --net=host \ --name minio \ -d --restart=always \ -e "minio_access_key=minioadmin" \ -e "minio_secret_key=minioadmin" \ -v /opt/minio/data:/data \ -v /opt/minio/config:/root/.minio \ minio/minio server \ /data --console-address ":9090" -address ":19000"
命令 | 描述 |
---|---|
-p 9000:9000 -p 9090:9090 | 这是端口映射,前一个是服务器的端口,后一个是客户端也就是api接口访问的端口地址 |
–name minio | 这是给新创建的容器命名的选项,名字是 “minio” |
–net=host | 这是网络设置,表示容器将使用主机的网络栈,这样就不需要在容器内部配置网络 |
-d --restart=always | 这是运行容器的其他选项,-d使容器在后台运行,–restart=always表示容器总是会在退出后自动重启 |
-e “minio_access_key=minioadmin” | 用户名 |
-e “minio_secret_key=minioadmin” | 密码 |
-v /opt/minio/data:/data | 这意味着将宿主机上的 /opt/minio/data 目录挂载到容器内的 /data 目录 |
-v /opt/minio/config:/root/.minio | 将宿主机上的 /opt/minio/config 目录挂载到容器内的 /root/.minio 目录 |
minio/minio server /data --console-address “:9090” -address “:9000” | 这是容器内要运行的命令,启动一个名为 “minio” 的服务器,数据存储在 /data 目录下,服务器的控制台地址为 “:9090”,服务地址为 “:9000” |
\ | 换行 |
4.1、访问操作
访问:http://47.117.160.102:9090/login 用户名:密码 minioadmin:minioadmin
4.2、创建用户
4.3、创建组
4.4、创建buckets
4.5、创建access keys
4.6、文件上传
4.7、浏览器访问上传文件
4.6.1、输入ip:19000/buckets名/文件名,如果不行,看看端口是否开放
5、springboot简单使用
5.1、添加minio依赖pom
<dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <!-- minio 客户端 --> <dependency> <groupid>io.minio</groupid> <artifactid>minio</artifactid> <version>8.5.7</version> </dependency> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> </dependency> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-lang3</artifactid> <version>3.11</version> </dependency> </dependencies>
5.2、配置minio的yaml
server: port: 3333 spring: servlet: multipart: max-request-size: 200mb max-file-size: 200mb minio: url: http://127.0.0.1:19000 #换成自己的minio服务端地址 accesskey: minioadmin # 用户名 secretkey: minioadmin # 密码 bucketname: demo # bucketname指的就是之前创建的minio桶bucket
5.3、配置类config
/** * @author haoyang * @create 2023-12-01 20:40 */ @data @configuration public class minioconfig { /** * 访问地址 */ @value("${minio.url}") private string endpoint; /** * accesskey类似于用户id,用于唯一标识你的账户 */ @value("${minio.accesskey}") private string accesskey; /** * secretkey是你账户的密码 */ @value("${minio.secretkey}") private string secretkey; /** * 默认存储桶 */ @value("${minio.bucketname}") private string bucketname; @bean public minioclient minioclient() { minioclient minioclient = minioclient.builder() .endpoint(endpoint) .credentials(accesskey, secretkey) .build(); return minioclient; } }
5.4、创建minio工具类
/** * minio工具类 * */ @slf4j @component @requiredargsconstructor public class minioutils { private final minioclient minioclient; /****************************** operate bucket start ******************************/ /** * 启动springboot容器的时候初始化bucket * 如果没有bucket则创建 * * @param bucketname */ @sneakythrows(exception.class) private void createbucket(string bucketname) { if (!bucketexists(bucketname)) { minioclient.makebucket(makebucketargs.builder().bucket(bucketname).build()); } } /** * 判断bucket是否存在,true:存在,false:不存在 * * @param bucketname * @return */ @sneakythrows(exception.class) public boolean bucketexists(string bucketname) { return minioclient.bucketexists(bucketexistsargs.builder().bucket(bucketname).build()); } /** * 获得bucket的策略 * * @param bucketname * @return */ @sneakythrows(exception.class) public string getbucketpolicy(string bucketname) { return minioclient.getbucketpolicy(getbucketpolicyargs .builder() .bucket(bucketname) .build()); } /** * 获得所有bucket列表 * * @return */ @sneakythrows(exception.class) public list<bucket> getallbuckets() { return minioclient.listbuckets(); } /** * 根据bucketname获取其相关信息 * * @param bucketname * @return */ @sneakythrows(exception.class) public optional<bucket> getbucket(string bucketname) { return getallbuckets().stream().filter(b -> b.name().equals(bucketname)).findfirst(); } /** * 根据bucketname删除bucket,true:删除成功; false:删除失败,文件或已不存在 * * @param bucketname * @throws exception */ @sneakythrows(exception.class) public void removebucket(string bucketname) { minioclient.removebucket(removebucketargs.builder().bucket(bucketname).build()); } /****************************** operate bucket end ******************************/ /****************************** operate files start ******************************/ /** * 判断文件是否存在 * * @param bucketname * @param objectname * @return */ public boolean isobjectexist(string bucketname, string objectname) { boolean exist = true; try { minioclient.statobject(statobjectargs.builder().bucket(bucketname).object(objectname).build()); } catch (exception e) { log.error("[minio工具类]>>>> 判断文件是否存在, 异常:", e); exist = false; } return exist; } /** * 判断文件夹是否存在 * * @param bucketname * @param objectname * @return */ public boolean isfolderexist(string bucketname, string objectname) { boolean exist = false; try { iterable<result<item>> results = minioclient.listobjects( listobjectsargs.builder().bucket(bucketname).prefix(objectname).recursive(false).build()); for (result<item> result : results) { item item = result.get(); if (item.isdir() && objectname.equals(item.objectname())) { exist = true; } } } catch (exception e) { log.error("[minio工具类]>>>> 判断文件夹是否存在,异常:", e); exist = false; } return exist; } /** * 根据文件前置查询文件 * * @param bucketname 存储桶 * @param prefix 前缀 * @param recursive 是否使用递归查询 * @return minioitem 列表 */ @sneakythrows(exception.class) public list<item> getallobjectsbyprefix(string bucketname, string prefix, boolean recursive) { list<item> list = new arraylist<>(); iterable<result<item>> objectsiterator = minioclient.listobjects( listobjectsargs.builder().bucket(bucketname).prefix(prefix).recursive(recursive).build()); if (objectsiterator != null) { for (result<item> o : objectsiterator) { item item = o.get(); list.add(item); } } return list; } /** * 获取文件流 * * @param bucketname 存储桶 * @param objectname 文件名 * @return 二进制流 */ @sneakythrows(exception.class) public inputstream getobject(string bucketname, string objectname) { return minioclient.getobject( getobjectargs.builder() .bucket(bucketname) .object(objectname) .build()); } /** * 断点下载 * * @param bucketname 存储桶 * @param objectname 文件名称 * @param offset 起始字节的位置 * @param length 要读取的长度 * @return 二进制流 */ @sneakythrows(exception.class) public inputstream getobject(string bucketname, string objectname, long offset, long length) { return minioclient.getobject( getobjectargs.builder() .bucket(bucketname) .object(objectname) .offset(offset) .length(length) .build()); } /** * 获取路径下文件列表 * * @param bucketname 存储桶 * @param prefix 文件名称 * @param recursive 是否递归查找,false:模拟文件夹结构查找 * @return 二进制流 */ public iterable<result<item>> listobjects(string bucketname, string prefix, boolean recursive) { return minioclient.listobjects( listobjectsargs.builder() .bucket(bucketname) .prefix(prefix) .recursive(recursive) .build()); } /** * 使用multipartfile进行文件上传 * * @param bucketname 存储桶 * @param file 文件名 * @param objectname 对象名 * @param contenttype 类型 * @return */ @sneakythrows(exception.class) public objectwriteresponse uploadfile(string bucketname, multipartfile file, string objectname, string contenttype) { inputstream inputstream = file.getinputstream(); return minioclient.putobject( putobjectargs.builder() .bucket(bucketname) .object(objectname) .contenttype(contenttype) .stream(inputstream, inputstream.available(), -1) .build()); } /** * 图片上传 * @param bucketname * @param imagebase64 * @param imagename * @return */ public objectwriteresponse uploadimage(string bucketname, string imagebase64, string imagename) { if (!stringutils.isempty(imagebase64)) { inputstream in = base64toinputstream(imagebase64); string newname = system.currenttimemillis() + "_" + imagename + ".jpg"; string year = string.valueof(new date().getyear()); string month = string.valueof(new date().getmonth()); return uploadfile(bucketname, year + "/" + month + "/" + newname, in); } return null; } // base64decoder在jdk8以上的版本移除了,报错最简单解决换成jdk8就行了 public static inputstream base64toinputstream(string base64) { bytearrayinputstream stream = null; try { byte[] bytes = new base64decoder().decodebuffer(base64.trim()); stream = new bytearrayinputstream(bytes); } catch (exception e) { e.printstacktrace(); } return stream; } /** * 上传本地文件 * * @param bucketname 存储桶 * @param objectname 对象名称 * @param filename 本地文件路径 * @return */ @sneakythrows(exception.class) public objectwriteresponse uploadfile(string bucketname, string objectname, string filename) { return minioclient.uploadobject( uploadobjectargs.builder() .bucket(bucketname) .object(objectname) .filename(filename) .build()); } /** * 通过流上传文件 * * @param bucketname 存储桶 * @param objectname 文件对象 * @param inputstream 文件流 * @return */ @sneakythrows(exception.class) public objectwriteresponse uploadfile(string bucketname, string objectname, inputstream inputstream) { return minioclient.putobject( putobjectargs.builder() .bucket(bucketname) .object(objectname) .stream(inputstream, inputstream.available(), -1) .build()); } /** * 创建文件夹或目录 * * @param bucketname 存储桶 * @param objectname 目录路径 * @return */ @sneakythrows(exception.class) public objectwriteresponse createdir(string bucketname, string objectname) { return minioclient.putobject( putobjectargs.builder() .bucket(bucketname) .object(objectname) .stream(new bytearrayinputstream(new byte[]{}), 0, -1) .build()); } /** * 获取文件信息, 如果抛出异常则说明文件不存在 * * @param bucketname 存储桶 * @param objectname 文件名称 * @return */ @sneakythrows(exception.class) public string getfilestatusinfo(string bucketname, string objectname) { return minioclient.statobject( statobjectargs.builder() .bucket(bucketname) .object(objectname) .build()).tostring(); } /** * 拷贝文件 * * @param bucketname 存储桶 * @param objectname 文件名 * @param srcbucketname 目标存储桶 * @param srcobjectname 目标文件名 */ @sneakythrows(exception.class) public objectwriteresponse copyfile(string bucketname, string objectname, string srcbucketname, string srcobjectname) { return minioclient.copyobject( copyobjectargs.builder() .source(copysource.builder().bucket(bucketname).object(objectname).build()) .bucket(srcbucketname) .object(srcobjectname) .build()); } /** * 删除文件 * * @param bucketname 存储桶 * @param objectname 文件名称 */ @sneakythrows(exception.class) public void removefile(string bucketname, string objectname) { minioclient.removeobject( removeobjectargs.builder() .bucket(bucketname) .object(objectname) .build()); } /** * 批量删除文件 * * @param bucketname 存储桶 * @param keys 需要删除的文件列表 * @return */ public void removefiles(string bucketname, list<string> keys) { list<deleteobject> objects = new linkedlist<>(); keys.foreach(s -> { objects.add(new deleteobject(s)); try { removefile(bucketname, s); } catch (exception e) { log.error("[minio工具类]>>>> 批量删除文件,异常:", e); } }); } /** * 获取文件外链 * * @param bucketname 存储桶 * @param objectname 文件名 * @param expires 过期时间 <=7 秒 (外链有效时间(单位:秒)) * @return url */ @sneakythrows(exception.class) public string getpresignedobjecturl(string bucketname, string objectname, integer expires) { getpresignedobjecturlargs args = getpresignedobjecturlargs.builder().expiry(expires).bucket(bucketname).object(objectname).build(); return minioclient.getpresignedobjecturl(args); } /** * 获得文件外链 * * @param bucketname * @param objectname * @return url */ @sneakythrows(exception.class) public string getpresignedobjecturl(string bucketname, string objectname) { getpresignedobjecturlargs args = getpresignedobjecturlargs.builder() .bucket(bucketname) .object(objectname) .method(method.get).build(); return minioclient.getpresignedobjecturl(args); } /** * 将urldecoder编码转成utf8 * * @param str * @return * @throws unsupportedencodingexception */ public string getutf8byurldecoder(string str) throws unsupportedencodingexception { string url = str.replaceall("%(?![0-9a-fa-f]{2})", "%25"); return urldecoder.decode(url, "utf-8"); } }
5.5、创建controller
/** * @author haoyang * @create 2023-12-01 20:38 */ @slf4j @restcontroller @requestmapping("/oss") public class osscontroller { @autowired private minioutils minioutils; @autowired private minioconfig minioconfig; /** * 文件上传 * * @param file */ @postmapping("/upload") public string upload(@requestparam("file") multipartfile file) { try { //文件名 string filename = file.getoriginalfilename(); string newfilename = system.currenttimemillis() + "." + stringutils.substringafterlast(filename, "."); //类型 string contenttype = file.getcontenttype(); minioutils.uploadfile(minioconfig.getbucketname(), file, newfilename, contenttype); return "上传成功"; } catch (exception e) { log.error("上传失败"); return "上传失败"; } } /** * 删除 * * @param filename */ @deletemapping("/") public void delete(@requestparam("filename") string filename) { minioutils.removefile(minioconfig.getbucketname(), filename); } /** * 获取文件信息 * * @param filename * @return */ @getmapping("/info") public string getfilestatusinfo(@requestparam("filename") string filename) { return minioutils.getfilestatusinfo(minioconfig.getbucketname(), filename); } /** * 获取文件外链 * * @param filename * @return */ @getmapping("/url") public string getpresignedobjecturl(@requestparam("filename") string filename) { return minioutils.getpresignedobjecturl(minioconfig.getbucketname(), filename); } /** * 文件下载 * * @param filename * @param response */ @getmapping("/download") public void download(@requestparam("filename") string filename, httpservletresponse response) { try { inputstream fileinputstream = minioutils.getobject(minioconfig.getbucketname(), filename); response.setheader("content-disposition", "attachment;filename=" + filename); response.setcontenttype("application/force-download"); response.setcharacterencoding("utf-8"); ioutils.copy(fileinputstream, response.getoutputstream()); } catch (exception e) { log.error("下载失败"); } } }
6、测试验证
6.1、文件上传
使用postman调用http://localhost:3333/oss/upload 接口,选择某个文件测试上传功能,如下图所示:
6.2、文件下载
在浏览器中,调用http://localhost:3333/oss/download?filename=1701436432918.gif 接口,验证文件下载接口,如下图所示:
以上就是docker搭建minio容器的流程步骤的详细内容,更多关于docker搭建minio容器的资料请关注代码网其它相关文章!
发表评论