springboot集成minio SDK实现文件上传下载(下)

简介: springboot集成minio SDK实现文件上传下载
  • 上传下载业务实现
// 文件上传
@PostMapping("/image/upload")
String upload(@RequestPart("userImage") MultipartFile userImage) throws Exception {
    fileService.putObject("image", userImage);
    return "success";
}
/**
   * 下载
   *
   * @param fileId
   * @param response
   * @throws Exception
   */
@GetMapping("/download/{fileId}")
public void download(@PathVariable("fileId") String fileId, HttpServletResponse response) throws Exception {
    fileService.getObject(fileId, response);
}
复制代码
  • controller接收到前端上传的文件,马上调用接口fileService的上传接口,把文件上传到minio服务;
import com.example.awesomespring.bo.FileUploadResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
 * @author zouwei
 * @className FileService
 * @date: 2022/8/4 下午3:45
 * @description:
 */
public interface FileService {
  // 上传功能,把文件提交到minio服务,并把提交结果持久化
  FileUploadResult putObject(String dirs, MultipartFile file) throws Exception;
  // 下载功能,把minio服务中的文件下载并写入响应
  void getObject(String fileId, HttpServletResponse response) throws Exception;
}
复制代码
  • 我们来看看具体实现:
import lombok.Data;
/**
* @author zouwei
* @className FileUploadResult
* @date: 2022/8/4 下午11:59
* @description:
*/
@Data
public class FileUploadResult {
    // 文件桶名称
    private String bucketName;
    // 文件存储的路径
    private String filePath;
    // 文件名称
    private String filename;
    // 文件上传类型
    private String contentType;
    // 文件大小
    private int length;
}
复制代码
import com.example.awesomespring.bo.FileUploadResult;
import com.example.awesomespring.config.MinioConfigProperties;
import com.example.awesomespring.dao.entity.FileUploadRecord;
import com.example.awesomespring.dao.mapper.FileUploadRecordMapper;
import com.example.awesomespring.service.FileService;
import io.minio.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.Date;
import java.util.UUID;
/**
 * @author zouwei
 * @className FileServiceImpl
 * @date: 2022/8/4 下午3:45
 * @description:
 */
@Service
public class FileServiceImpl implements FileService {
  @Autowired
  private MinioClient client;
  @Autowired
  private MinioConfigProperties properties;
  @Autowired
  private FileUploadRecordMapper fileUploadRecordMapper;
  /**
   * 上传文件
   *
   * @param dirs 目标文件夹; 比如image、video
   * @param file 上传的文件
   * @return
   * @throws Exception
   */
  @Override
  public FileUploadResult putObject(String dirs, MultipartFile file) throws Exception {
    FileUploadResult result = putObject(dirs, file, true);
    // 保存到数据库
    FileUploadRecord row = new FileUploadRecord();
    row.setFileName(result.getFilename());
    row.setCreateTime(new Date());
    row.setFilePath(result.getFilePath());
    row.setContentType(result.getContentType());
    row.setBucketName(result.getBucketName());
    row.setId(UUID.randomUUID().toString());
    row.setSize(result.getLength());
    fileUploadRecordMapper.insert(row);
    return result;
  }
  /**
   * 下载文件并写入响应中
   *
   * @param fileId
   * @param response
   * @throws Exception
   */
  @Override
  public void getObject(String fileId, HttpServletResponse response) throws Exception {
    FileUploadRecord row = fileUploadRecordMapper.selectByPrimaryKey(fileId);
    String path = row.getFilePath();
    // 构建下载参数
    GetObjectArgs objectArgs = GetObjectArgs.builder()
        .bucket(bucketName())
        .object(path)
        .build();
    // 下载并写入响应中
    try (InputStream input = client.getObject(objectArgs); OutputStream outputStream = response.getOutputStream()) {
      response.setContentType(row.getContentType());
      response.setHeader("Accept-Ranges", "bytes");
      response.setHeader("Content-Length", String.valueOf(length));
      response.setHeader("Content-disposition", "attachment; filename=" + filename);
      outputStream.write(input.readAllBytes());
      outputStream.flush();
    } catch (Exception e) {
      // 建议包装成自定义异常,以便自定义异常处理捕获到
      throw e;
    }
  }
  /**
   * 获取文件桶
   *
   * @return
   */
  private String bucketName() {
    return properties.getBucketName();
  }
  /**
   * 如果文件桶不存在就创建
   *
   * @param bucketName
   * @throws Exception
   */
  private void createIfNotExistBucket(String bucketName) throws Exception {
    if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
      client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }
  }
  /**
   * 这个实现只针对于minio服务实现,所以不建议以接口暴露给外部调用
   *
   * @param dirs
   * @param file
   * @param createIfNotExistBucket
   * @return
   * @throws Exception
   */
  private FileUploadResult putObject(final String dirs, MultipartFile file, boolean createIfNotExistBucket) throws Exception {
    // 获取桶名称
    final String bucketName = bucketName();
    // 获取文件名称
    final String filename = file.getOriginalFilename();
    // 获取文件类型
    final String contentType = file.getContentType();
    // 拼接路径;因为不会把所有文件直接放在桶下面
    String path = filename;
    if (StringUtils.isNotBlank(dirs)) {
      path = Paths.get(dirs, filename).toString();
    }
    // 从上传来的文件中取流
    try (InputStream fileStream = file.getInputStream()) {
      // 如果要求文件桶不存在就创建
      if (createIfNotExistBucket) {
        createIfNotExistBucket(bucketName);
      }
      int length = fileStream.available();
      // 准备好文件上传的参数
      PutObjectArgs objectArgs = PutObjectArgs.builder()
          .bucket(bucketName)
          .object(path)
          .contentType(contentType)
          .stream(fileStream, length, -1)
          .build();
      // 上传文件
      client.putObject(objectArgs);
      // 返回上传结果
      FileUploadResult result = new FileUploadResult();
      result.setContentType(contentType);
      result.setFilePath(dirs);
      result.setFilename(filename);
      result.setBucketName(bucketName);
      result.setLength(length);
      return result;
    } catch (Exception e) {
      // 建议包装成自定义异常,以便自定义异常处理捕获到
      throw e;
    }
  }
}
复制代码
  • 以上代码有几个需要注意的点:

1.文件上传成功到minio服务中后,并不会返回统一的哈希等唯一标识字段,所以我建议我们需要把上传结果保存一条记录到数据库。

2.我们提供给外面的下载链接应该尽可能的简单,比如:http://127.0.0.1/download/{fileId};所以我在设计上传和下载的时候,上传结果用fileId来表示一个文件,下载的时候也只需要使用fileId就可以下载目标文件。

3.在文件上传下载处理过程中,产生的Exception应该全部转换成自定义的异常抛出去,这样的话,可以方便后续的统一异常处理逻辑一次性解决服务端的异常问题。

至此,基于minio对象存储中间件的集成就完成了,小伙伴们可以根据自己的实际情况修改文件存储逻辑的具体实现。


相关文章
|
2月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
1月前
|
前端开发 Java easyexcel
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
118 8
|
27天前
|
消息中间件 监控 Java
您是否已集成 Spring Boot 与 ActiveMQ?
您是否已集成 Spring Boot 与 ActiveMQ?
52 0
|
2月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
3月前
|
前端开发 Java easyexcel
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
50 6
|
3月前
|
存储 前端开发 Java
springboot文件上传和下载接口的简单思路
本文介绍了在Spring Boot中实现文件上传和下载接口的简单思路。文件上传通过`MultipartFile`对象获取前端传递的文件并存储,返回对外访问路径;文件下载通过文件的uuid名称读取文件,并通过流的方式输出,实现文件下载功能。
springboot文件上传和下载接口的简单思路
|
2月前
|
JavaScript 前端开发 Java
Springboot+vue实现文件的下载和上传
这篇文章介绍了如何在Springboot和Vue中实现文件的上传和下载功能,包括后端控制器的创建、前端Vue组件的实现以及所需的依赖配置。
280 0
|
4月前
|
运维 分布式计算 DataWorks
DataWorks产品使用合集之sdk的下载地址在哪里
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
4月前
|
API 网络安全 开发工具
【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)
【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)
|
4月前
|
存储 Java 开发工具
【Azure Developer】VS Code运行Java 版Azure Storage SDK操作Blob (新建Container, 上传Blob文件,下载及清理)
【Azure Developer】VS Code运行Java 版Azure Storage SDK操作Blob (新建Container, 上传Blob文件,下载及清理)

热门文章

最新文章