Springboot+Minio实现上传下载预览删除文件操作

首先我们先需要在服务器上搭建minio,目前我是在linux用docker搭建的minio服务:

搭建minio服务:

1. 拉取镜像,下载指定版本的minio

docker pull minio/minio:RELEASE.2021-04-06T23-11-00Z 

2.  指定镜像版本创建minio容器并运行

docker run -p 4007:9000 --name  minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio111" -v /minio/data:/data -v /minio/config:/root/.minio minio/minio:RELEASE.2021-04-06T23-11-00Z server /data

 命令行翻译:

-p 4007:9000 ,端口映射
-e,环境变量
-d,后台运行
–name,给容器起名字
–restart=always,开机自启
-e “MINIO_ACCESS_KEY=minio”,设置账号
-e “MINIO_SECRET_KEY=minio123”,设置密码
-v 挂载数据卷

 我自己设置成了4007的端口

3. 测试访问minio后台登录系统,直接访问服务器IP:4007(刚设置的端口即可),进行登录

管理页面:正常一进来是没有buket桶的  需要自行点击右下角的加号创建

输入桶的名称创建桶

刚刚创建的桶test,以及右侧框住的桶结构

4. SpringBoot整合minio

       导入相关依赖

<dependencies>
    <!--minio-->
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>7.1.0</version>
    </dependency>
    <!--web-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--test-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <!--knife4j(swagger) -->
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>3.0.2</version>
    </dependency>
    <!--lombok-->
     <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

编写minio属性配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.Serializable;

@Data
@Component
@ConfigurationProperties(prefix = "minio")  //自动注入属性前缀为minio的配置
public class MinIOConfigProperties implements Serializable {
    private String accessKey; // 访问key
    private String secretKey; // 秘钥
    private String bucket;    // 桶
    private String endpoint;  // 地域节点
    private String readPath;  // 读取路径
}

编写MinIO配置类,注册MinioClient客户端的Bean对象


import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MinIO配置类
 *
 * @author 白豆五
 * @version 2023/04/21
 * @since JDK8
 */
@Configuration
public class MinIOConfig {

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    // 注册MinIO实例
    @Bean
    public MinioClient buildMinioClient(){
        return MinioClient
                .builder()
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .endpoint(minIOConfigProperties.getEndpoint())
                .build();
    }
}

在application.yml文件中配置minio自定义属性和文件上传大小

minio:
  accessKey: minio
  secretKey: minio123
  bucket: testminio
  endpoint: http://192.168.200.128:9000
  readPath: http://192.168.200.128:9000
  
  servlet:
    multipart:
      # 单个上传文件的最大值是200mb
      max-file-size: 200MB
      # 单次请求的最大值
      max-request-size: 200MB

编写操作minio相关业务接口

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;

/**
 * 操作minio相关业务接口
 *
 * @author Jx
 * @version 2023-11-14
 * @since JDK8
 */
public interface IFileStorageService{

    /**
     * 上传文件
     *
     * @param prefix      文件前缀
     * @param filename    文件名
     * @param inputStream 文件流
     * @return 文件全路径
     */
    public String uploadFile(String prefix, String filename, InputStream inputStream);

    /**
     * 删除文件
     *
     * @param pathUrl 文件全路径
     */
    public void delete(String pathUrl);

    /**
     * 下载文件
     *
     * @param pathUrl 文件全路径
     * @return
     */
    public void downLoad(HttpServletResponse response, String pathUrl);


    /**
     * 在线预览文件
     * @param filePath
     * @return
     */
    public String getPreviewUrl(String filePath);

}

业务接口实现类:


import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.geb.common.config.MinIOConfigProperties;
import com.geb.system.service.IFileStorageService;
import io.minio.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
@Service
public class MinIOFileStorageServiceImpl implements IFileStorageService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    private final static String separator = "/"; //文件夹分隔符

    private final static String endPointUrl = "http://219.159.22.22:4007";
    private final static String endPointUrl1 = "http://minio:9000";

    /**
     * 构建文件的绝对路径 -- 按需构建  如无需则可省略此步骤
     *
     * @param dirPath  文件路径
     * @param filename 文件名  yyyy/mm/dd/file.jpg
     * @return /test
     */
    public String builderFilePath(String dirPath, String filename) {
        StringBuilder stringBuilder = new StringBuilder(50);
        if (!StringUtils.isEmpty(dirPath)) {
            stringBuilder.append(dirPath).append(separator);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String todayStr = sdf.format(new Date());
        stringBuilder.append(todayStr).append(separator);
        stringBuilder.append(filename);
        return stringBuilder.toString();
    }


    /**
     * 上传文件
     *
     * @param prefix      文件前缀
     * @param filename    文件名
     * @param inputStream 文件流
     * @return 文件全路径
     */
    @Override
    public String uploadFile(String prefix, String filename, InputStream inputStream) {
        String filePath = builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath) //文件名
                    .contentType("text/json")//文件类型
                    .bucket(minIOConfigProperties.getBucket())//桶名称与minio创建的桶一致
                    .stream(inputStream, inputStream.available(), -1)//文件流
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator + minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString(); //文件全路径
        } catch (Exception ex) {
            log.error("minio put file error.", ex);
            ex.printStackTrace();
            throw new RuntimeException("上传文件失败");
        }
    }

    /**
     * 删除文件 -- 能获取到根节点endpoint即可  如果可直接获取到则可无需重新构建根节点endpoint
     *
     * @param pathUrl 文件全路径
     */
    @Override
    public void delete(String pathUrl) {
        /** 获取桶后面的删除路径 */
        String delUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());

        /** 重新构建根节点endpoint */
        minioClient = MinioClient.builder()
                .endpoint(endPointUrl1)
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .build();

        /** 删除文件 */
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs
                .builder()
                .bucket(minIOConfigProperties.getBucket())
                .object(separator + delUrl).build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            log.error("minio remove file error.  pathUrl:{}", pathUrl);
            e.printStackTrace();

        }
    }


    /**
     * 下载文件 -- 走浏览器下载
     *
     * @param pathUrl 文件全路径
     * @return 文件流 byte[]
     */
    @Override
    public void downLoad(HttpServletResponse response, String pathUrl) {/** 拼接完整的下载路径 pathUrl+minio */
        /** 获取文件名称 */
        String fileName = pathUrl.substring(pathUrl.lastIndexOf("/") + 1, pathUrl.length()) + ".json";
        /** 获取桶后面的下载路径 */
        String downUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());

        /** 获取本地文件默认下载路径 */
        InputStream inputStream = null;
        try {
            /** 重新构建根节点endpoint */
            minioClient = MinioClient.builder()
                    .endpoint(endPointUrl1)
                    .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                    .build();

            inputStream = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(minIOConfigProperties.getBucket())
                    .object(downUrl).build());

            /*** text/json */
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setCharacterEncoding("UTF-8");

            /*** 用文件流的方式读取到下载文件中 */
            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            log.error("minio down file error.  pathUrl:{}", pathUrl);
            e.printStackTrace();
        }
    }



    /**
     * 在线预览文件
     * @param pathUrl
     * @return
     */
    @Override
    @SneakyThrows(Exception.class)
    public String getPreviewUrl(String pathUrl) {
        /** 获取文件名称 */
        String fileName = pathUrl.substring(pathUrl.lastIndexOf("/") + 1, pathUrl.length());
        /** 获取桶后面的下载路径 */
        String downUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());
        /** 重新构建根节点endpoint */
        minioClient = MinioClient.builder()
                .endpoint(endPointUrl)
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .build();

        /** 获取预览的路径 */
        String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(minIOConfigProperties.getBucket())
                        .object(downUrl)
                        .build());
        System.out.println("previewUrl===" + url);
        return url;
    }




}

编写controller

package com.baidou.controller;

import com.baidou.dto.Result;
import com.baidou.service.FileStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 操作minio的控制器类
 *
 * @author 白豆五
 * @version 2023/04/21
 * @since JDK8
 */
@RestController
@RequestMapping("/minio")
@Api(tags = "minio相关接口")
public class MinioController {

    @Autowired
    private FileStorageService fileStorageService;


    /**
     * 上传图片到minio
     *
     * @param file
     * @return
     */
    @PostMapping("upload")
    @ApiOperation(value = "图片上传接口")
    public Result uploadFile(MultipartFile file) throws IOException {
        try {
            // 获取文件名称
            String fileName = file.getOriginalFilename();
            /*解决多次上传同名文件覆盖问题*/
            // 在文件名称里面添加随机唯一的值
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            fileName = uuid + fileName;
            // 获取文件输入流
            InputStream is = file.getInputStream();
            String imgUrl = fileStorageService.uploadImgFile("img", fileName, is);
            return Result.success(imgUrl, "上传成功");
        } catch (IOException e) {
            e.printStackTrace();
            return Result.error("上传失败");
        }
    }
}

启动项目,然后用postman测试

如果想上传其它格式的文件,可以在上传接口更换文件格式,由于我自己做的上传是通过读取数据库表数据进行prompt格式转换后的输入流,下面把Controller以及实现类的代码po出来

Controller如下:

 /**
     * 新增数据格式转换
     */
    @Log(title = "数据格式转换-创建转换记录", businessType = BusinessType.INSERT)
    @ApiOperation(value = "创建转换记录(上传文件数据)")
    @PostMapping("/save")
    public R<String> save(@Validated @RequestBody AddDataFormatConversionDto addDataFormatConversionDto) {
        /** 获取数据表的字段列名称 */
        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(addDataFormatConversionDto.getDataId());
        List<String> columnList = new ArrayList<>();
        for (GenTableColumn genTableColum : list) {
            columnList.add(genTableColum.getColumnName());
        }
        String filePath = dataFormatConversionService.insertDataFormatConversion(addDataFormatConversionDto, columnList, getUsername(), getUserId());
        return R.ok(filePath);
    }

serviceImpl层代码:

/** 区分不同文件名称 */
        String fileName = "fine_tune_data_" + dataFormatConversion.getId() + ".json";
        byte[] bytes = dataContent.toString().getBytes();
        InputStream inputStream = new ByteArrayInputStream(bytes);
        String filePath = uploadFile("json", fileName, inputStream, dataFormatConversion.getId());
/**
     * 上传文件
     *
     * @param prefix      文件前缀
     * @param filename    文件名
     * @param inputStream 文件流
     * @return 文件全路径
     */
    public String uploadFile(String prefix, String filename, InputStream inputStream, Long id) {

        String filePath = JsonUtil.builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath) //文件名
                    .contentType("text/json")//文件类型
                    .bucket(minIOConfigProperties.getBucket())//桶名称与minio创建的桶一致
                    .stream(inputStream, inputStream.available(), -1)//文件流
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator + minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString(); //文件全路径
        } catch (Exception ex) {
            DataFormatConversion updateDfa = new DataFormatConversion();
            updateDfa.setId(id);
            updateDfa.setTransisionStatus(3L); // 设置数据格式转换失败状态
            dataFormatConversionMapper.updateById(updateDfa);
            log.error("minio put file error. && 文件格式转换失败", ex);
            ex.printStackTrace();
            throw new RuntimeException("上传文件失败");
        }
    }

共用的上传,预览,下载,删除文件接口都在minio serviceImpl实现类中,可自行使用,感谢阅读,有不足欢迎补充~希望跟大家多多交流!

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Spring BootMinio的大文件上传并解压的功能,可以按照以下步骤进行操作: 1. 首先,在Spring Boot项目的pom.xml文件中引入Minio的依赖。可以使用以下代码将Minio的依赖添加到项目中: ``` <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.2.1</version> </dependency> ``` 2. 然后,将大文件分片并上传到Minio对象存储服务。可以按照以下步骤进行操作: - 将要上传的大文件进行分片处理,可以使用文件分片算法将大文件分成多个小块。 - 将分片后的文件依次上传到Minio对象存储服务,并指定一个临时文件名。 3. 分片上传完成后,将所有分片合并为一个完整的文件。可以按照以下步骤进行操作: - 从Minio中读取所有分片文件的流。 - 将分片流写入到一个临时文件中,以便后续解压。 4. 解压临时文件。可以按照以下步骤进行操作: - 使用合适的解压库或工具,对临时文件进行解压。 - 解压后的文件可以按需求进行进一步处理,例如再次上传到Minio或其他存储系统。 综上所述,要实现Spring BootMinio的大文件上传并解压功能,需要将文件分片并上传到Minio,然后将分片合并为完整文件,最后解压文件。这样可以实现文件的上传和解压操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring boot + minio 分片上传](https://blog.csdn.net/XIAOTONGZHU/article/details/130346735)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [SpringBoot 使用 Minio 进行文件存储](https://blog.csdn.net/qq_43692950/article/details/125961685)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Windows常用软件压缩包,后端Java适用于springboot 2.6.x等高版本](https://download.csdn.net/download/m0_55710969/85062866)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值