SpringBoot 整合MinIO并实现文件上传

1、依赖

<!-- https://mvnrepository.com/artifact/io.minio/minio -->
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.9</version>
</dependency><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.1</version>
</dependency>

2、连接参数说明

你需要有存储服务的三个参数才能连接到该服务。

参数 说明
Endpoint 对象存储服务的URL
Access Key Access key就像用户ID,可以唯一标识你的账户。
Secret Key Secret key是你账户的密码。
bucketName bucketName是你设置的桶的名称

3、yaml配置

server:port: 18001
spring:application:name: minio-applicationservlet:multipart:max-file-size: 10MBmax-request-size: 10MB
minio:endpoint: http://192.168.211.132:9000accessKey: adminsecretKey: admin123456bucketName: minio-test

4、加载Minio配置 MinioConfig.java

package cn.lyf.minio.config;import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author lyf* @description: Minio 配置类* @version: v1.0* @since 2022-04-29 14:49*/
@Configuration
@Data
@ConfigurationProperties(value = "minio")
public class MinioConfig {/*** 对象存储服务的URL*/private String endpoint;/*** Access key就像用户ID,可以唯一标识你的账户。*/private String accessKey;/*** Secret key是你账户的密码。*/private String secretKey;/*** bucketName是你设置的桶的名称*/private String bucketName;/*** 初始化一个MinIO客户端用来连接MinIO存储服务** @return MinioClient*/@Beanpublic MinioClient initMinioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}
}

5、分布式ID生成方案IdWorker (代码来源于网络)

package cn.lyf.minio.entity;import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;/*** <p>名称:IdWorker.java</p>* <p>描述:分布式自增长ID</p>* <pre>*     Twitter的 Snowflake JAVA实现方案* </pre>* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。* <p>* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))** @author Polim*/
public class IdWorker {// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)private final static long twepoch = 1649410310176L;// 机器标识位数private final static long workerIdBits = 5L;// 数据中心标识位数private final static long datacenterIdBits = 5L;// 机器ID最大值private final static long maxWorkerId = ~(-1L << workerIdBits);// 数据中心ID最大值private final static long maxDatacenterId = ~(-1L << datacenterIdBits);// 毫秒内自增位private final static long sequenceBits = 12L;// 机器ID偏左移12位private final static long workerIdShift = sequenceBits;// 数据中心ID左移17位private final static long datacenterIdShift = sequenceBits + workerIdBits;// 时间毫秒左移22位private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;private final static long sequenceMask = ~(-1L << sequenceBits);/* 上次生产id时间戳 */private static long lastTimestamp = -1L;// 0,并发控制private long sequence = 0L;private final long workerId;// 数据标识id部分private final long datacenterId;public IdWorker(){this.datacenterId = getDatacenterId(maxDatacenterId);this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);}/*** @param workerId*            工作机器ID* @param datacenterId*            序列号*/public IdWorker(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}this.workerId = workerId;this.datacenterId = datacenterId;}/*** 获取下一个ID** @return*/public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}if (lastTimestamp == timestamp) {// 当前毫秒内,则+1sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {// 当前毫秒内计数满了,则等待下一秒timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;// ID偏移组合生成最终的ID,并返回IDlong nextId = ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift) | sequence;return nextId;}private long tilNextMillis(final long lastTimestamp) {long timestamp = this.timeGen();while (timestamp <= lastTimestamp) {timestamp = this.timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}/*** <p>* 获取 maxWorkerId* </p>*/protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {StringBuffer mpid = new StringBuffer();mpid.append(datacenterId);String name = ManagementFactory.getRuntimeMXBean().getName();if (!name.isEmpty()) {/** GET jvmPid*/mpid.append(name.split("@")[0]);}/** MAC + PID 的 hashcode 获取16个低位*/return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);}/*** <p>* 数据标识id部分* </p>*/protected static long getDatacenterId(long maxDatacenterId) {long id = 0L;try {InetAddress ip = InetAddress.getLocalHost();NetworkInterface network = NetworkInterface.getByInetAddress(ip);if (network == null) {id = 1L;} else {byte[] mac = network.getHardwareAddress();id = ((0x000000FF & (long) mac[mac.length - 1])| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;id = id % (maxDatacenterId + 1);}} catch (Exception e) {System.out.println(" getDatacenterId: " + e.getMessage());}return id;}/*public static void main(String[] args) {//推特  26万个不重复的ID*//*IdWorker idWorker = new IdWorker(0,0);for (int i = 0; i <2600 ; i++) {System.out.println(idWorker.nextId());}*//*System.out.println(maxDatacenterId);System.out.println(maxWorkerId);System.out.println(System.currentTimeMillis());}*/}

5.1、注入IDWorker

    /*** 分布式ID生成方案,用于生成文件名称** @return id*/@Beanpublic IdWorker idWorker() {return new IdWorker(0, 0);}

6、文件上传的代码 FileController.java

package cn.lyf.minio.controller;import cn.lyf.minio.config.MinioConfig;
import cn.lyf.minio.entity.IdWorker;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import java.util.concurrent.ThreadPoolExecutor;/*** @author lyf* @description:* @version: v1.0* @since 2022-05-03 10:39*/
@RestController
@RequestMapping(value = "/file")
@Slf4j
public class FileController {@Autowiredprivate MinioConfig minioConfig;@Autowiredprivate MinioClient minioClient;@Autowiredprivate IdWorker idWorker;@Resource(name = "minioFileThreadPool")private ThreadPoolExecutor minioFileThreadPool;/*** 文件上传** @param file file* @return 上传之后的文件地址*/@PostMapping(value = "/upload")public String upload(@RequestParam(name = "file") MultipartFile file) throws Exception {// 检查存储桶是否已经存在boolean isExist =minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioConfig.getBucketName()).build());if (isExist) {log.info("Bucket {} already exists.", minioConfig.getBucketName());} else {// 创建一个名为asiatrip的存储桶,用于存储照片的zip文件。minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConfig.getBucketName()).build());}String originalFilename = file.getOriginalFilename();String filenameExtension = StringUtils.getFilenameExtension(originalFilename);String fileNameInMinio = idWorker.nextId() + "." + filenameExtension;// 使用putObject上传一个文件到存储桶中。minioClient.putObject(PutObjectArgs.builder()// 设置桶名称.bucket(minioConfig.getBucketName())// 设置文件流对象.stream(file.getInputStream(), file.getSize(), -1)// 设置文件在minio服务器中的名称.object(fileNameInMinio)// 设置文件类型.contentType(file.getContentType()).build());log.info("file upload success, filename: {}, contentType: {}, size(byte): {}", fileNameInMinio,file.getContentType(), file.getSize());// 获取文件名称String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()// 文件请求方式.method(Method.GET)// 对应的桶的名称.bucket(minioConfig.getBucketName())// 对应的文件名.object(fileNameInMinio).build());// TODO 可以异步的将文件信息存入数据库return presignedObjectUrl;}
}

7、测试

http://192.168.211.132:9000/minio-test/8962006962929664.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20220503%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220503T030339Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=178facc151eb409b283270dc2fd1210a3eb1162e4cadcc600a6f6e033e60680c

MinIO入门-02 SpringBoot 整合MinIO并实现文件上传相关推荐

  1. SpringBoot整合阿里云OSS文件上传、下载、查看、删除

    SpringBoot整合阿里云OSS文件上传.下载.查看.删除 该项目源码地址:https://github.com/ggb2312/springboot-integration-examples ( ...

  2. SpringBoot整合Jersey2.x实现文件上传API

    前言 SpringBoot的官方文档中关于Jersey的介绍并不是很全面: 27.3 JAX-RS and Jersey,SpringBoot-Sample项目里面也只有非常基础的代码,对于一些复杂的 ...

  3. SpringBoot(24) 整合七牛云实现文件上传

    一.前言 本文将基于springboot2.1.8.RELEASE整合七牛云实现文件上传 本文参考 https://www.keppel.fun/articles/2019/02/27/1551262 ...

  4. SpringBoot整合FFmpeg进行视频分片上传(Linux)

    SpringBoot整合FFmpeg进行视频分片上传 分片上传的核心思路: 分片上传到意义: 分片上传的原理: 准备工作: 一:下载.解压 代码展示: pom文件 yml配置 工具类 controll ...

  5. spring boot 整合web开发之文件上传、静态资源访问、异常处理、返回JSON数据

    目录 springboot 整合web开发 返回json数据 静态资源访问 文件上传 全局异常 1.返回json数据 springboot默认的是jackson-databind做为json处理器.也 ...

  6. SpringMVC整合fastdfs-client-java实现web文件上传下载

    为什么80%的码农都做不了架构师?>>>    版权声明:本文为博主原创文章,转载请标明出处(http://blog.csdn.net/wlwlwlwl015)Thanks. 目录( ...

  7. SpringBoot集成FastDFS依赖实现文件上传

    前言 对FastDFS文件系统安装后的使用. FastDFS的安装请参考这篇:https://www.cnblogs.com/niceyoo/p/13511082.html 本文环境:IDEA + J ...

  8. springBoot 简单优雅是实现文件上传和下载

    前言 好久没有更新spring Boot 这个项目了.最近看了一下docker 的知识,后期打算将spring boot 和docker 结合起来.刚好最近有一个上传文件的工作呢,刚好就想起这个脚手架 ...

  9. 【前端】wangeditor源码修改,打包发布到npm,实现上传视频功能,得到视频的第一帧保存为封面,spring-boot+vue,axios实现文件上传,视频图片浏览

    一.实现 1.创建git分支,clone下源码 git地址 创建分支 2.图片上传具有文件选择的功能,所以我完全模仿(抄袭)图片上传 报错不慌,全部改完就不报错了 1)在src/config/inde ...

最新文章

  1. 无法打开文件“python310_d.lib”
  2. Linux 系统应用编程——标准I/O
  3. java定时任务_ftp上传软件,ftp上传软件定时功能教程
  4. LeetCode题库11:盛最多水的容器——JavaScript解答
  5. putty 32位_了解linux系统远程操作软件,putty的安装过程!
  6. MongoDB怎么做性能测试,看看这篇大神总结
  7. 第八章 linux磁盘与文件系统管理g
  8. 怎么判断浮点数的有效位数_JavaScript的数据类型及判断
  9. 网上十大经典黑客软件大曝光(转)
  10. [转]开源软件名的读音
  11. Java二进制zip,excel文件流到前端时,修改jQuery接受二进制数据。转文件后提示文件损坏(不可预料的压缩文件末端)处理
  12. 个人域名备案有什么要求?需要准备什么?
  13. Excel表格中,删除列或行的快捷键是什么
  14. css悬停动画,CSS卡片悬停动画效果实现
  15. 浅谈JAVA程序破解(原创)
  16. 1、编写一个程序,将一个小写字母(如a)转换成相应的大写字母并显示输出。
  17. 通达OA国产化简介/信创版本
  18. 基于快速GeoHash,如何实现海量商品与商圈的高效匹配?...
  19. 桌游推荐|谁是卧底推理系列游戏上新,不一样的头脑风暴
  20. Zebec获BNB Chain生态大力支持,ZBC通证将陆续登录一线平台

热门文章

  1. 服务器被攻击导致CPU100%的解决
  2. Apifox 生成接口文档 教程与操作步骤
  3. Mysql中的索引原理
  4. Python使用traceback.print_exc()输出异常信息
  5. SVM支持向量机算法
  6. 《合成孔径雷达成像——算法与实现》之【0】仿真汇报
  7. 淘宝客如何通过简书引流?如何成为淘宝客?
  8. 〖Python零基础入门篇(60)〗 - 随机模块 - random
  9. 桌面出现“了解此图片”如何删除?
  10. PHP非诚勿扰-我不是“拍黄片”的!