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


相关文章
|
5月前
|
物联网 Linux 开发者
快速部署自己私有MQTT-Broker-下载安装到运行不到一分钟,快速简单且易于集成到自己项目中
本文给物联网开发的朋友推荐的是GMQT,让物联网开发者快速拥有合适自己的MQTT-Broker,本文从下载程序到安装部署手把手教大家安装用上私有化MQTT服务器。
1412 5
|
10月前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
647 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
6月前
|
存储 Java API
MinIO Java SDK 7.1.4 升级到 8.5.17 需要注意什么
现在我需要你帮我分析对比这个两个sdk在对外的接口设计上是否有不兼容的变更
489 5
|
XML Java API
SpringBoot 整合 Minio
本文介绍了如何在服务器上安装并配置Minio服务,包括Minio的依赖、配置类以及基本操作。首先,通过Maven添加Minio依赖;接着,在`yml`文件中配置Minio的连接信息;然后,创建`MinIoClientConfig`类将MinioClient注入到Spring容器中;最后,定义`OSSFileService`接口及其实现类`OssFileServiceImpl`,实现文件上传、获取文件URL、临时访问URL和删除文件等操作。
370 2
|
8月前
|
Java 开发工具 Spring
【Azure Application Insights】为Spring Boot应用集成Application Insight SDK
本文以Java Spring Boot项目为例,详细说明如何集成Azure Application Insights SDK以收集和展示日志。内容包括三步配置:1) 在`pom.xml`中添加依赖项`applicationinsights-runtime-attach`和`applicationinsights-core`;2) 在main函数中调用`ApplicationInsights.attach()`;3) 配置`applicationinsights.json`文件。同时提供问题排查建议及自定义日志方法示例,帮助用户顺利集成并使用Application Insights服务。
229 8
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
11月前
|
存储 Java 文件存储
Spring Boot 3 整合 Minio 实现文件存储
本文介绍了如何使用 Spring Boot 3 整合 MinIO 实现文件存储服务。MinIO 是一款高性能的对象存储服务器,适合大规模数据存储与分析,支持多种部署环境且文档完备、开源免费。从 MinIO 的快速安装、配置文件公开访问,到 Spring Boot 中集成 MinIO 客户端的步骤,包括创建用户访问密钥、引入依赖包、添加配置信息、编写 MinIO 客户端配置类及上传和预览文件的服务代码。最后通过 Apifox 进行文件上传测试,并验证文件是否成功存储及预览功能是否正常。关注公众号“Harry技术”,回复 minio 获取源码地址。
821 76
|
9月前
|
存储 Java 文件存储
🗄️Spring Boot 3 整合 MinIO 实现分布式文件存储
本文介绍了如何基于Spring Boot 3和MinIO实现分布式文件存储。随着应用规模扩大,传统的单机文件存储方案难以应对大规模数据和高并发访问,分布式文件存储系统成为更好的选择。文章详细讲解了MinIO的安装、配置及与Spring Boot的整合步骤,包括Docker部署、MinIO控制台操作、Spring Boot项目中的依赖引入、配置类编写及工具类封装等内容。最后通过一个上传头像的接口示例展示了具体的开发和测试过程,强调了将API操作封装成通用工具类以提高代码复用性和可维护性的重要性。
1957 7
🗄️Spring Boot 3 整合 MinIO 实现分布式文件存储
|
7月前
|
存储 Java Linux
SpringBoot × MinIO 极速开发指南:对象存储服务高可用实战
生成临时访问URL接口和文件预览其实是同一个方法,只是文件预览内定了七天访问,而这个方法可以自行制定,单位是秒。方法,所以返回的是地址信息,但是可以通过dubug看到Bucket中的属性,确实是当前所有桶信息。配置类中奖MinIOClient客户端注入到Springboot中。MinIO集群的在Linux上的部署可以参考:​​​​​​​。Nginx代理MinIO集群可以参考:​​​​​​​。从Bucket源码可以看出,并没有实现。
717 0
|
9月前
|
存储 XML 开发工具
【Azure Storage Account】利用App Service作为反向代理, 并使用.NET Storage Account SDK实现上传/下载操作
本文介绍了如何在Azure上使用App Service作为反向代理,以自定义域名访问Storage Account。主要内容包括: 1. **设置反向代理**:通过配置`applicationhost.xdt`和`web.config`文件,启用IIS代理功能并设置重写规则。 2. **验证访问**:测试原生URL和自定义域名的访问效果,确保两者均可正常访问Storage Account。 3. **.NET SDK连接**:使用共享访问签名(SAS URL)初始化BlobServiceClient对象,实现通过自定义域名访问存储服务。
152 1