首页
最新活动
服务器租用
香港服务器租用
台湾服务器租用
美国服务器租用
日本服务器租用
新加坡服务器租用
高防服务器
香港高防服务器
台湾高防服务器
美国高防服务器
裸金属
香港裸金属服务器
台湾裸金属服务器
美国裸金属服务器
日本裸金属服务器
新加坡裸金属服务器
云服务器
香港云服务器
台湾云服务器
美国云服务器
日本云服务器
CDN
CDN节点
CDN带宽
CDN防御
CDN定制
行业新闻
官方公告
香港服务器资讯
帮助文档
wp博客
zb博客
服务器资讯
联系我们
关于我们
机房介绍
机房托管
登入
注册
帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
联系客服
服务器资讯
/
香港服务器租用
/
香港VPS租用
/
香港云服务器
/
美国服务器租用
/
台湾服务器租用
/
日本服务器租用
/
官方公告
/
帮助文档
MinIO的安装与使用
发布时间:2024-03-11 02:51:49 分类:帮助文档
MinIO的安装与使用 MinIO的安装与使用 一、MinIO是什么?二、MinIO安装(centos7)2.1 下载MinIO2.2 启动MinIO2.3 修改配置2.4 编写启动脚本,以及加入到systemctl中 三、Springboot集成MinIO3.1 项目应用 四、Java中图片压缩上传4.1 背景4.2 开发准备4.3 压缩上传 五、MinIO集群搭建(完善中~) 一、MinIO是什么? MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。 MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。 MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。 MinIO主要采用Golang语言实现,,客户端与存储服务器之间采用http/https通信协议。 它与 Amazon S3 云存储服务 API 兼容 MinIO的相关信息 中文官网: http://www.minio.org.cn/ 中文文档: http://docs.minio.org.cn/docs/ 中文下载地址:http://www.minio.org.cn/download.shtml#/linux 英文官网: https://min.io/ 英文文档: https://docs.min.io/ 英文下载地址:https://min.io/download#/linux Github地址:https://github.com/minio/minio 二、MinIO安装(centos7) 2.1 下载MinIO 演示以官网下载二进制文件配置,下载地址见上方,,,,docker安装更简单哦~ #创建目录 mkdir /usr/local/minio/ cd /usr/local/minio/ #下载并添加权限 wget http://dl.minio.org.cn/server/minio/release/linux-amd64/minio #赋值权限 chmod +x minio 2.2 启动MinIO #创建数据目录,数据目录存储需要大点 mkdir -p /home/data/minio #创建日志目录 mkdir -p /home/data/minio/log touch /home/data/minio/log/minio.log #前台启动minio ./minio server /home/data/minio #后台启动minio nohup ./minio server /home/data/minio > /home/data/minio/log/minio.log & # nohup端口自定义启动服务 指定文件存放路径 /home/data/minio 还有设置日志文件路径 /home/data/minio/log/minio.log nohup ./minio server --address :9000 --console-address :9001 /home/data/minio > /home/data/minio/log/minio.log 2>&1 & –address :9000 --console-address :9001 是配置端口,默认minio端口是9000,如果9000端口被占用了,那就加上这一串配置,端口号的冒号之前不需要特意写出ip,当然如果你的ip的动态变化的,而不是静态的话,前边的ip不用写上,当然最好是用静态的ip 关闭防火墙 如果未关闭,输入以下命令: systemctl stop firewalld 注意:如果不想关闭防火墙,需要开放ip端口9000和设置静态控制访问IP 访问:http://192.168.92.100:9000查看控制台 这里我们都使用的默认配置账号密码 minioadmin:minioadmin 2.3 修改配置 这里账号和密码都是用的默认的,如果我们要修改可以在环境变量里设置 修改环境变量 打开 /etc/profile 文件 vim /etc/profile 在文件的最末尾加上以下信息(启动的时候看提示,新版本需要用MINIO_ROOT_USER和MINIO_ROOT_PASSWORD,旧版需要用MINIO_ACCESS_KEY和MINIO_SECRET_KEY)。 按 i 键后,在文档末尾输入 (1)新版: export MINIO_ROOT_USER=minioadmin export MINIO_ROOT_PASSWORD=admin123 (2)旧版 export MINIO_ACCESS_KEY=minioadmin export MINIO_SECRET_KEY=admin123 保存退出,刷新重载环境变量 source /etc/profile 2.4 编写启动脚本,以及加入到systemctl中 为了方便管理,我们这里给命令添加到脚本中 在/usr/local/minio/目录下新建run.sh vim run.sh 然后将以下内容保存到run.sh,并为其赋予执行权限chmod +x run.sh #!/bin/bash #配置登陆账号密码 export MINIO_ROOT_USER=minioadmin export MINIO_ROOT_PASSWORD=admin123 # nohup启动服务 指定文件存放路径 /home/data/minio 还有设置日志文件路径 /home/data/minio/log/minio.log nohup ./minio server --address :9000 --console-address :9001 /home/data/minio > /home/data/minio/log/minio.log 2>&1 & 然后启动minio # 启动minio服务 bash run.sh # 查看日志 tail -200f /home/data/minio/log/minio.log 然后会有日志打印信息,然后可以看到minio服务器地址,和控制台信息地址 然后在浏览器中访问地址http://192.168.92.100:9000,输入这个地址后会重定向到控制台登录地址http://192.168.92.100:9001/login 添加到systemctl启动命令中 编写minio.service文件 vim /usr/lib/systemd/system/minio.service 填写以下内容 [Unit] Description=minio Documentation=https://docs.min.io Wants=network-online.target After=network-online.target AssertFileIsExecutable=/usr/local/minio/minio [Service] #User and group User=root Group=root ExecStart=/usr/local/minio/run.sh #Let systemd restart this service always Restart=always #Specifies the maximum file descriptor number that can be opened by this process LimitNOFILE=65536 #Disable timeout logic and wait until process is stopped TimeoutStopSec=infinity SendSIGKILL=no [Install] WantedBy=multi-user.target 赋值权限并且启动 chmod +x /usr/lib/systemd/system/minio.service 启动、查看、设置开机启动 systemctl daemon-reload systemctl start minio systemctl enable minio systemctl status minio 启动报错处理 systemctl start minio Assertion failed on job for minio.service. # 是 minio.service 的 AssertFileIsExecutable 路径错误 AssertFileIsExecutable=/usr/local/minio # 改为 AssertFileIsExecutable=/usr/local/minio/minio 到这里单机版的已经安装完毕! 三、Springboot集成MinIO 3.1 项目应用 项目的pom文件中引入minio依赖
7.1.0
io.minio
minio
${minio.version}
在application.yml文件中配置minio minio: endpoint: http://192.168.92.100 port: 9000 accessKey: minioadmin secretKey: admin123 bucketName: test secure: false spring: #设置文件上传大小限制 servlet: multipart: max-file-size: 100MB max-request-size: 150MB 创建minio配置类和工具类 配置类: package cn.cvzhanshi.wechatpush.config; import io.minio.MinioClient; import io.minio.errors.InvalidPortException; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration @Component @ConfigurationProperties(prefix = "minio") @Getter @Setter public class MinioConfig { private String endpoint; private int port; private String accessKey; private String secretKey; private Boolean secure; private String bucketName; @Bean public MinioClient getMinioClient() throws InvalidPortException { MinioClient minioClient = MinioClient.builder().endpoint(endpoint, port, secure) .credentials(accessKey, secretKey) .build(); return minioClient; } // // @Bean(name = "multipartResolver") // public MultipartResolver multipartResolver(){ // CommonsMultipartResolver resolver = new CommonsMultipartResolver(); // resolver.setDefaultEncoding("UTF-8"); // //resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常 // resolver.setResolveLazily(true); // resolver.setMaxInMemorySize(40960); // //上传文件大小 50M 50*1024*1024 // resolver.setMaxUploadSize(50*1024*1024); // return resolver; // } } 工具类: package cn.cvzhanshi.wechatpush.utils; import io.minio.*; import io.minio.errors.*; import io.minio.http.Method; import io.minio.messages.Bucket; import io.minio.messages.DeleteError; import io.minio.messages.DeleteObject; import io.minio.messages.Item; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; / * MinIO 客户端工具类 */ @Component @Slf4j public class MinioClientUtils { @Autowired private MinioClient minioClient; private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600; / * 检查存储桶是否存在 * * @param bucketName 存储桶名称 * @return boolean */ public boolean bucketExists(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = false; flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); if (flag) { return true; } return false; } / * 创建存储桶 * * @param bucketName 存储桶名称 */ public boolean makeBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, RegionConflictException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (!flag) { minioClient.makeBucket( MakeBucketArgs.builder() .bucket(bucketName) .build()); return true; } else { return false; } } / * 列出所有存储桶名称 * * @return List
*/ public List
listBucketNames() throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { List
bucketList = listBuckets(); List
bucketListName = new ArrayList<>(); for (Bucket bucket : bucketList) { bucketListName.add(bucket.name()); } return bucketListName; } / * 列出所有存储桶 * * @return List
*/ public List
listBuckets() throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { return minioClient.listBuckets(); } / * 删除存储桶 * * @param bucketName 存储桶名称 * @return boolean */ public boolean removeBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { Iterable
> myObjects = listObjects(bucketName); for (Result
result : myObjects) { Item item = result.get(); // 有对象文件,则删除失败 if (item.size() > 0) { return false; } } // 删除存储桶,注意,只有存储桶为空时才能删除成功。 minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); flag = bucketExists(bucketName); if (!flag) { return true; } } return false; } / * 列出存储桶中的所有对象名称 * * @param bucketName 存储桶名称 * @return List
*/ public List
listObjectNames(String bucketName) throws XmlParserException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, InvalidBucketNameException, InsufficientDataException, InternalException { List
listObjectNames = new ArrayList<>(); boolean flag = bucketExists(bucketName); if (flag) { Iterable
> myObjects = listObjects(bucketName); for (Result
result : myObjects) { Item item = result.get(); listObjectNames.add(item.objectName()); } } return listObjectNames; } / * 列出存储桶中的所有对象 * * @param bucketName 存储桶名称 * @return Iterable
> */ public Iterable
> listObjects(String bucketName) throws XmlParserException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); if (flag) { return minioClient.listObjects( ListObjectsArgs.builder().bucket(bucketName).build()); } return null; } / * 通过文件上传到对象 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param fileName File name * @return boolean */ public boolean uploadObject(String bucketName, String objectName, String fileName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { minioClient.uploadObject( UploadObjectArgs.builder() .bucket(bucketName).object(objectName).filename(fileName).build()); ObjectStat statObject = statObject(bucketName, objectName); if (statObject != null && statObject.length() > 0) { return true; } } return false; } / * 文件上传 * * @param bucketName 存储捅名称 * @param multipartFile 文件 * @param filename 文件名 */ public void putObject(String bucketName, MultipartFile multipartFile, String filename) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE); putObjectOptions.setContentType(multipartFile.getContentType()); minioClient.putObject( PutObjectArgs.builder().bucket(bucketName).object(filename).stream( multipartFile.getInputStream(), multipartFile.getSize(), -1).contentType(multipartFile.getContentType()) .build()); } / * 通过InputStream上传对象 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param inputStream 要上传的流 * @param contentType 上传的文件类型 例如 video/mp4 image/jpg * @return boolean */ public boolean putObject(String bucketName, String objectName, InputStream inputStream,String contentType) throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); if (flag) { minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( //不清楚文件的大小时,可以传-1,10485760。如果知道大小也可以传入size,partsize。 inputStream, -1, 10485760) .contentType(contentType) .build()); ObjectStat statObject = statObject(bucketName, objectName); if (statObject != null && statObject.length() > 0) { return true; } } return false; } / * 以流的形式获取一个文件对象 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @return InputStream */ public InputStream getObject(String bucketName, String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { ObjectStat statObject = statObject(bucketName, objectName); if (statObject != null && statObject.length() > 0) { InputStream stream = minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); return stream; } } return null; } / * 以流的形式获取一个文件对象(断点下载) * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param offset 起始字节的位置 * @param length 要读取的长度 (可选,如果无值则代表读到文件结尾) * @return InputStream */ public InputStream getObject(String bucketName, String objectName, long offset, Long length) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { ObjectStat statObject = statObject(bucketName, objectName); if (statObject != null && statObject.length() > 0) { InputStream stream = minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .offset(1024L) .length(4096L) .build()); return stream; } } return null; } / * 下载并将文件保存到本地 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param fileName File name * @return boolean */ public boolean downloadObject(String bucketName, String objectName, String fileName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { ObjectStat statObject = statObject(bucketName, objectName); if (statObject != null && statObject.length() > 0) { minioClient.downloadObject(DownloadObjectArgs.builder() .bucket(bucketName) .object(objectName) .filename(fileName) .build()); return true; } } return false; } / * 删除一个对象 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 */ public boolean removeObject(String bucketName, String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { boolean flag = bucketExists(bucketName); if (flag) { minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); return true; } return false; } / * 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表 * * @param bucketName 存储桶名称 * @param objectNames 含有要删除的多个object名称的迭代器对象 * @return * eg: * List
objects = new LinkedList<>(); * objects.add(new DeleteObject("my-objectname1")); * objects.add(new DeleteObject("my-objectname2")); * objects.add(new DeleteObject("my-objectname3")); */ public List
removeObjects(String bucketName, List
objectNames) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException { List
deleteErrorNames = new ArrayList<>(); boolean flag = bucketExists(bucketName); if (flag) { Iterable
> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objectNames).build()); for (Result
result : results) { DeleteError error = result.get(); deleteErrorNames.add(error.objectName()); } } return deleteErrorNames; } / * 生成一个给HTTP GET请求用的presigned URL。 * 浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天 * @return */ public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws InvalidExpiresRangeException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); String url = ""; if (flag) { if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) { throw new InvalidExpiresRangeException(expires, "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME); } try { url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(bucketName) .object(objectName) .expiry(expires)//动态参数 // .expiry(24 * 60 * 60)//用秒来计算一天时间有效期 // .expiry(1, TimeUnit.DAYS)//按天传参 // .expiry(1, TimeUnit.HOURS)//按小时传参数 .build()); } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException | InvalidExpiresRangeException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) { e.printStackTrace(); } } return url; } / * 生成一个给HTTP PUT请求用的presigned URL。 * 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天 * @return String */ public String presignedPutObject(String bucketName, String objectName, Integer expires) throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); String url = ""; if (flag) { if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) { try { throw new InvalidExpiresRangeException(expires, "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME); } catch (InvalidExpiresRangeException e) { e.printStackTrace(); } } try { url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.PUT) .bucket(bucketName) .object(objectName) .expiry(expires)//动态参数 // .expiry(24 * 60 * 60)//用秒来计算一天时间有效期 // .expiry(1, TimeUnit.DAYS)//按天传参 // .expiry(1, TimeUnit.HOURS)//按小时传参数 .build()); } catch (ErrorResponseException | InsufficientDataException e) { e.printStackTrace(); } catch (InternalException e) { log.error("InternalException",e); } catch (InvalidBucketNameException e) { log.error("InvalidBucketNameException",e); } catch (InvalidExpiresRangeException e) { log.error("InvalidExpiresRangeException",e); } catch (InvalidKeyException e) { log.error("InvalidKeyException",e); } catch (InvalidResponseException e) { log.error("InvalidResponseException",e); } catch (IOException e) { log.error("IOException",e); } catch (NoSuchAlgorithmException e) { log.error("NoSuchAlgorithmException",e); } catch (ServerException e) { log.error("ServerException",e); } catch (XmlParserException e) { log.error("XmlParserException",e); } } return url; } / * 获取对象的元数据 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @return */ public ObjectStat statObject(String bucketName, String objectName) throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); if (flag) { ObjectStat statObject = null; try { statObject = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); } catch (ErrorResponseException e) { log.error("ErrorResponseException",e); } catch (InsufficientDataException e) { log.error("ErrorResponseException",e); e.printStackTrace(); } catch (InternalException e) { log.error("InternalException",e); } catch (InvalidBucketNameException e) { log.error("InvalidBucketNameException",e); } catch (InvalidKeyException e) { log.error("InvalidKeyException",e); } catch (InvalidResponseException e) { log.error("InvalidResponseException",e); } catch (IOException e) { log.error("IOException",e); } catch (NoSuchAlgorithmException e) { log.error("NoSuchAlgorithmException",e); } catch (ServerException e) { log.error("ServerException",e); } catch (XmlParserException e) { log.error("XmlParserException",e); } return statObject; } return null; } / * 文件访问路径 * * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @return String */ public String getObjectUrl(String bucketName, String objectName) throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException { boolean flag = bucketExists(bucketName); String url = ""; if (flag) { try { url = minioClient.getObjectUrl(bucketName, objectName); } catch (ErrorResponseException e) { log.error("XmlParserException",e); } catch (InsufficientDataException e) { log.error("InsufficientDataException",e); } catch (InternalException e) { log.error("InternalException",e); } catch (InvalidBucketNameException e) { log.error("InvalidBucketNameException",e); } catch (InvalidKeyException e) { log.error("InvalidKeyException",e); } catch (InvalidResponseException e) { log.error("InvalidResponseException",e); } catch (IOException e) { log.error("IOException",e); } catch (NoSuchAlgorithmException e) { log.error("NoSuchAlgorithmException",e); } catch (ServerException e) { log.error("ServerException",e); } catch (XmlParserException e) { log.error("XmlParserException",e); } } return url; } public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) { try { InputStream file = minioClient.getObject(GetObjectArgs.builder() .bucket(bucketName) .object(fileName) .build()); String filename = new String(fileName.getBytes("ISO8859-1"), StandardCharsets.UTF_8); if (StringUtils.isNotEmpty(originalName)) { fileName = originalName; } response.setHeader("Content-Disposition", "attachment;filename=" + filename); ServletOutputStream servletOutputStream = response.getOutputStream(); int len; byte[] buffer = new byte[1024]; while ((len = file.read(buffer)) > 0) { servletOutputStream.write(buffer, 0, len); } servletOutputStream.flush(); file.close(); servletOutputStream.close(); } catch (ErrorResponseException e) { log.error("ErrorResponseException",e); } catch (Exception e) { log.error("Exception",e); } } } 创建一个数据表,用于保存上传到minio的文件的信息 CREATE TABLE `minio_file` ( `id` bigint(20) NOT NULL COMMENT '文件id', `original_file_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '原始文件名称', `file_ext_name` varchar(15) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '文件拓展名', `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(单位:字节)', `file_name` varchar(35) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '存入minio时的文件名称', `mime` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '文件的content-type', `file_url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '文件路径', `is_delete` tinyint(1) DEFAULT NULL COMMENT '是否删除 0 否 1 是', `create_by` varchar(25) COLLATE utf8mb4_bin DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_by` varchar(25) COLLATE utf8mb4_bin DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 创建minio上传接口 package cn.cvzhanshi.wechatpush.controller; import cn.cvzhanshi.wechatpush.config.MinioConfig; import cn.cvzhanshi.wechatpush.utils.MinioClientUtils; import cn.hutool.core.io.FileUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Controller; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.FileInputStream; import java.time.Instant; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/fileHandle") @Slf4j @AllArgsConstructor @Api(tags = "文件处理模块") public class FileHandleController { private MinioClientUtils minioClientUtils; private MinioConfig minioConfig; @ApiOperation(value = "上传文件,支持批量上传") @ApiImplicitParams({@ApiImplicitParam(name = "files", value = "文件流对象,接收数组格式", paramType = "query",required = true, dataType = "MultipartFile", allowMultiple = true)} ) @PostMapping("/uploadFile") public ApiResult uploadFile(@RequestParam(value = "files", required = true) MultipartFile[] files) { log.info(files.toString()); /* if (CollectionUtils.isEmpty(files)){ return ApiResult.error("未选择文件!"); }*/ List
MinioResponseDTOList = new ArrayList<>(); for (MultipartFile file : files) { String originalFilename = file.getOriginalFilename(); // 获取文件拓展名 String extName = FileUtil.extName(originalFilename); log.info("文件拓展名:" + extName); // 生成新的文件名,存入到minio long millSeconds = Instant.now().toEpochMilli(); String minioFileName = millSeconds + RandomStringUtils.randomNumeric(12) + "." + extName; String contentType = file.getContentType(); log.info("文件mime:{}", contentType); // 返回文件大小,单位字节 long size = file.getSize(); log.info("文件大小:" + size); try { String bucketName = minioConfig.getBucketName(); minioClientUtils.putObject(bucketName, file, minioFileName); String fileUrl = minioClientUtils.getObjectUrl(bucketName, minioFileName); /* MinioFile minioFile = new MinioFile(); minioFile.setOriginalFileName(originalFilename); minioFile.setFileExtName(extName); minioFile.setFileName(minioFileName); minioFile.setFileSize(size); minioFile.setMime(contentType); minioFile.setIsDelete(NumberUtils.INTEGER_ZERO); minioFile.setFileUrl(fileUrl); boolean insert = minioFile.insert(); if (insert) { MinioResponseDTO minioResponseDTO = new MinioResponseDTO(); minioResponseDTO.setFileId(minioFile.getId()); minioResponseDTO.setOriginalFileName(originalFilename); minioResponseDTO.setFileUrl(fileUrl); MinioResponseDTOList.add(minioResponseDTO); }*/ MinioResponseDTOList.add(fileUrl); } catch (Exception e) { log.error("上传文件出错:{}", e); return ApiResult.error("上传文件出错"); } } return ApiResult.success(MinioResponseDTOList); } / * 仅仅用于测试,是否可以正常上传文件 * * @return * @throws Exception */ @GetMapping("/test") @ApiOperation(value = "测试minio文件上传") public ApiResult testPutObject() throws Exception { FileInputStream fileInputStream = new FileInputStream("C:\\Users\\MSI\\Desktop\\新建文本文档.txt"); boolean bs = minioClientUtils.putObject("fsp-dev", "新建文本文档.txt", fileInputStream, "image/jpg"); log.info("上传成功?" + bs); return ApiResult.success("上传成功"); } } 测试接口 四、Java中图片压缩上传 4.1 背景 现在大家都是用的智能手机拍照,拍出来的照片小则 2-3 M,大则十几 M,所以导致图片显示较慢。思考再三,决定将图片进行压缩再上传图片服务器来解决图片显示慢的问题 4.2 开发准备 引入 maven 依赖
net.coobird
thumbnailator
0.4.8
本次我们选择了使用 thumbnailator 来作为压缩的工具 thumbnailator 简介 Thumbnailator 是一个用来生成图像缩略图的 Java 类库,通过很简单的代码即可生成图片缩略图,也可直接对一整个目录的图片生成缩略图 支持图片缩放,区域裁剪,水印,旋转,保持比例 压缩准备 判断是否是图片方法 / * 判断文件是否为图片 */ public boolean isPicture(String imgName) { boolean flag = false; if (StringUtils.isBlank(imgName)) { return false; } String[] arr = {"bmp", "dib", "gif", "jfif", "jpe", "jpeg", "jpg", "png", "tif", "tiff", "ico"}; for (String item : arr) { if (item.equals(imgName)) { flag = true; break; } } return flag; } 4.3 压缩上传 / * 上传文件 * * @param file 文件 * @return */ public JSONObject uploadFile(MultipartFile file) throws Exception { JSONObject res = new JSONObject(); res.put("code", 500); // 判断上传文件是否为空 if (null == file || 0 == file.getSize()) { res.put("msg", "上传文件不能为空"); return res; } // 判断存储桶是否存在 if (!client.bucketExists("test")) { client.makeBucket("test"); } // 拿到文件后缀名,例如:png String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1); // UUID 作为文件名 String uuid = String.valueOf(UUID.randomUUID()); // 新的文件名 String fileName = DateUtils.getYyyymmdd() + "/" + uuid + "." + suffix; / * 判断是否是图片 * 判断是否超过了 100K */ if (isPicture(suffix) && (1024 * 1024 * 0.1) <= file.getSize()) { // 在项目根目录下的 upload 目录中生成临时文件 File newFile = new File(ClassUtils.getDefaultClassLoader().getResource("upload").getPath() + uuid + "." + suffix); // 小于 1M 的 if ((1024 * 1024 * 0.1) <= file.getSize() && file.getSize() <= (1024 * 1024)) { Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.3f).toFile(newFile); } // 1 - 2M 的 else if ((1024 * 1024) < file.getSize() && file.getSize() <= (1024 * 1024 * 2)) { Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.2f).toFile(newFile); } // 2M 以上的 else if ((1024 * 1024 * 2) < file.getSize()) { Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.1f).toFile(newFile); } // 获取输入流 FileInputStream input = new FileInputStream(newFile); // 转为 MultipartFile MultipartFile multipartFile = new MockMultipartFile("file", newFile.getName(), "text/plain", input); // 开始上传 client.putObject("test", fileName, multipartFile.getInputStream(), file.getContentType()); // 删除临时文件 newFile.delete(); // 返回状态以及图片路径 res.put("code", 200); res.put("msg", "上传成功"); res.put("url", minioProp.getEndpoint() + "/" + "test" + "/" + fileName); } // 不需要压缩,直接上传 else { // 开始上传 client.putObject("test", fileName, file.getInputStream(), file.getContentType()); // 返回状态以及图片路径 res.put("code", 200); res.put("msg", "上传成功"); res.put("url", minioProp.getEndpoint() + "/" + "test" + "/" + fileName); } return res; } 这里我们判断了当文件为图片的时候,且当它大小超过了 (1024 * 1024 * 0.1),约为 100K 的时候,才进行压缩我们首先在根目录下的 upload 目录中创建了一个临时文件 newFileThumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.3f).toFile(newFile);将压缩后的文件输出到临时文件中然后将 FileInputStream 转为 MultipartFile 上传最后删除临时文件 newFile.delete();完成图片压缩上传 遇到的问题: Thumbnails.scale效果会导致图片大小变大 Thumbnails应该是存在bug,但是也一直没有更新版本,所以根据多次测试得来的结果:用jpg转成jpg效果最佳。所以当图片为png时,先改成jpg格式,再进行压缩。 public static String imgConvert(String tempDirPath, String fileName, String fileExt) throws IOException { String srcPath = tempDirPath + fileName; //原始图片路径 if("png".equals(fileExt)) { //生成新图片名称 SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); String fileString = df.format(new Date()) + "_" + new Random().nextInt(1000) + ".jpg"; //新图片全路径 String newJpg = tempDirPath + fileString; // 1、先转换成jpg Thumbnails.of(srcPath).scale(1f).toFile(newJpg); //2.jpg图片压缩 Thumbnails.of(newJpg).scale(1f).outputQuality(0.25d).toFile(newJpg); //压缩成功后,删除png图片 File f = new File(srcPath); f.delete(); return fileString; } else { Thumbnails.of(srcPath).scale(1f).outputQuality(0.25d).toFile(srcPath); } return null; } 五、MinIO集群搭建(完善中~)
上一篇
香港 虚拟主机
下一篇
香港属于中国境内吗
相关文章
VPS按错关机了怎么办
安卓盒子 魔百盒311-1a YST 刷Armbian系统刷机教程
servers怎么看谁占的内存大
asp免费空间怎么创建新的数据库
服务器出故障了怎么办
搬瓦工cn2怎么购买
新安装的Ubuntu20.04 5.13上没有WIFI 看这一篇就够了
租用服务器到底能干什么呢
电脑只有浏览器可以联网,应用不能连网。你的计算机配置似乎是正确的,但该设备或资源(dns 服务器)没有响应)
香港云服务器租用推荐
服务器租用资讯
·租用美国服务器配置
·怎样使用美国服务器(新的服务器怎样使用)
·怎么联系美国服务器(本服务器在美国受到法律)
·云服务器美国电影(美国高防云服务器)
·源服务器在美国(美国服务器ip)
·邮箱搭建美国服务器(群晖搭建邮箱服务器)
·微信美国服务器(微信小程序要服务器吗)
·受美国服务器保护(此服务器受美国保护)
·手机vpn美国服务器
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价
7*24H在线售后
高可用资源,安全稳定
1v1专属客服对接
无忧退款试用保障
德讯电讯股份有限公司
电话:00886-982-263-666
台湾总部:台北市中山区建国北路一段29号3楼
香港分公司:九龙弥敦道625号雅兰商业二期906室
服务器租用
香港服务器
日本服务器
台湾服务器
美国服务器
高防服务器购买
香港高防服务器出租
台湾高防服务器租赁
美国高防服务器DDos
云服务器
香港云服务器
台湾云服务器
美国云服务器
日本云服务器
行业新闻
香港服务器租用
服务器资讯
香港云服务器
台湾服务器租用
zblog博客
香港VPS
关于我们
机房介绍
联系我们
Copyright © 1997-2024 www.hkstack.com All rights reserved.