SpringBoot集成MinIO

news2024/11/17 21:50:28

简介

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

引入依赖

     <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>7.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.14.9</version>
            <scope>compile</scope>
        </dependency>

yml文件配置

# Tomcat
server:
  port: 9100

# 自定义配置项,方便在代码中使用
minio:
  endpoint: 127.0.0.1
  port: 9001
  accessKey: minioadmin
  secretKey: minioadmin
  bucketName: upload
spring:
  servlet:
    multipart:
      max-file-size: 10000MB
      max-request-size: 20000MB

编写配置类

package com.example.mimio.config;

import io.minio.MinioClient;

import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
/*加载yml文件中以minio开头的配置项*/
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
    /*会自动的对应配置项中对应的key*/
    private String endpoint;//minio.endpoint
    private String accessKey;
    private String secretKey;
    private Integer port;
    /*把官方提供的MinioClient客户端注册到IOC容器中*/
    @Bean
    public MinioClient getMinioClient() throws InvalidPortException, InvalidEndpointException {
        MinioClient   minioClient = new MinioClient(getEndpoint(), getPort(), getAccessKey(), getSecretKey(), false);
        return minioClient;
    }
}

编写工具类

package com.example.mimio.util;

import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectOptions;
import io.minio.Result;
import io.minio.errors.*;
import io.minio.messages.DeleteError;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

@Component
public class MinioClientUtil {
    @Value("${minio.bucketName}")
    private String bucketName;
    @Resource
    private MinioClient minioClient;

    private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;

    /**
     * 检查存储桶是否存在
     */
    public boolean bucketExists(String bucketName) throws InvalidKeyException, ErrorResponseException,
            IllegalArgumentException, InsufficientDataException, InternalException, InvalidBucketNameException,
            InvalidResponseException, NoSuchAlgorithmException, XmlParserException, IOException {
        boolean flag = minioClient.bucketExists(this.bucketName);
        if (flag) return true;
        return false;
    }

    /**
     * 通过InputStream上传对象
     *
     * @param objectName 存储桶里的对象名称
     * @param stream     要上传的流 (文件的流)
     */
    public boolean putObject(String objectName, InputStream stream) throws Exception {

        //判断 桶是否存在
        boolean flag = bucketExists(bucketName);

        if (flag) {
            //往桶中添加数据   minioClient 进行添加

            /**
             *   参数1: 桶的名称
             *   参数2: 文件的名称
             *   参数3: 文件的流
             *   参数4: 添加的配置
             */
            minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1));
            ObjectStat statObject = statObject(objectName);
            if (statObject != null && statObject.length() > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 删除一个对象
     * @param objectName 存储桶里的对象名称
     */
    public boolean removeObject(String objectName)throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            minioClient.removeObject(bucketName, objectName);
            return true;
        }
        return false;
    }
    /**
     * 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表
     * @param objectNames 含有要删除的多个object名称的迭代器对象
     */
    public List<String> removeObject(List<String> objectNames) throws Exception {
        List<String> deleteErrorNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);
            for (Result<DeleteError> result : results) {
                DeleteError error = result.get();
                deleteErrorNames.add(error.objectName());
            }
        }
        return deleteErrorNames;
    }

    /**
     * 获取对象的元数据
     * @param objectName 存储桶里的对象名称
     */
    public ObjectStat statObject(String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            ObjectStat statObject = minioClient.statObject(bucketName, objectName);
            return statObject;
        }
        return null;
    }

    /**
     * 文件访问路径
     * @param objectName 存储桶里的对象名称
     */
    public String getObjectUrl(String objectName) throws Exception {
        boolean flag = bucketExists(bucketName);
        String url = "";
        if (flag) {
            url = minioClient.getObjectUrl(bucketName, objectName);
        }
        return url;
    }
    public void getObject(String filename, HttpServletResponse response){
        InputStream in = null;
        OutputStream out = null;
        try{
            in=minioClient.getObject(bucketName,filename);
            int length=0;
            byte[] buffer = new byte[1024];
            out = response.getOutputStream();
            response.reset();
            response.addHeader("Content-Disposition",
                    " attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
            response.setContentType("application/octet-stream");
            while ((length = in.read(buffer)) > 0) {
                out.write(buffer, 0, length);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (in != null){
                try {
                    in.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

编写控制器

package com.example.mimio.controller;

import com.example.mimio.response.ResponseData;
import com.example.mimio.util.MinioClientUtil;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

@RestController
public class TestController {
    @Autowired
    public void setMinioClientUtil(MinioClientUtil minioClientUtil) {
        this.minioClientUtil = minioClientUtil;
    }

    private MinioClientUtil minioClientUtil;

    @PostMapping("/upload")
    public ResponseData uploadMinio(@RequestPart MultipartFile file) throws Exception {

        //拿到图片  MultipartFile封装接受的类
        //拿到图片的名称
        String filename = file.getOriginalFilename();

        //拿到图片的 UUId + 图片类型 (解决图片重名的问题 )
        String uuid = UUID.randomUUID().toString();
        String imgType = filename.substring(filename.lastIndexOf("."));

        //图片文件的新名称 xxx/uuid.jpg   图片拼接后的名
        String fileName = uuid + imgType;

        boolean flag = minioClientUtil.putObject(fileName, file.getInputStream());


        String path = "/upload/" + fileName;

        return flag ? ResponseData.success("上传成功",path):ResponseData.failed("上传失败");
    }
    @PostMapping("/downLoad")
    public ResponseData downLoadMinio(String url,HttpServletResponse response) throws Exception {
       // String objectUrl = minioClientUtil.getObjectUrl("a9e203f9-1bbb-4d59-8c28-3a183c064502.sql")
        String trim = url.trim();
        String path = trim.substring(trim.indexOf("/", 1), trim.length());
        minioClientUtil.getObject(path,response);
        return null;
    }

}

上传接口调用

 下载接口调用

 

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

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

相关文章

工业物联网解决方案:水轮机PLC数据采集远程监控系统

水轮机是一种能将水的动能转化为旋转机械能的动力设备&#xff0c;是水电站的重要工业设备。随着工业自动化技术与PLC设备的推广应用&#xff0c;水轮机可以通过PLC实现自动化控制&#xff0c;进而通过搭建PLC数据采集远程监控系统&#xff0c;实现水轮机的实时在线监控&#x…

产品再次跳票 法拉第未来的融资价值却渐渐浮现?

从“生态化反”到“极智科技顶奢”&#xff0c;贾跃亭讲故事的出众能力&#xff0c;总是能为旗下企业和产品赚足市场眼球。 但仅有宏大的前景描绘&#xff0c;似乎难以触动理性的资本市场&#xff0c;其创立的新能源车企法拉第未来&#xff08;NASDAQ&#xff1a;FFIE&#xf…

在IDEA中将自定义的配置文件设置到SpringBoot工程中

可以帮助我们生成自定义配置的元数据信息&#xff0c;让配置文件和Java代码之间的对应参数可以自动定位&#xff0c;方便开发。 <!-- 生成自定义配置的元数据信息 --><dependency><groupId>org.springframework.boot</groupId><artifactId>sprin…

Hiera:一个没有Bells-and-Whistles的分层视觉转换器

文章目录 Hiera: A Hierarchical Vision Transformer without the Bells-and-Whistles摘要本文方法实验结果 Hiera: A Hierarchical Vision Transformer without the Bells-and-Whistles 摘要 现代层次视觉转换器在追求监督分类性能的过程中增加了一些特定于视觉的组件。虽然…

PS修改日期(简单两步)

PS修改日期&#xff08;简单两步&#xff09; Q&#xff1a;将图中的日期修改为6月10日 选择画笔工具&#xff0c;把要修改的日期涂抹掉 设置前景色&#xff0c;使用吸管吸附要涂抹的颜色&#xff0c;然后点击确定 使用设置好颜色的画笔&#xff0c;在要修改的日期上涂抹 …

接口自动化测试实操【设置断言思路】

1 断言设置思路 这里总结了我在项目中常用的5种断言方式&#xff0c;基本可能满足90%以上的断言场景&#xff0c;具体参见如下脑图&#xff1a; 在这里插入图片描述 下面分别解释一下图中的五种思路&#xff1a; 1&#xff09; 响应码 对于http类接口&#xff0c;有时开发人…

期末复习【计算机网络】

期末复习【计算机网络】 前言推荐期末复习如何快速阅读电子书重点第1章 概述1.6 计算机网络的性能1.6.2 计算机网络的性能指标√ 1.7 计算机网络体系结构1.7.3 具有五层协议的体系结构√ 第2章 物理层2.3 物理层下面的传输媒体 *2.4 信道复用技术2.4.1 频分复用、时分复用和统计…

天津大学天津市认知计算与应用重点实验室视听觉认知计算团队12篇论文被语音处理顶会Interspeech 2023接收

天津大学天津市认知计算与应用重点实验室视听觉认知计算团队12篇论文被语音技术顶会Interspeech 2023接收&#xff0c;涵盖意图识别、口语理解、声学特征、语音识别、语音分离、情感识别等研究方向&#xff0c;论文简介如下。 01. Rethinking the visual cues in audio-visual…

Harbor 间通过API实现镜像复制

背景&#xff1a; 通过harbor搭建私有镜像仓库时&#xff0c;往往会设计出 研发镜像仓库--》测试镜像仓库--》产品镜像仓库&#xff0c;甚至更多。那个多镜像间的复制将成了一个必须解决的问题。当然可以通过harbor自带的界面操作即可实现需求&#xff0c;也可以通过harbor提供…

详解20个常见的模拟电路

桥式整流电路 二极管的单向导电性&#xff1a;二极管的PN结加正向电压&#xff0c;处于导通状态&#xff1b;加反向电压&#xff0c;处于截止状态。其伏安特性曲线&#xff0c;如下图。 理想开关模型和恒压降模型&#xff1a;理想模型指的是在二极管正向偏置时&#xff0c;其管…

乳腺癌预测的黑科技!一起探索 R 语言和随机森林算法的奇妙之处!

一、引言 乳腺癌是全球最常见的女性恶性肿瘤之一&#xff0c;也是导致女性死亡的主要原因之一。根据世界卫生组织的数据&#xff0c;每年有约200万例乳腺癌新病例的发生&#xff0c;导致60多万人死亡。乳腺癌的早期发现和精准治疗对于患者的生存率和预后至关重要。 然而&…

uniapp封装门票等票务样式

先看效果图 ticketpage组件引用后&#xff0c;根据父级背景颜色改变镂空的颜色,空组件只有中间镂空的样式&#xff0c;上面是插槽heaer,下面内容是插槽content&#xff0c;可以自定义自己的内容和样式。我实现的最终效果是用的uview组件&#xff0c;如果复现需要项目引入。可…

pytorch量化库使用(2)

FX Graph Mode量化模式 训练后量化有多种量化类型&#xff08;仅权重、动态和静态&#xff09;&#xff0c;配置通过qconfig_mapping &#xff08; prepare_fx函数的参数&#xff09;完成。 FXPTQ API 示例&#xff1a; import torch from torch.ao.quantization import (ge…

ACL2023 | 赔了?引入GPT-3大模型到智能客服,竟要赔钱?

作者 | 小戏、Python 关于大模型的商业落地&#xff0c;一个非常容易想到的场景就是智能客服&#xff0c;作为不止是大模型也是 NLP 领域的一个最主要的应用场景&#xff0c;由于人工客服的高昂成本&#xff0c;AI 客服伴随着模型技术的发展也逐步走进我们的生活&#xff0c;在…

vue iview table Tooltip内容过多闪屏解决

vue的项目&#xff0c;框架是iview 客户反应&#xff0c;指令描述的内容有几百个字&#xff0c;鼠标悬浮&#xff0c;浏览器开始闪烁 解决思路是加宽度限制&#xff0c;滚动&#xff0c; 后面发现像是transfer属性的bug&#xff0c;触碰浏览器底部&#xff0c;距离不够造成 …

重新理解 RocketMQ Commit Log 存储协议

最近突然感觉&#xff1a;很多软件、硬件在设计上是有 root reason 的&#xff0c;不是 by desgin 如此&#xff0c;而是解决了那时、那个场景的那个需求。一旦了解后&#xff0c;就会感觉在和设计者对话&#xff0c;了解他们的思路&#xff0c;学习他们的方法&#xff0c;思维…

C#可视化 国产热剧信息查询(具体做法及全部代码)

目录 题目&#xff1a; 做法&#xff1a; 代码部分&#xff1a; DBHelper类 From1主窗体代码 题目&#xff1a; 1. 首次打开页面&#xff0c;展示所有汽车信息列表&#xff0c;如图 1 所示。 2.双击第二行右边内容全部发生改变 数据库设计及内容 做法&#xff1a; 首先设置d…

React hooks文档笔记(五)useEffect——解决异步操作竞争问题

1.开发环境下组件加载两次&#xff1f; 非bug&#xff0c;重新安装组件仅在开发过程中发生&#xff0c;帮助找到需要清理的效果。在生产环境中只会加载一次。 React 将在 Effect 下次运行之前以及卸载期间调用您的清理函数。return () > {}; 2. &#x1f330;订阅事件情况…

Python连接MySQL数据库(简单便捷)

&#x1f412;&#xff0c;本文中&#xff0c;使用到的工具有&#xff1a;Pycharm&#xff0c;Anaconda&#xff0c;MySQL 5.5&#xff0c;spyder(Anaconda) 什么是 PyMySQL&#xff1f; PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库&#xff0c;Python2 中则…

Java 语言基础练习题

Java 语言基础练习题 Key Point ●包的基本语法 ●Java 语言中的标识符&#xff0c;命名规范 ●八种基本类型 ●基本操作符 ●if 语句和switch 语句 练习 1.&#xff08;标识符命名&#xff09;下面几个变量中&#xff0c;那些是对的&#xff1f;那些是错的&#xff1f;错的请…