SpringBoot:整合 Minio 文件上传操作

news2024/11/16 20:50:27

简介

  • 对象存储服务OSS(Object Storage Service)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本,今天我这里主要讲解SpringBoot如何集成MinIO。

引入依赖

<!--minio-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.0.3</version>
        </dependency> 

yml文件配置

spring:
  # 配置文件上传大小限制
  servlet:
    multipart:
      max-file-size: 200MB
      max-request-size: 200MB
minio:
  endpoint: http://127.0.0.1:9000
  accessKey: minioadmin
  secretKey: minioadmin
  bucketName: test 

编写配置类

@Data
@Component
public class MinIoClientConfig {
    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;
 
    /**
     * 注入minio 客户端
     * @return
     */
    @Bean
    public MinioClient minioClient(){
 
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
 
} 

编写工具类

@Data
public class ObjectItem {
    private String objectName;
    private Long size;
}

/**
 * @description:
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class MinioUtil {
    final MinIoClientConfig prop;

    final MinioClient minioClient;

    /**
     * 查看存储bucket是否存在
     * @return boolean
     */
    public Boolean bucketExists(String bucketName) {
        Boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    /**
     * 创建存储bucket
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 删除存储bucket
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 获取全部bucket
     */
    public List<Bucket> getAllBuckets() {
        try {
            List<Bucket> buckets = minioClient.listBuckets();
            return buckets;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件上传
     *
     * @param file 文件
     * @return Boolean
     */
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)){
            throw new RuntimeException();
        }
        String fileName = UuidUtils.generateUuid() + originalFilename.substring(originalFilename.lastIndexOf("."));
        String objectName = DateUtils.getDayStr() + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectName;
    }

    /**
     * 预览
     * @param fileName
     * @return
     */
    public String preview(String fileName){
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(prop.getBucketName()).object(fileName).method(Method.GET).build();
        try {
            String url = minioClient.getPresignedObjectUrl(build);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件下载
     * @param fileName 文件名称
     * @param res response
     * @return Boolean
     */
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(prop.getBucketName())
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)){
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
                while ((len=response.read(buf))!=-1){
                    os.write(buf,0,len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件对象
     * @return 存储bucket内文件对象信息
     */
    public List<Item> listObjects() {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(prop.getBucketName()).build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }

    /**
     * 删除
     * @param fileName
     * @return
     * @throws Exception
     */
    public boolean remove(String fileName){
        try {
            minioClient.removeObject( RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());
        }catch (Exception e){
            return false;
        }
        return true;
    }
} 

编写控制器

@RestController
@RequestMapping("/minio")
@Api(tags = "minio测试")
@RequiredArgsConstructor
@Slf4j
public class MinioController {
    @Autowired
    private MinIoUtil minIoUtil;
    @Autowired
    private MinioUtilS minioUtilS;
    @Value("${minio.endpoint}")
    private String address;
    @Value("${minio.bucketName}")
    private String bucketName;
 
    @PostMapping("/upload")
    public Object upload(MultipartFile file) {
        
        List<String> upload = minioUtilS.upload(new MultipartFile[]{file});
 
        return address+"/"+bucketName+"/"+upload.get(0);
    }
 
} 

总结

  • springboot 集成 minio 非常简单,通过封装 minioclient,可增加代码的灵活性可扩展性,隔离底层存储接口,后续入要更换其他的存储,经过简单的适配即可实现,通过REST提供存储的基础能力接口,可非常简单的被使用。

声明

  • 原文链接:https://www.jianshu.com/p/6de1acde167d

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/700657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ 面向对象程序设计 14万字总结笔记

文章的索引都在目录处可以找到 学好C可以采取以下几个步骤&#xff1a; 掌握基本语法&#xff1a;C的语法对于初学者来说可能是一件比较难的事情&#xff0c;所以需要花时间掌握C的语言基础和语法规则&#xff0c;例如数据类型、流程控制、函数等。 学会面向对象编程(OOP)&a…

6.28 内存分配/管理 学习总结

一、通过程序验证系统内存分配机制 1、实验&#xff1a; 两个char 指针&#xff0c;连续先后在内存中各申请100、102个字节&#xff0c; 它们实际上会占用多少字节的内存空间&#xff1f; 如果两个char 指针&#xff0c;连续先后在内存中各申请200个字节&#xff0c; 它们实…

青大数据结构【2017】【综合应用、算法分析】

关键字&#xff1a; 平衡二叉树、平均查找长度、单链表、二叉树中序遍历非递归 三、综合应用 平衡二叉树AVL定义&#xff1a;任意节点的子树的高度差都小于等于 1 ASL&#xff08;12*24*3&#xff09;/717/7 四、算法分析

APA 参考页格式 | 第六版指南

参考页&#xff1a;文章最后列出所有的参考文献的页面。引用&#xff1a;指在文章正文中进行引用。 APA 参考页是论文末尾的一个单独页面&#xff0c;其中列出了您在正文中引用的所有来源。参考文献按字母顺序排序&#xff0c;双倍行距&#xff0c;并使用1/2 英寸的悬挂缩进进行…

接口自动化测试中,文件上传该如何测试?

在服务端自动化测试过程中&#xff0c;文件上传类型的接口对应的请求头中的 content-type 为 multipart/form-data; boundary...&#xff0c;碰到这种类型的接口&#xff0c;使用 Java 的 REST Assured 或者 Python 的 Requests 均可解决。 实战练习 Python 版本 在 Python …

初识Go语言24-数据结构与算法【链表、栈】

文章目录 数据结构与算法链表栈 数据结构与算法 链表 ---手写单链表 type Node struct {Info intNext *Node }type List struct {Head *NodeLen intTail *Node }func (list *List) Add(ele int) {node : &Node{Info: ele, Next: nil}if list.Len 0 {list.Head nodelist…

基于WebSocket的简易聊天室的基本实现梳理

一&#xff0c;前言 目前在很多网站为了实现推送技术所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔&#xff08;如每1秒&#xff09;&#xff0c;由浏览器对服务器发出HTTP请求&#xff0c;然后由服务器返回最新的数据给客户端的浏览器。HTTP 协议是一种无状态的、无连…

轨道交通车体自动化检修测量大尺寸测量仪器-CASAIM激光三维扫描仪

现今我国轨道交通高速发展&#xff0c;重大装备技术的进步离不开先进的大尺寸测量手段支持&#xff0c;CASAIM大尺寸测量在测量环境、测量精度和测量效率上明显区别于常规尺寸测量&#xff0c;可以快速检测车体表面的尺寸变形等问题&#xff0c;实现高精度、高效率的自动化车体…

(质数)牛客·Prime Distance

非质数的一个性质&#xff1a; 必定有一个因子大于它的算术平方根。 该性质有范围限制&#xff0c;一般情况下都可以使用。以后数学家们再扩张。碰到质数的一般做法&#xff1a;假定范围为[1,n] 1、预处理1-√n的质数&#xff0c;存入数组p中 2、对于[1-n]里的数&#xff0c;用…

git常用命令之Push

9. Push 命令作用延展阅读git push --set-upstream origin releasegit push -u origin release 为缩写版本1. .git/config配置文件会追加如下关联关系&#xff0c;[branch “release”] remote origin merge refs/heads/release故后续可以直接执行git push2. .git\refs\remo…

VueCli的Nuxt重构

我的博客用vuecli写的&#xff0c;SEO不忍直视。于是用Nuxt重构了代码&#xff0c;过程中踩了无数坑 一&#xff1a;body样式不生效 正常的body样式设置不能生效&#xff0c;需要在nuxt.config.js中配置 1、设置bodyAttrs的class属性&#xff0c;该属性值对应一个类名 2、该…

【Java面试题】Java基础——查找算法

文章目录 基本查找二分查找★★★插值查找斐波那契查找分块查找 基本查找 基本查找也叫做顺序查找 ​ 说明&#xff1a;顺序查找适合于存储结构为数组或者链表。 基本思想&#xff1a;顺序查找也称为线形查找&#xff0c;属于无序查找算法。从数据结构线的一端开始&#xff…

IP地址定位查询技术,不管对方在哪,轻轻松松查到他的位置

这是外面在卖588的抓ip技术&#xff0c;真的很简单&#xff0c;卖此技术的人帮人查一次都能赚几十&#xff0c;每天都能出个两三单 玩法&#xff1a;可以生成链接、邮件、图片、pdf的形式&#xff0c;发送给对方的微信或者QQ等地方&#xff0c;只要对方点击后&#xff0c;立马…

知易行难!项目推进的6大常见问题

项目推进是一项企业发展业务中的关键任务。然而&#xff0c;许多项目在实施过程中遇到各种困难和挑战&#xff0c;导致项目无法按计划进行或无法实现预期的成果。以下是项目推进过程中常见的六个问题以及解决方案。1、项目目标不明确 项目推进时&#xff0c;如果项目团队不清楚…

Material —— 材质节点 | Utility

目录 AddNamedRerouteDeclarationNode... AddRerouteNode... AntialiasedTextureMask AtmosphereSunLightIlluminanceOnGround AtmosphereSunLightVector BentNormalCustomOutput BlackBody BoxMask-2D BoxMask-3D BumpOffset&#xff08;B&#xff09; ChannelMask…

Spring Boot 中的 STOMP 是什么,原理,如何使用

Spring Boot 中的 STOMP 是什么&#xff0c;原理&#xff0c;如何使用 介绍 在 Spring Boot 中&#xff0c;STOMP 是一种简单的文本协议&#xff0c;用于在客户端和服务器之间进行实时消息传递。它是 WebSocket 协议的一种扩展&#xff0c;可以在 WebSocket 上运行。在本文中…

Electron + ts + vue3 + vite 项目搭建

新建一个vite ts vue3的项目 在创建选项中选择ts和vue选项。 之后&#xff0c;安装依赖之后试运行一下&#xff0c;出现一下页面意味着vite-vue项目创建成功。 npm create vitelatest electron-vue3-ts-vite-test1 VSCode打开electron-vue3-ts-vite-test1或者cd electron-…

vue项目运行后使用ip地址在手机上打开

文章目录 1、获取ip地址2、保证你的手机和电脑使用的是一个wifi3、修改配置文件 1、获取ip地址 windowr&#xff0c;输入cmd按回车后在输入ipconfig ipv4地址就是你了 2、保证你的手机和电脑使用的是一个wifi 3、修改配置文件 &#xff08;1&#xff09;vue.config.js文件中…

大数据时代,商业智能BI的使用规则

商业智能BI的火热程度让很多不了解的企业也在内部部署了BI系统&#xff0c;怎么利用BI创造价值也就成了新的问题。 商业智能面向管理人员 很多人其实不理解&#xff0c;为什么说企业的管理人员想要完全了解企业的各项业务发展情况实际上是很困难的。 一家企业有这么多部门&a…

【redis】stream消息队列

目录 截图一、代码示例1.1 pom.xml依赖1.2 application.xml配置1.3 启动类1.4 配置类1.5 消息实体1.6 自定义错误1.7 自定义注解1.8 服务类1.9 监听类1.10 controller 截图 一、代码示例 1.1 pom.xml依赖 <?xml version"1.0" encoding"UTF-8"?> …