青岛谁做网站多少钱,wordpress模板 官网,永康好口碑关键词优化,东莞房价2022最新房价docker-compose搭建minio对象存储服务器 最近想使用oss对象存储进行用户图片上传的管理#xff0c;了解了一下例如aliyun或者腾讯云的oss对象存储服务#xff0c;但是呢涉及到对象存储以及经费有限的缘故#xff0c;决定自己手动搭建一个oss对象存储服务器#xff1b; 首先…docker-compose搭建minio对象存储服务器 最近想使用oss对象存储进行用户图片上传的管理了解了一下例如aliyun或者腾讯云的oss对象存储服务但是呢涉及到对象存储以及经费有限的缘故决定自己手动搭建一个oss对象存储服务器 首先大致了解一下对象存储 对象存储OSSObject Storage Service是一种云存储服务它提供了海量、安全、低成本、高可靠的存储解决方案 然后在经过大致了解后选择了MiNiO进行oss对象服务器的搭建工作MinIO是一个开源的对象存储服务器它兼容Amazon S3 API并提供高性能、高可用性的存储解决方案。在本文中我们将介绍如何使用Docker Compose快速部署MinIO。
一、docker-compose中的minio对象服务部署
准备工作 1、服务器必须安装docker 2、服务器必须安装docker对应版本的docker-compose 1.1获取镜像
首先如果你的docker还能连上网能够通过docker pull相关的镜像咳咳最近docker不对劲拉取不到镜像如果可以拉取镜像可以执行下述命令
docker pull minio/minio:latest如果不可以建议在往上下载一个minio的tar包上传至服务器后可以执行以下命令
docker load -i minio.tar ## minio 是你自己tar包的名字。通过上述操作后可以使用 docker images 进行查看获取到的镜像
1.2 docker-compose.yml文件制作
vim docker-compose.yml先贴一个代码叭一会儿挨个儿解释
version: 3
services:minio:image: minio/miniocontainer_name: minioports:- 9010:9000- 9011:9011environment:TZ: Asia/ShanghaiMINIO_ACCESS_KEY: minioMINIO_SECRET_KEY: minio123volumes:- ./data:/datacommand: server /data --console-address :9011大概配置如上所示有几点注意 注 1、minio容器默认使用两个端口9000和9001 9000端口主要适用于数据传输9001端口主要是用于管理界面上述文件中我为了好记且避免端口冲突将9000端口映射到了服务器的9010端口将9001端口改成了9011并映射到了服务器的9011端口 2、数据卷映射 默认将数据卷映射到了docker-compose.yml同文件目录下的data文件夹 3、command: server --console-address ‘:9011’ /data 这行一定要加否则端口号是随机的你压根映射不出去 4、新版本中用户名和密码改用成了 “MINIO_ROOT_USER” 和 “MINIO_ROOT_PASSWORD” 旧版本是 “MINIO_ACCESS_KEY” 和 “MINIO_SECRET_KEY” 可以自己按照版本进行设置。 5、4中分别对应的是管理界面的用户名和密码 在编辑docker-compose.yml并保存后通过下述命令创建并启动minio容器
#如果你的docker-compose.yml文件中有好几个容器你并不想启动其他容器只想启动minio
docker-compose up -d minio
#如果你的docker-compose.yml文件中只有目前的minio
docker-compose up -d 启动成功后会看到服务器显示 此时可以在浏览器输入 上面docker-compose.yml文件中的【你自己的IP9011】 访问minio的控制面板记得开启防火墙90109011端口哟~ 输入用户名和密码登录minio控制面板 至此呢 单机版本 通过docker-compose 部署minio对象存储结束
二、spring-boot 集成 minio 对象存储
1、自己创建spring-boot 工程在这里不多赘述
2、引入pom依赖
在自己的boot项目中引入minio依赖
!---minio cos对象存储--dependencygroupIdio.minio/groupIdartifactIdminio/artifactIdversion8.4.0/version/dependency3、集成代码
在集成代码之前呢首先了解一下minio的几个知识点 Object存储到Minio的基本对象如文件、字节流、Anything…Bucket用来存储Object的逻辑空间。每个Bucket之间的数据量是互相隔离的。对于客户端而言就相当于一个存放文件的顶层文件夹。Drive即存储数据的磁盘在Minio启动时以参数的方式传入。Minio中所有的对象数据都会存储在Drive里。Set即一组Drive的集合分布式部署根据集群规模自动划分一个或多个Set每个Set中的Drive分布在不同位置。一个对象存储在一个Set上.for example:{1…64} is divided into 4 sets each of size 16 一个对象存储在一个Set上一个集群划分为多个Set一个Set包含的Drive数量是固定的默认由系统根据集群规模自动计算得出一个Set中我的Drive尽可能分布在不同的节点上 3.1 创建用户创建桶
可以在minio控制面板进行用户的创建以及存储桶bucket的创建。我们创建一个test的桶以及创建一个用户并赋予读写的权限 3.2 添加application.yml配置文件
minio:url: http://xxxxxxx #Minio服务所在地址bucketName: xxxxxx #存储桶名称accessKey: testUser #创建用户访问的key secretKey: 000000000 #创建用户 访问的秘钥3.3 引入配置
创建MinioConfig 配置文件将MinioClient 注入容器
Data
Configuration
ConfigurationProperties(prefix minio)
public class MinioConfig {/*** 服务地址*/private String url;/*** 用户名*/private String accessKey;/*** 密码*/private String secretKey;/*** 存储桶名称*/private String bucketName;/*** 预览到期时间小时*/private Integer previewExpiry;Beanpublic MinioClient getMinIOClient() {return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();}
}3.4 引入相关操作
创建MinioCosManger文件 封装了minio客户端的一些操作
Component
Slf4j
public class MinioCosManger {Autowiredprivate MinioConfig prop;Resourceprivate MinioClient minioClient;/*** 查看存储bucket是否存在** return boolean*/public Boolean bucketExists(String bucketName) {Boolean found;try {found minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return found;}/*** 创建存储bucket** return Boolean*/public Boolean makeBucket(String bucketName) {try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 删除存储bucket** return Boolean*/public Boolean removeBucket(String bucketName) {try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 获取全部bucket*/public ListBucket getAllBuckets() {try {ListBucket buckets minioClient.listBuckets();return buckets;} catch (Exception e) {e.printStackTrace();}return null;}/*** 文件上传** param file 文件* return Boolean*/public String upload(MultipartFile file) {String originalFilename file.getOriginalFilename();if (StringUtils.isBlank(originalFilename)) {throw new RuntimeException();}String fileName UUID.randomUUID() originalFilename.substring(originalFilename.lastIndexOf(.));String dateFormat yyyy-MM/dd;DateTimeFormatter formatter DateTimeFormatter.ofPattern(dateFormat);LocalDate nowDate LocalDate.now();String format nowDate.format(formatter);String objectName format / fileName;try {PutObjectArgs objectArgs PutObjectArgs.builder().bucket(prop.getBucketName()).object(objectName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();//文件名称相同会覆盖minioClient.putObject(objectArgs);} catch (Exception e) {e.printStackTrace();return null;}return objectName;}/*** 预览图片** param fileName* return*/public String preview(String fileName) {// 查看文件地址GetPresignedObjectUrlArgs build new GetPresignedObjectUrlArgs().builder().bucket(prop.getBucketName()).object(fileName).method(Method.GET).build();try {String url minioClient.getPresignedObjectUrl(build);return url;} catch (Exception e) {e.printStackTrace();}return null;}/*** 文件下载** param fileName 文件名称* param res response* return Boolean*/public void download(String fileName, HttpServletResponse res) {GetObjectArgs objectArgs GetObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build();try (GetObjectResponse response minioClient.getObject(objectArgs)) {byte[] buf new byte[1024];int len;try (FastByteArrayOutputStream os new FastByteArrayOutputStream()) {while ((len response.read(buf)) ! -1) {os.write(buf, 0, len);}os.flush();byte[] bytes os.toByteArray();res.setCharacterEncoding(utf-8);// 设置强制下载不打开// res.setContentType(application/force-download);res.addHeader(Content-Disposition, attachment;fileName fileName);try (ServletOutputStream stream res.getOutputStream()) {stream.write(bytes);stream.flush();}}} catch (Exception e) {e.printStackTrace();}}/*** 查看文件对象** return 存储bucket内文件对象信息*/public ListItem listObjects() {IterableResultItem results minioClient.listObjects(ListObjectsArgs.builder().bucket(prop.getBucketName()).build());ListItem items new ArrayList();try {for (ResultItem result : results) {items.add(result.get());}} catch (Exception e) {e.printStackTrace();return null;}return items;}/*** 删除** param fileName* return* throws Exception*/public boolean remove(String fileName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());} catch (Exception e) {return false;}return true;}}3.5 创建controller进行测试
/*** version 1.0* Author jerryLau* Date 2024/7/1 11:23* 注释*/
Api(tags 文件相关接口)
Slf4j
RestController
RequestMapping(value product/file)
public class FileController2 {Autowiredprivate MinioCosManger minioUtil;Autowiredprivate MinioConfig prop;ApiOperation(value 查看存储bucket是否存在)GetMapping(/bucketExists)public BaseResponseString bucketExists(RequestParam(bucketName) String bucketName) {if (minioUtil.bucketExists(bucketName)) {return ResultUtils.success(bucketName is exit!);} elsereturn ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, bucketName is not exit!);}ApiOperation(value 创建存储bucket)GetMapping(/makeBucket)public BaseResponseString makeBucket(String bucketName) {if (minioUtil.makeBucket(bucketName)) {return ResultUtils.success(create bucket success!);} elsereturn ResultUtils.error(ErrorCode.OPERATION_ERROR, create bucket error!);}ApiOperation(value 删除存储bucket)GetMapping(/removeBucket)public BaseResponseString removeBucket(String bucketName) {if (minioUtil.removeBucket(bucketName)) {return ResultUtils.success(removeBucket success!);} elsereturn ResultUtils.error(ErrorCode.OPERATION_ERROR, removeBucket error!);}ApiOperation(value 获取全部bucket)GetMapping(/getAllBuckets)public BaseResponseListBucket getAllBuckets() {ListBucket allBuckets minioUtil.getAllBuckets();return ResultUtils.success(allBuckets);}ApiOperation(value 文件上传返回url)PostMapping(/upload)public BaseResponseString upload(RequestParam(file) MultipartFile file) {String objectName minioUtil.upload(file);if (null ! objectName) {String url (prop.getUrl() / prop.getBucketName() / objectName);return ResultUtils.success(url);}return ResultUtils.error(ErrorCode.OPERATION_ERROR, upload error!);}ApiOperation(value 图片/视频预览)GetMapping(/preview)public BaseResponseString preview(RequestParam(fileName) String fileName) {String preview minioUtil.preview(fileName);return ResultUtils.success(preview);}ApiOperation(value 文件下载)GetMapping(/download)public void download(RequestParam(fileName) String fileName, HttpServletResponse res) {minioUtil.download(fileName, res);}ApiOperation(value 删除文件, notes 根据url地址删除文件)PostMapping(/delete)public BaseResponseString remove(String url) {String objName url.substring(url.lastIndexOf(prop.getBucketName() /) prop.getBucketName().length() 1);boolean remove minioUtil.remove(objName);if (remove) {return ResultUtils.success(objName delete success!);} else return ResultUtils.error(ErrorCode.OPERATION_ERROR, objName delete error!);}}3.6 接口测试以及存储验证
通过knife4j或者其他请求测试工具postman、apifox等测试接口 注意 1、按照理论来说在上传结束后返回的这个文件的url应该没有办法直接访问应该在访问该存储对象的时候去调用preview方法但是对本人而言调用preview返回的地址太长了并且存在一定的时效性在超过一段时间后将不会在被访问到所以本人通过给bucket设置access prefix为 readandwrite这样一来上传接口的返回url便可直接被访问到了。 2、如果想去调用preview 或者download 方法时所传入的文件名一定是bucket后面的全部文件名称比如上面测试图片中如果调用传入文件名应为2024-07/01/0011c366-f2a4-4b26-adbc-931d444d7205.png 而不是简单的0011c366-f2a4-4b26-adbc-931d444d7205.png ,否则即使返回了preview的url 这个url也无法被访问到。 至此通过docker-compose手动搭建minio 对象存储服务器已全部完结喜欢的观众老爷请一键三连 感谢大家~