minio + linux + docker + spring boot实现文件上传与下载

minio + docker + spring boot实现文件上传与下载

  • 1.在linux上安装并启动docker
  • 2.在docker中拉取minio并启动
  • 3.Spring Boot 整合 minio
  • 4.测试 minio 文件上传、下载及图片预览等功能

1.在linux上安装并启动docker

  • 检查linux内核,必须是3.10以上
uname ‐r
  • 安装docker
yum install docker
  • 启动docker
systemctl start docker

2.在docker中拉取minio并启动

  • 搜索镜像
docker search minio

在这里插入图片描述

  • 拉取镜像
docker pull minio/minio

在这里插入图片描述

  • 启动minio
docker run  -p 9000:9000 -p 9090:9090 --name minio \
 -d --restart=always \
 -e MINIO_ACCESS_KEY=vinci \
 -e MINIO_SECRET_KEY=123456\
 -v /usr/local/minio/data:/data \
 -v /usr/local/minio/config:/root/.minio \
  minio/minio server /data  --console-address ":9000" --address ":9090"

-p: 指定端口映射,格式为:主机端口:容器端口 (这里注意要映射两个,否则API会访问不到)
-e “MINIO_ROOT_USER=vinci” minio用户名;
-e MINIO_SECRET_KEY=123456 minio 密码
-d: 后台运行容器,并返回容器ID;
-v: 绑定一个卷

这里可以看到minio已经在docker里启动起来了
在这里插入图片描述

接下来我们可以通过以下命令来查看 minio console和minio api 访问端口

docker logs minio

在这里插入图片描述

  • 访问minio控制台
    在此步骤前记得开放端口号
    在这里插入图片描述
    我们接下来可以使用密码和账号登录minio控制台了

3.Spring Boot 整合 minio

在此之前我们可以先通过控制台来创建一个bucket
在这里插入图片描述

  • 集成minio
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.4.0</version>
</dependency>
  • 编写minio配置类
/**
 * @package: com.vinci.minio.config
 * @className: MinioConfig
 * @author: Vinci
 * @description: minio配置类
 * @date: 2023/10/27 13:10
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    private String endpoint;

    private String accessKey;

    private String secretKey;

    private String bucketName;

    @Bean
    public MinioClient minioClient(){
        return MinioClient
                .builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }

}
  • 在application.properties中添加以下配置
minio.endpoint=http://108.13.21.28:9090/ 
minio.bucket-name=images
minio.access-key=xxxxx
minio.secret-key=xxxxx

注意 minio.endpoint 是minio API地址,不是控制台地址
minio.bucket-name 是 bucket的名称
minio.access-key 是用户名
minio.secret-key是密码

  • 编写minio工具类
package com.vinci.minio.utils;

import com.vinci.minio.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @description: minio工具类
 * @author: Vinci
 * @date: 2023/10/27 13:23
 **/
@Component
@Slf4j
public class MinioUtil {

    @Resource
    private MinioConfig config;

    @Resource
    private MinioClient minioClient;


    /**
     * @description: 查看存储bucket是否存在
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param bucketName 要查看的bucket名称
     * @return 存在即返回true
     **/
    public Boolean bucketExists(String bucketName) {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            log.error("发现异常",e);
            return false;
        }
    }

    /**
     * @description: 创建存储bucket
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param bucketName 要创建的bucket名称
     * @return 创建成功即返回true
     **/
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
            return true;
        } catch (Exception e) {
            log.error("发现异常",e);
            return false;
        }
    }


    /**
     * @description: 删除存储bucket
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param bucketName 要删除的bucket名称
     * @return 删除成功即返回true
     **/
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(
                    RemoveBucketArgs.builder()
                            .bucket(bucketName)
                            .build()
            );
            return true;
        } catch (Exception e) {
            log.error("发现异常",e);
            return false;
        }
    }


    /**
     * @description: 获取全部bucket
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @return 返回bucket结果集
     **/
    public List<Bucket> getAllBuckets() {
        try {
            return minioClient.listBuckets();
        } catch (Exception e) {
            log.error("发现异常",e);
            return null;
        }
    }



    /**
     * @description: 文件上传
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param file 表单上传的文件
     * @return 返回文件上传的路径
     **/
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()){
            throw new RuntimeException();
        }
        String fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        String objectName = new SimpleDateFormat("yyyyMM").format(new Date()) + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(config.getBucketName()).object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            minioClient.putObject(objectArgs);
            return objectName;
        } catch (Exception e) {
            log.error("发现异常",e);
            return null;
        }
    }


    /**
     * @description: 预览图片
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param fileName 文件在bucket中的全路径
     * @return 返回文件的浏览路径
     **/
    public String preview(String fileName){
        // 查看文件地址
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
                .builder()
                .bucket(config.getBucketName())
                .object(fileName)
                .method(Method.GET)
                .build();
        try {
            return minioClient.getPresignedObjectUrl(build);
        } catch (Exception e) {
            log.error("发现异常",e);
            return null;
        }
    }


    /**
     * @description: 文件下载
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @param fileName 文件在bucket中的全路径
     **/
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder()
                .bucket(config.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", "inline;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            log.error("发现异常",e);
        }
    }

    /**
     * @description: 查看文件对象
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @return 存储bucket内文件对象信息
     **/
    public List<Item> listObjects() {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(config.getBucketName()).build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
            return items;
        } catch (Exception e) {
            log.error("发现异常",e);
            return null;
        }
    }

    /**
     * @description: 删除文件信息
     * @author: Vinci
     * @date: 2023/10/27 13:24
     * @return 删除成功则返回true
     **/
    public boolean remove(String fileName){
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(config.getBucketName())
                            .object(fileName).build()
            );
            return true;
        }catch (Exception e){
            log.error("发现异常",e);
            return false;
        }
    }
    
    

}

4.测试 minio 文件上传、下载及图片预览等功能

  • 编写controller通过接口的方式来测试minio功能
package com.vinci.minio.controller;

import com.vinci.minio.utils.MinioUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

/**
 * @package: com.vinci.minio.controller
 * @className: TestMinioController
 * @author: Vinci
 * @description: 测试minio
 * @date: 2023/10/27 13:48
 */
@Controller
@RequestMapping(value = "/minio")
public class TestMinioController {

    @Resource
    private MinioUtil minioUtil;

    /**
     * @description: 文件上传测试
     * @author: Vinci
     * @date: 2023/10/27 13:48
     **/
    @ResponseBody
    @PostMapping("/upload")
    public String fileUpload(MultipartFile file) {
        return minioUtil.upload(file);
    }

    /**
     * @description: 文件下载测试
     * @author: Vinci
     * @date: 2023/10/27 13:51
     **/
    @ResponseBody
    @GetMapping("/download")
    public String fileDownload(String fileName, HttpServletResponse response){
        minioUtil.download(fileName,response);
        return "success";
    }

    /**
     * @description: 图片预览
     * @author: Vinci
     * @date: 2023/10/27 13:53
     **/
    @GetMapping("/preview")
    public String imagePreview(String fileName){
        return minioUtil.preview(fileName);
    }

}

  • 测试文件上传
    使用postMan来调用文件上传的接口
    在这里插入图片描述
    我们返回控制台可以看到文件已经上传上去了
    在这里插入图片描述
  • 测试文件下载
    在这里插入图片描述
    我们借助postman工具点击发送并下载可以看到文件下载成功了
    在这里插入图片描述
    在这里插入图片描述
  • 图片在线预览
    在这里插入图片描述
    我们同样借助postman工具发送请求,我们可以看到返回了图片的在线浏览地址,点击即可在线浏览图片
    在这里插入图片描述
    以上便是minio 整合springboot的全部流程了,感谢阅读!
    SpringBoot案例地址:https://gitee.com/vinci99/springboot-minio-test.git

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于aop 代理 Sentinel Nacos配置控制包装类实现原理

基于aop & 代理 & Sentinel & Nacos配置控制包装类实现原理 Hi&#xff0c;我是阿昌&#xff0c;今天记录下看sentinel源码结合业务实现的思路基于aop & 代理 & Sentinel & Nacos配置控制包装类实现原理&#xff1b;下面并不会手把手的记录方案的实现…

绿野仙踪不仅是童话,还是便宜又好用的产品测试法!

以 ChatGPT 为代表的大语言模型爆火后&#xff0c;推动了对话类人工智能产品的高速发展&#xff0c;我们已经看到了如智能助理、问答系统、自动写作等多种类型的个性化对话类 AI 服务。 AI 能力的提升让人们对智能 AI 产品的期望越来越高&#xff0c;相关产品的用户体验也因此变…

基于springboot实现校友社交平台管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校友社交平台管理系统演示 摘要 校友社交系统提供给用户一个校友社交信息管理的网站&#xff0c;最新的校友社交信息让用户及时了解校友社交动向,完成校友社交的同时,还能通过论坛中心进行互动更方便。本系统采用了B/S体系的结构&#xff0c;使用了java技…

PPT文档图片设计素材资源下载站模板源码/织梦内核(带用户中心+VIP充值系统+安装教程)

源码简介&#xff1a; PPT文档图片设计素材资源下载站模板源码&#xff0c;作为织梦内核素材资源下载站源码&#xff0c;它自带了用户中心和VIP充值系统&#xff0c;也有安装教程。 织梦最新内核开发的模板&#xff0c;该模板属于素材下载、文档下载、图库下载、PPT下载、办公…

疯狂java 三-六章

第三章 数据类型和运算符 Java语言是强类型语言&#xff0c;意思是每个变量和每个表达式都有一个在编译时就确定的类型&#xff0c;所有的变量都必须显式声明类型 标识符就是类&#xff0c;变量、方法命名的符号 标识符不能包含空格 标识符只能包含美元符($)&#xff0c;不…

python自动化测试平台开发:自动化测试平台简介

一.测试平台简介 为什么需要测试平台 已有的开源测试平台不能满足需要&#xff0c;不要轻易造轮子 需要公司级别的定制 需要整合公司内部的多套平台 例子&#xff1a;DevOps平台、精准化测试平台、质量监控平台等等 常见的测试平台开发模式 大一统模式&#xff08;适合简单的…

基于springboot实现校友社交平台管理系统项目【项目源码+论文说明】

基于springboot实现校友社交平台管理系统演示 摘要 校友社交系统提供给用户一个校友社交信息管理的网站&#xff0c;最新的校友社交信息让用户及时了解校友社交动向,完成校友社交的同时,还能通过论坛中心进行互动更方便。本系统采用了B/S体系的结构&#xff0c;使用了java技…

STM32-程序占用内存大小计算

STM32中程序占用内存容量 Keil MDK下Code, RO-data,RW-data,ZI-data这几个段: Code存储程序代码。 RO-data存储const常量和指令。 RW-data存储初始化值不为0的全局变量。 ZI-data存储未初始化的全局变量或初始化值为0的全局变量。 占用的FlashCode RO Data RW Data; 运行消…

如何为你的地图数据设置地图样式?

地图样式设置是GIS系统中非常重要的功能模块&#xff0c;水经微图Web版本最近对符号样式功能模块进行了升级。 你可以通过以下网址直接打开访问&#xff1a; https://map.wemapgis.com 现在我们为大家分享一下水经微图Web版中&#xff0c;如何为你标注的地图数据设置地图样式…

微信小程序——后台交互

目录 后台准备 pom.xml 配置数据源 整合mtbatis 前后端交互 method1 method2 后台准备 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org…

postgresSQL 数据库本地创建表空间读取本地备份SQL文件

使用pgAdmin4&#xff0c;你安装PG得文件夹****/16/paAdmin 4 /runtime/pgAdmin4.exe 第一步&#xff1a;找到Tablespaces 第二步&#xff1a;创建表空间名称 第三步&#xff1a;指向数据文件 第四步&#xff1a;找到Databases&#xff0c;创建表空间 第五步&#xff1a;输入数…

Jmeter性能测试:高并发分布式性能测试

​一、为什么要进行分布式性能测试 当进行高并发性能测试的时候&#xff0c;受限于Jmeter工具本身和电脑硬件的原因&#xff0c;无法满足我们对大并发性能测试的要求。 基于这种场景下&#xff0c;我们就需要采用分布式的方式来实现我们高并发的性能测试要求。 二、分布式性能…

Zeth:首个Type 0 zkEVM

1. 引言 一年前&#xff0c;V神博客The different types of ZK-EVMs中指出&#xff1a; 以太坊初始设计未围绕ZK友好性&#xff0c;因此&#xff0c;以太坊协议的很多部分都需要大量计算来做ZK-prove。Type 1 zkEVM致力于精准复制以太坊&#xff0c;因此它没有办法减轻这些低…

台积电2纳米黑科技 - 晶背供电 | 百能云芯

近期&#xff0c;台积电总裁魏哲家在一次法说会中透露了有关2纳米芯片的最新进展&#xff0c;并提到了“晶背供电”技术&#xff0c;这个领域的神秘黑科技正逐渐引起人们的兴趣。 在最近的台积电法说会上&#xff0c;总裁魏哲家不仅提到了2纳米制程的进展&#xff0c;还透露&am…

向量检索库Milvus架构及数据处理流程

文章目录 背景milvus想做的事milvus之前——向量检索的一些基础近似算法欧式距离余弦距离 常见向量索引1&#xff09; FLAT2&#xff09; Hash based3&#xff09; Tree based4&#xff09; 基于聚类的倒排5&#xff09; NSW&#xff08;Navigable Small World&#xff09;图 向…

Linux-安装docker-compose

前言&#xff1a;本文建立在服务器中已经存在docker环境的基础上&#xff0c;总结了安装docker-compose过程&#xff0c;以及安装过程中遇到的问题和解决方案。 一、下载docker-compose 在网上找了两种&#xff0c;一种是github官方的&#xff0c;一种是国内的镜像 gitbub官…

2023年9月青少年机器人技术(五级)等级考试试卷-实操题

2023.09青少年机器人技术&#xff08;五级&#xff09;等级考试试卷-实操题 主题&#xff1a;串口交互数字滚动循环显示 器件&#xff1a;ESP32主控板1块&#xff0c;四位数码管1个&#xff0c;74HC595移位寄存器芯片&#xff08;或模块&#xff09;及相应辅件。以上模块也可…

ubuntu 安装串口工具和添加虚拟串口

目录 一、串口工具安装 二、使用Windows本身虚拟的串口 &#xff08;一&#xff09;添加串口 1、保证虚拟机是关闭状态&#xff0c;打开“虚拟机设置”&#xff0c;点击“添加”。 2、选中“串行端口”&#xff0c;点击“完成”。 3、选中刚添加的串口&#xff0c;下拉选…

分享119个ASP.NET源码总有一个是你想要的

分享119个ASP.NET源码总有一个是你想要的 链接&#xff1a;https://pan.baidu.com/s/1Mp0RugMnIJbS8Hrja4sCOQ?pwd8888 提取码&#xff1a;8888 项目名称 asp.net core 微服务 项目 ASP.NET Core 项目日志解决方案 Serilog Log4net ASP.NET Core分布式项目实战 asp.n…

智能矩阵,引领商业新纪元!拓世方案:打破线上线下界限,开启无限营销可能!

在科技赋能商业大潮中&#xff0c;一切行业都在经历巨大变革&#xff0c;传统的营销策略被彻底改变&#xff0c;催生着无数企业去打造横跨线上线下、多维度、全方位的矩阵营销帝国。无数的成功案例已经告诉我们&#xff0c;营销不再只是宣传&#xff0c;而是建立品牌与消费者之…