0


Spring Boot轻松整合Minio实现文件上传下载功能

一、Linux 安装Minio

安装
在/root/xxkfz/soft目录下面创建文件minio文件夹,进入minio文件夹,并创建data目录;

[root@xxkfz soft]# mkdir minio
[root@xxkfz soft]# cd minio
[root@xxkfz minio]# mkdir data

执行如下命令进行下载

[root@xxkfz minio]# wget https://dl.min.io/server/minio/release/linux-amd64/minio
[root@xxkfz minio]# chmod +x minio  # 赋权

下载完成后如下所示:
在这里插入图片描述
设置账号密码
minio 默认账号密码为 minioadmin/minioadmin

[root@xxkfz minio]# export MINIO_ACCESS_KEY=admin # 设置控制台账号(最少3位)
[root@xxkfz minio]# export MINIO_SECRET_KEY=12345678 # 设置密码(最少8位)

直接设置管理员账号密码 编辑 /etc/profile 文件即可

[root@xxkfz minio]# vim /etc/profile

编辑/etc/profile文件,追加如下内容:

# set minio environment
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=admin123

启动

进入执行文件目录/root/xxkfz/soft/minio,自定义端口启动(默认端口:9000)

[root@xxkfz minio]# nohup /root/xxkfz/soft/minio/minio server --address :9001--console-address :9002/root/xxkfz/soft/minio/data>/root/xxkfz/soft/minio/minio.log 2>&1 &

说明:

  • nohup 为后台启动
  • ./minio server 启动命令
  • –address :9001 指定API端口
  • –console-address :9002 指定控制台端口
  • /usr/local/minio/data 指定存储目录
  • /usr/local/minio/minio.log 2>&1 控制台日志重定向
  • 到/usr/local/minio/minio.log文件中
  • & 后台运行

启动成功:
在这里插入图片描述
注意:浏览器访问需要开启防火墙端口!
阿里云配置开放9001、9002端口
在这里插入图片描述

测试访问:http://IP地址:9002
输入账号密码: admin/12345678 登录成功!
在这里插入图片描述

设置开机自启动
设置Minio服务器宕机后自动重启

进入init.d目录

[root@xxkfz minio]# cd /etc/rc.d/init.d

新建minio.sh shell脚本文件

[root@xxkfz init.d]# vim minio.sh 

shell脚本内容

#!/bin/bash#chkconfig: 2345 10 90#description: ping10nohup /root/xxkfz/soft/minio/minio server --address :9001 --console-address :9002 /root/xxkfz/soft/minio/data >/root/xxkfz/soft/minio/minio.log 2>&1&

给shell脚本赋权

chmod +x minio.sh

添加到开机自启动服务中

chkconfig--add minio.sh

设置开机自启动

chkconfig minio.sh on

查看是否添加成功

chkconfig--list

在这里插入图片描述

二、Spring Boot整合Minio

项目搭建
在这里插入图片描述

项目基本结构
引入依赖

pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version></dependency>

配置MinIo

application.yml
minio:endpoint: http://IP地址:9001accessKey: admin
  secretKey:12345678bucketName: xk-admin

配置端口号

server:port:8099

编写配置类

MinioConfig.java
/**
 * @program: xxkfz-minio
 * @ClassName MinioConfig.java
 * @author: 公众号:小小开发者
 * @create: 2024-03-13 10:53
 * @description: Minio 配置类
 **/@Data@ConfigurationpublicclassMinioConfig{/**
     * 访问地址
     */@Value("${minio.endpoint}")privateString endpoint;/**
     * accessKey类似于用户ID,用于唯一标识你的账户
     */@Value("${minio.accessKey}")privateString accessKey;/**
     * secretKey是你账户的密码
     */@Value("${minio.secretKey}")privateString secretKey;/**
     * 默认存储桶
     */@Value("${minio.bucketName}")privateString bucketName;@BeanpublicMinioClientminioClient(){MinioClient minioClient =MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();return minioClient;}}

编写Minio操作工具类

MinioUtils.java
/**
 * @program: xxkfz-minio
 * @ClassName MinioUtils.java
 * @author: 公众号:小小开发者
 * @create: 2024-03-13 10:55
 * @description: MinIO操作工具类
 **/@Slf4j@ComponentpublicclassMinioUtils{@AutowiredprivateMinioClient minioClient;/**
     * 启动SpringBoot容器的时候初始化Bucket
     * 如果没有Bucket则创建
     *
     * @param bucketName
     */publicvoidcreateBucket(String bucketName){try{if(!bucketExists(bucketName)){
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                log.info("创建bucketName = {}完成!", bucketName);return;}
            log.info("bucketName = {}已存在!策略为:{}", bucketName,getBucketPolicy(bucketName));}catch(Exception e){
            log.error("创建bucketName = {}异常!e = {}", bucketName, e);}}/**
     * 判断Bucket是否存在,true:存在,false:不存在
     *
     * @param bucketName
     * @return
     */@SneakyThrowspublicbooleanbucketExists(String bucketName){return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/**
     * 获得Bucket的策略
     *
     * @param bucketName
     * @return
     */@SneakyThrowspublicStringgetBucketPolicy(String bucketName){return minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());}/**
     * 获得所有Bucket列表
     *
     * @return
     */@SneakyThrowspublicList<Bucket>getAllBuckets(){return minioClient.listBuckets();}/**
     * 根据bucketName获取其相关信息
     *
     * @param bucketName
     * @return
     */@SneakyThrows(Exception.class)publicOptional<Bucket>getBucket(String bucketName){returngetAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/**
     * 根据bucketName删除Bucket,true:删除成功; false:删除失败,文件或已不存在
     *
     * @param bucketName
     * @throws Exception
     */@SneakyThrows(Exception.class)publicvoidremoveBucket(String bucketName){
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/**
     * 判断文件是否存在
     *
     * @param bucketName
     * @param objectName
     * @return
     */publicbooleanisObjectExist(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
     */publicbooleanisFolderExist(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)publicList<Item>getAllObjectsByPrefix(String bucketName,String prefix,boolean recursive){List<Item> list =newArrayList<>();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)publicInputStreamgetObject(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)publicInputStreamgetObject(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 二进制流
     */publicIterable<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)publicObjectWriteResponseuploadFile(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
     */publicObjectWriteResponseuploadImage(String bucketName,String imageBase64,String imageName){if(!StringUtils.isEmpty(imageBase64)){InputStream in =base64ToInputStream(imageBase64);String newName =System.currentTimeMillis()+"_"+ imageName +".jpg";String year =String.valueOf(newDate().getYear());String month =String.valueOf(newDate().getMonth());returnuploadFile(bucketName, year +"/"+ month +"/"+ newName, in);}returnnull;}publicstaticInputStreambase64ToInputStream(String base64){ByteArrayInputStream stream =null;try{byte[] bytes =Base64.getEncoder().encode(base64.trim().getBytes());
            stream =newByteArrayInputStream(bytes);}catch(Exception e){
            e.printStackTrace();}return stream;}/**
     * 上传本地文件
     *
     * @param bucketName 存储桶
     * @param objectName 对象名称
     * @param fileName   本地文件路径
     * @return
     */@SneakyThrows(Exception.class)publicObjectWriteResponseuploadFile(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)publicObjectWriteResponseuploadFile(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)publicObjectWriteResponsecreateDir(String bucketName,String objectName){return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(newByteArrayInputStream(newbyte[]{}),0,-1).build());}/**
     * 获取文件信息, 如果抛出异常则说明文件不存在
     *
     * @param bucketName 存储桶
     * @param objectName 文件名称
     * @return
     */@SneakyThrows(Exception.class)publicStringgetFileStatusInfo(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)publicObjectWriteResponsecopyFile(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)publicvoidremoveFile(String bucketName,String objectName){
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}/**
     * 批量删除文件
     *
     * @param bucketName 存储桶
     * @param keys       需要删除的文件列表
     * @return
     */publicvoidremoveFiles(String bucketName,List<String> keys){List<DeleteObject> objects =newLinkedList<>();
        keys.forEach(s ->{
            objects.add(newDeleteObject(s));try{removeFile(bucketName, s);}catch(Exception e){
                log.error("[Minio工具类]>>>> 批量删除文件,异常:", e);}});}/**
     * 获取文件外链
     *
     * @param bucketName 存储桶
     * @param objectName 文件名
     * @param expires    过期时间 <=7 秒 (外链有效时间(单位:秒))
     * @return url
     */@SneakyThrows(Exception.class)publicStringgetPresignedObjectUrl(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)publicStringgetPresignedObjectUrl(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
     */publicStringgetUtf8ByURLDecoder(String str)throwsUnsupportedEncodingException{String url = str.replaceAll("%(?![0-9a-fA-F]{2})","%25");returnURLDecoder.decode(url,"UTF-8");}}

项目启动初始化配置

创建配置类InitConfig.java,并实现了InitializingBean接口,重写afterPropertiesSet方法。

该方法主要实现逻辑:在项目启动的时候初始化Bucket,如果没有则进行创建!

InitConfig.java
/**
 * @program: xxkfz-minio
 * @ClassName Init.java
 * @author: wust
 * @create: 2024-03-16 10:34
 * @description: 项目启动初始化配置
 **/@Component@Slf4jpublicclassInitConfigimplementsInitializingBean{@AutowiredprivateMinioUtils minioUtils;@AutowiredprivateMinioConfig minioConfig;@OverridepublicvoidafterPropertiesSet()throwsException{// 项目启动创建Bucket,不存在则进行创建
        minioUtils.createBucket(minioConfig.getBucketName());}}

编写测试接口

MinioController.java
/**
 * @program: xxkfz-minio
 * @ClassName OSSController.java
 * @author: wust
 * @create: 2024-03-13 11:01
 * @description:
 **/@Slf4j@RestController@RequestMapping("/oss")publicclassMinioController{@AutowiredprivateMinioUtils minioUtils;@AutowiredprivateMinioConfig minioConfig;/**
     * 文件上传
     *
     * @param file
     */@PostMapping("/upload")publicStringupload(@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"上传成功,文件名:"+ newFileName;}catch(Exception e){
            e.printStackTrace();return"上传失败";}}/**
     * 删除
     *
     * @param fileName
     */@DeleteMapping("/")publicvoiddelete(@RequestParam("fileName")String fileName){
        minioUtils.removeFile(minioConfig.getBucketName(), fileName);}/**
     * 获取文件信息
     *
     * @param fileName
     * @return
     */@GetMapping("/info")publicStringgetFileStatusInfo(@RequestParam("fileName")String fileName){return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);}/**
     * 获取文件外链
     *
     * @param fileName
     * @return
     */@GetMapping("/url")publicStringgetPresignedObjectUrl(@RequestParam("fileName")String fileName){return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);}/**
     * 文件下载
     *
     * @param fileName
     * @param response
     */@GetMapping("/download")publicvoiddownload(@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("下载失败");}}}

测试验证
启动项目:
在这里插入图片描述

上传图片

测试接口:http://localhost:8099/oss/upload

在这里插入图片描述

进入服务器查看文件上传情况。

进入目录:/root/xxkfz/soft/minio/data/xk-admin

在这里插入图片描述

当然,也可以直接访问minio的地址:http://IP地址:9001/xk-admin/1710558001536.jpg。验证文件是否上传成功。

在这里插入图片描述

获取文件信息

测试接口:http://localhost:8099/oss/info

在这里插入图片描述

获取文件外链

测试接口:http://localhost:8099/oss/url

在这里插入图片描述

下载文件

测试接口:http://localhost:8099/oss/download

在这里插入图片描述


本文转载自: https://blog.csdn.net/love7489/article/details/139761111
版权归原作者 断春风 所有, 如有侵权,请联系我们删除。

“Spring Boot轻松整合Minio实现文件上传下载功能”的评论:

还没有评论