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对象存储中间件的集成就完成了,小伙伴们可以根据自己的实际情况修改文件存储逻辑的具体实现。


相关文章
|
1月前
|
Java 数据库连接 mybatis
springboot访问jsp页面变成直接下载?
springboot访问jsp页面变成直接下载?
39 0
|
2月前
|
Java 开发工具 Maven
springboot项目打包为sdk供其他项目引用
springboot项目打包为sdk供其他项目引用
|
2月前
|
Java API 开发工具
支付与银行业线上客户协议应用中的DocuSign集成方式选择——SDK和API
跨境支付公司和Docusign进行集成时,碰到问题时的解决方案。分别用SDK和API集成后的各自使用体验。
46 2
支付与银行业线上客户协议应用中的DocuSign集成方式选择——SDK和API
|
2月前
|
JavaScript 前端开发 Java
springboot整合minio+vue实现大文件分片上传,断点续传(复制可用,包含minio工具类)
springboot整合minio+vue实现大文件分片上传,断点续传(复制可用,包含minio工具类)
449 0
|
3月前
|
存储 Java 对象存储
springboot配置阿里云OSS存储实现文件上传下载功能
【1月更文挑战第1天】springboot配置阿里云OSS存储实现文件上传下载功能
579 2
|
2月前
|
Web App开发 前端开发 JavaScript
如何快速与呼叫中心系统CTI/API/SDK接口集成
由于呼叫中心系统涉及通信、CTI、终端设备、中继线路等技术与概念,从事信息管理系统、ERP、CRM、工单系统等的研发人员一般不是非常熟悉这部分技术,当需要提供具备呼叫中心能力的解决方案时,往往要用较多的时间来研究这些相对复杂的技术,对接过程比较长,开发调试有一定的阻力,基于此,我们提出一种更加简便高效的集成方法,可以零代码集成呼叫中心平台,实现项目快速上线。
如何快速与呼叫中心系统CTI/API/SDK接口集成
|
2月前
|
对象存储
阿里云oss-cloud-sdk-springboot3兼容问题
阿里云oss-cloud-sdk-springboot3兼容问题
76 0
|
3月前
|
存储 Java 大数据
Springboot整合Minio实现文件上传和下载
Minio是一个灵活、高性能、开源的对象存储解决方案,适用于各种存储需求,并可以与云计算、容器化、大数据和应用程序集成。它为用户提供了自主控制和可扩展性,使其成为一个强大的存储解决方案。
230 0
|
3月前
|
JavaScript 小程序 Java
基于Java+SpringBoot+Vue的摄影素材分享网站的设计与实现(亮点:活动报名、点赞评论、图片下载、视频下载、在线观看)
基于Java+SpringBoot+Vue的摄影素材分享网站的设计与实现(亮点:活动报名、点赞评论、图片下载、视频下载、在线观看)
51 0
|
4月前
|
Java Linux 开发工具
MinIO【部署 01】MinIO安装及SpringBoot集成简单测试
MinIO【部署 01】MinIO安装及SpringBoot集成简单测试
124 0