MinIO实现文件上传
一、使用Docker安装minio
docker run -d -p 9000:9000 -p 9001:9001 --name minio -e MINIO_ACCESS_KEY=qbb -e MINIO_SECRET_KEY=startqbb -v /opt/minio/data:/data -v /opt/minio/config:/root/.minio minio/minio server /data --console-address ":9000" --address ":9001"
- MINIO_ACCESS_KEY:指定的是"用户名",可以这么理解,后面我们文件上传需要使用
- MINIO_SECRET_KEY:指定的是"密码",可以这么理解,后面我们文件上传需要使用
二、创建一个Project工程(我是用的是Gradle,大家也可以使用Maven)

三、实现文件上传
1、导入相关依赖
plugins {
id 'java'
}
group 'com.qbb'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.3'
implementation 'mysql:mysql-connector-java:8.0.29'
implementation 'org.springframework.boot:spring-boot-starter-test:2.7.3'
implementation 'org.projectlombok:lombok:1.18.24'
implementation 'io.springfox:springfox-swagger2:3.0.0'
implementation 'io.springfox:springfox-swagger-ui:3.0.0'
implementation 'io.minio:minio:8.4.3'
}
test {
useJUnitPlatform()
}
2、修改配置文件
# application.yml
server:
port: 8080
spring:
profiles:
active: dev
# include: dev
application:
name: minio
# 这个mvc的配置是springboot2.6.1不支持swagger3的折衷配置,后面考虑升级Springboot版本或降级版本
mvc:
pathmatch:
matching-strategy: ant_path_matcher
servlet:
multipart:
# 设置 上传文件的大小
max-file-size: 100MB
# 设置 整个请求的大小
max-request-size: 150MB
# application-dev.yml
swagger:
enabled: true
app:
minio:
endpoint: http://192.168.119.159:9001
accessKey: qbb
secretKey: startqbb
bucket: qbb
3、主启动类
package com.qbb.minio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-09-19 15:45
* @Description:
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、Swagger3配置类
package com.qbb.minio.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-09-19 15:45
* @Description: Swagger配置
*/
@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Value("${swagger.enabled}")
boolean swaggerEnabled;
@Value("${spring.application.name}")
String name;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo())
// 是否开启
.enable(swaggerEnabled).select()
// 扫描的路径使用@Api的controller
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 指定路径处理PathSelectors.any()代表所有的路径
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Swagger3接口文档")
.description(name + "接口文档")
//作者信息
.contact(new Contact("startqbb", "https://www.cnblogs.com/qbbit", "startqbb@163.com"))
.version("1.0")
.build();
}
}
5、Minio配置类
package com.qbb.minio.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-09-19 15:57
* @Description:
*/
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "app.minio")
@Configuration
@Data
public class MinioConfig {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucket;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
6、Minio工具类
package com.qbb.minio.util;
import com.qbb.minio.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
/**
* @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-09-19 16:44
* @Description:
*/
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioConfig minioConfig;
@Resource
private 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
*/
public void makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除存储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 {
return minioClient.listBuckets();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件上传
*
* @param file 上传的文件
* @return
*/
public String upload(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
throw new RuntimeException();
}
String fileName = UUID.randomUUID().toString().replace("-", "") + "_" + originalFilename;
// 日期目录
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
// String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
// 也可以使用JDK1.8的新时间类LocalDate/LocalDateTime
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String formatDatePath = formatter.format(now);
// 加一个时间戳
long timeMillis = System.currentTimeMillis();
String objectName = formatDatePath + "/" + timeMillis + fileName;
try {
PutObjectArgs objectArgs = PutObjectArgs.builder()
.bucket(minioConfig.getBucket())
.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 = GetPresignedObjectUrlArgs.builder()
.bucket(minioConfig.getBucket())
.object(fileName)
.method(Method.GET)
.build();
try {
return minioClient.getPresignedObjectUrl(build);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件下载
*
* @param fileName 文件名称
* @param res response
*/
public void download(String fileName, HttpServletResponse res) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(minioConfig.getBucket())
.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(String bucketName) {
if (StringUtils.isBlank(bucketName) || !bucketExists(bucketName)) {
return null;
}
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).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 bucket 桶名称
* @return {@link List}<{@link String}>
*/
public List<String> getBucketObjectName(String bucket) {
boolean exsit = bucketExists(bucket);
if (exsit) {
List<String> listObjetcName = new ArrayList<>();
try {
Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket).build());
for (Result<Item> result : myObjects) {
Item item = result.get();
listObjetcName.add(item.objectName());
}
return listObjetcName;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 删除
*
* @param fileName 文件名称
* @return true|false
*/
public boolean remove(String fileName) {
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucket()).object(fileName).build());
} catch (Exception e) {
return false;
}
return true;
}
/**
* 批量删除文件
*
* @param bucket 桶名称
* @param objectNames 对象名称
* @return boolean
*/
public boolean removeObjects(String bucket, List<String> objectNames) {
boolean exsit = bucketExists(bucket);
if (exsit) {
try {
List<DeleteObject> objects = new LinkedList<>();
for (String str : objectNames) {
objects.add(new DeleteObject(str));
}
minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucket).objects(objects).build());
return true;
} catch (Exception e) {
log.error("removeObjects", e);
}
}
return false;
}
}
7、测试
package com.qbb.minio.controller;
import com.qbb.minio.config.MinioConfig;
import com.qbb.minio.util.MinioUtil;
import io.minio.messages.Bucket;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-09-19 15:45
* @Description:
*/
@Slf4j
@Api(tags = "MinIO")
@RestController
@RequestMapping("/minio")
public class FileUploadController {
@Resource
MinioConfig minioConfig;
@Resource
MinioUtil minioUtil;
@ApiOperation("测试程序")
@GetMapping("/hello")
public String hello() {
return "hello";
}
@ApiOperation("文件上传")
@PostMapping("/upload")
public String upload(@ApiParam("文件") MultipartFile file) {
try {
/**
* 这里应该放在service层处理的,将上传的文件路径存入数据库,我就不这么麻烦了,直接返回给前端
*/
String bucket = minioConfig.getBucket();
String endpoint = minioConfig.getEndpoint();
// 1.检查存储桶是否已经存在
boolean isExist = minioUtil.bucketExists(bucket);
if (isExist) {
log.info("Bucket already exists");
} else {
// 不存在则创建一个名为bucket的存储桶,用于存储照片的zip文件。
minioUtil.makeBucket(bucket);
}
// 2.上传
String objectName = minioUtil.upload(file);
// 3.访问路径
return endpoint + "/" + bucket + "/" + objectName;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("文件上传异常!!!");
}
}
@ApiOperation("文件下载")
@GetMapping("/download")
public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
minioUtil.download(fileName, response);
}
@ApiOperation("文件删除")
@DeleteMapping("/remove")
public String remove(@RequestParam("fileName") String fileName) {
boolean flag = minioUtil.remove(fileName);
if (flag) {
return "success";
}
return "error";
}
@ApiOperation("文件预览")
@GetMapping("/preview")
public String preview(@RequestParam("fileName") String fileName) {
String url = minioUtil.preview(fileName);
if (!StringUtils.isEmpty(url)) {
return url;
}
return "error";
}
@ApiOperation("获取Bucket列表")
@GetMapping("/getAllBuckets")
public List<Bucket> getAllBuckets() {
return minioUtil.getAllBuckets();
}
@ApiOperation("创建一个Bucket")
@PostMapping("/makeBucket/{bucketName}")
public String makeBucket(@PathVariable("bucketName") String bucketName) {
minioUtil.makeBucket(bucketName);
return "success";
}
@ApiOperation("删除一个Bucket")
@DeleteMapping("/removeBucket/{bucketName}")
public String removeBucket(@PathVariable("bucketName") String bucketName) {
Boolean isSuccess = minioUtil.removeBucket(bucketName);
if (isSuccess) {
return "success";
}
return "error";
}
@ApiOperation("查看Bucket中的所有Object")
@GetMapping("/getBucketObjectName/{bucketName}")
public List<String> getBucketObjectName(@PathVariable("bucketName") String bucketName) {
return minioUtil.getBucketObjectName(bucketName);
}
}

MinIO实现文件上传的更多相关文章
- minio实现文件上传下载和删除功能
https://blog.csdn.net/tc979907461/article/details/106673570?utm_medium=distribute.pc_relevant_t0.non ...
- springCloud 微服务通过minio实现文件上传和文件下载接口
直接上代码吧,好多文章的下载都写的不明不白的,让人理解错,气死了!! 文件上传功能 文件上传很简单,首先你得部署好minio,然后写好配置信息,我的是动态读取nacos上配置的yml @Autowir ...
- minio文件上传与下载
目录 一.minio简介 二.minio安装 一.java中使用 一.minio简介 MinIO 是在 GNU Affero 通用公共许可证 v3.0 下发布的高性能对象存储. 它是与 Amazon ...
- UniApp文件上传(SpringBoot+Minio)
UniApp文件上传(SpringBoot+Minio) 一.Uni文件上传 (1).文件上传的问题 UniApp文件上传文档 uni.uploadFile({ url: 'https://www.e ...
- 94、springboot+minio实现分片上传(超大文件快速上传)
设计由来 在实际的项目开发中常遇到超大附件上传的情况,有时候客户会上传GB大小的文件,如果按照普通的MultipartFile方式来接收上传的文件,那么无疑会把服务器给干崩溃,更别说并发操作了.于是笔 ...
- Springboot 一行代码实现文件上传 20个平台!少写代码到极致
大家好,我是小富~ 技术交流,公众号:程序员小富 又是做好人好事的一天,有个小可爱私下问我有没有好用的springboot文件上传工具,这不巧了嘛,正好我私藏了一个好东西,顺便给小伙伴们也分享一下,d ...
- jquery.uploadify文件上传组件
1.jquery.uploadify简介 在ASP.NET中上传的控件有很多,比如.NET自带的FileUpload,以及SWFUpload,Uploadify等等,尤其后面两个控件的用户体验比较好, ...
- 11、Struts2 的文件上传和下载
文件上传 表单准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设置 ...
- Java FtpClient 实现文件上传服务
一.Ubuntu 安装 Vsftpd 服务 1.安装 sudo apt-get install vsftpd 2.添加用户(uftp) sudo useradd -d /home/uftp -s /b ...
- 小兔Java教程 - 三分钟学会Java文件上传
今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...
随机推荐
- 在线问诊 Python、FastAPI、Neo4j — 创建 节点关系
目录 关系:症状-检查 关系:疾病-症状 代码重构 relationship_data.csv 症状,检查,疾病,药品,宜吃,忌吃 "上下楼梯疼,不能久站,感觉有点肿"," ...
- oracle优化-分页查询新认识
在写这篇文章之前,对分页查询的认识就是经典的三层嵌套:第①层:获得需要的数据,第②层:用rownum限制展示数据的上限,第③层:用rownum的别名rn限制展示数据的下限. 在生产中遇见一个两层嵌套满 ...
- Fireboom on Sealos:半小时搞定一个月的接口工作
后端日常开发工作中有 88% 的接口都是 CURD,占用了超过 6 成开发时间.这些工作枯燥乏味,且价值低下,不仅荒废了时间,还无法获得任何成就感.而 Fireboom 可在 2 分钟内,完成传统模式 ...
- 2023 ICPC 网络赛 I
没留够时间准备导致开考的时候耽搁了 开场我先写缺省源,抄串了一行,后面才发现...然后看了 L 发现是签到,此时 ddw 会了 A 让 zsy 上去写,我等了一会才把 zsy 撵下来写 L 是个失误 ...
- hadoop集群搭建及编程实践
Hadoop集群搭建 前期准备及JDK,hadoop安装 设置主机名和添加主机映射 验证连通性 SSH无密码登录 配置集群/分布式环境 修改workers 修改文件core-site.xml 修改hd ...
- 在线问诊 Python、FastAPI、Neo4j — 问题咨询
目录 查出节点 拼接节点属性 测试结果 问答演示 通过节点关系,找出对应的节点,获取节点属性值,并拼接成想要的结果. 接上节生成的CQL # 输入 question_class = {'args': ...
- Java虚拟机(JVM):第四幕:自动内存管理 - 经典垃圾收集器
前言:如果说收集算法是内存回收的方法论,那么垃圾收集器则是内存回收的实践者.整哥Java堆 :Full GC. 1.Serial收集器:最基础.历史最悠久的收集器,这是一个单线程工作的收集器. 2.P ...
- Go泛型解密:从基础到实战的全方位解析
本篇文章深入探讨了Go语言的泛型特性,从其基础概念到高级用法,并通过实战示例展示了其在实际项目中的应用. 关注[TechLeadCloud],分享互联网架构.云服务技术的全维度知识.作者拥有10+年互 ...
- 一步步带你剖析Java中的Reader类
本文分享自华为云社区<深入理解Java中的Reader类:一步步剖析>,作者:bug菌. 前言 在Java开发过程中,我们经常需要读取文件中的数据,而数据的读取需要一个合适的类进行处理.J ...
- ELK中 Elasticsearch和Logstash内存大小设置的考虑
本文为博主原创,转载请注明出处: 在ELK(Elasticsearch.Logstash和Kibana)日志采集和分析场景中,适当设置Logstash和Elasticsearch的内存大小非常重要.这 ...