杭州网站建设小程序,设计制作小车视频,织梦网站百度推送加哪,打开网站显示建设中七、Java中SpringBoot组件集成接入【Minio文件服务器】 1.Minio介绍2.搭建Minio服务2.1Windows部署2.2Linux部署2.3docker部署 3.Minio可视化操作4.SpringBoot接入Minio1.添加maven依赖2.yaml配置文件3.配置类4.工具类5.控制类 5.常见问题6.其他参考文章 1.Minio介绍
对象存储… 七、Java中SpringBoot组件集成接入【Minio文件服务器】 1.Minio介绍2.搭建Minio服务2.1Windows部署2.2Linux部署2.3docker部署 3.Minio可视化操作4.SpringBoot接入Minio1.添加maven依赖2.yaml配置文件3.配置类4.工具类5.控制类 5.常见问题6.其他参考文章 1.Minio介绍
对象存储服务OSSObject Storage Service是一种海量、安全、低成本、高可靠的云存储服务适合存放任意类型的文件。容量和处理能力弹性扩展多种存储类型供选择全面优化存储成本。 Minio是一个开源的对象存储服务器可以提供Amazon S3兼容的API接口。它设计用来容易部署和扩展支持高性能、高可用性和强大的分布式存储。
关键特点包括
Amazon S3兼容性Minio兼容S3 API使得现有的S3客户端能够无缝地与Minio集成。分布式架构Minio可以水平扩展在多节点环境中提供高性能和高可用存储解决方案。高可用性Minio支持数据冗余备份和故障转移确保数据的可靠性和持久性。易于部署Minio的部署和配置简单支持Docker、Kubernetes等现代化部署方式。开源和免费基于Apache License 2.0开源许可发布用户可以免费使用并定制。强大的生态系统Minio拥有活跃的社区和文档支持为用户提供丰富的资源和工具。
总体来说Minio是一个灵活、可靠且易于使用的对象存储解决方案适用于各种规模的应用和场景帮助用户有效管理数据并构建可扩展的存储基础设施。 Minio官方文档https://min.io/ Minio中文文档http://minio.org.cn/ github项目地址https://github.com/minio/
2.搭建Minio服务
下载地址https://min.io/download
2.1Windows部署
1.下载minio.exe 2.在cmd命令行窗口中进行minio.exe所在的文件夹输入minio.exe server E:\minio命令启动服务。 server后面的地址是你图片上传之后的存储目录默认账户密码为minioadmin/minioadmin
2.2Linux部署
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod x minio
MINIO_ROOT_USERadmin MINIO_ROOT_PASSWORDpassword ./minio server /mnt/data --console-address :90012.3docker部署
docker search minio
docker pull minio/minio
docker run -d -p 9000:9000 --nameminio --restartalways -e MINIO_ROOT_USERadmin -e MINIO_ROOT_PASSWORDadmin123456 -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data --console-address :9000 --address :9090
docker logs -f containerid3.Minio可视化操作
部署启动后访问http://127.0.0.1:9000/minio可以进入到minio的控制台可以尝试进行创建存储桶上传文件到桶中删除文件等操作.
4.SpringBoot接入Minio
1.添加maven依赖 !--整合minio--dependencygroupIdio.minio/groupIdartifactIdminio/artifactIdversion8.3.7/version/dependencydependencygroupIdcom.squareup.okhttp3/groupIdartifactIdokhttp/artifactIdversion4.9.1/version/dependency2.yaml配置文件 # 文件服务器
minio:endpoint: http://ip:9000accessKey: minioadminsecretKey: minioadminbucketName: funfan3.配置类
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;Data
Configuration
public class MinioConfig {/*** 访问地址*/Value(${minio.endpoint})private String endpoint;/*** accessKey类似于用户ID用于唯一标识你的账户*/Value(${minio.accessKey})private String accessKey;/*** secretKey是你账户的密码*/Value(${minio.secretKey})private String secretKey;/*** 默认存储桶*/Value(${minio.bucketName})private String bucketName;Beanpublic MinioClient minioClient() {MinioClient minioClient MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).region(bucketName).build();return minioClient;}
}4.工具类
import cn.hutool.core.codec.Base64Decoder;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;/*** 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 ListBucket getAllBuckets() {return minioClient.listBuckets();}/*** 根据bucketName获取其相关信息** param bucketName* return*/SneakyThrows(Exception.class)public OptionalBucket getBucket(String bucketName) {return getAllBuckets().stream().filter(b - b.name().equals(bucketName)).findFirst();}/*** 根据bucketName删除Buckettrue删除成功 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 {IterableResultItem results minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for (ResultItem 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 ListItem getAllObjectsByPrefix(String bucketName,String prefix,boolean recursive) {ListItem list new ArrayList();IterableResultItem objectsIterator minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if (objectsIterator ! null) {for (ResultItem 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 IterableResultItem 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);return uploadFile(bucketName, imageName, in);}return null;}public static InputStream base64ToInputStream(String base64) {ByteArrayInputStream stream null;try {byte[] bytes Base64Decoder.decode(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, ListString keys) {ListDeleteObject 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.控制类
import com.unitech.camera.common.model.RestResponse;
import com.unitech.camera.component.oss.MinioConfig;
import com.unitech.camera.component.oss.MinioUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;/*** Author: jiangzhiyuan* Date: 2024/3/5 10:21* Description:*/
Slf4j
RestController
RequestMapping(/oss)
public class OSSController {Autowiredprivate MinioUtils minioUtils;Autowiredprivate MinioConfig minioConfig;/*** 文件上传** param file*/PostMapping(/upload)public Object 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 RestResponse.success();} catch (Exception e) {log.error(上传失败);return RestResponse.error(上传失败);}}/*** 删除** param fileName*/DeleteMapping(/)public Object delete(RequestParam(fileName) String fileName) {minioUtils.removeFile(minioConfig.getBucketName(), fileName);//不需要加桶名称return RestResponse.success();}/*** 获取文件信息** param fileName* return*/GetMapping(/info)public Object getFileStatusInfo(RequestParam(fileName) String fileName) {return RestResponse.success(minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName));}/*** 获取文件外链** param fileName* return*/GetMapping(/url)public Object getPresignedObjectUrl(RequestParam(fileName) String fileName) {return RestResponse.success(minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName));}/*** 文件下载** param fileName* param response*/GetMapping(/download)public Object 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());return RestResponse.success();} catch (Exception e) {return RestResponse.error(下载失败);}}
}5.常见问题
暂无
6.其他参考文章
SpringBoot集成Minio实战详解 springboot整合minio全网最详细的教程