一、使用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实现文件上传的更多相关文章

  1. minio实现文件上传下载和删除功能

    https://blog.csdn.net/tc979907461/article/details/106673570?utm_medium=distribute.pc_relevant_t0.non ...

  2. springCloud 微服务通过minio实现文件上传和文件下载接口

    直接上代码吧,好多文章的下载都写的不明不白的,让人理解错,气死了!! 文件上传功能 文件上传很简单,首先你得部署好minio,然后写好配置信息,我的是动态读取nacos上配置的yml @Autowir ...

  3. minio文件上传与下载

    目录 一.minio简介 二.minio安装 一.java中使用 一.minio简介 MinIO 是在 GNU Affero 通用公共许可证 v3.0 下发布的高性能对象存储. 它是与 Amazon ...

  4. UniApp文件上传(SpringBoot+Minio)

    UniApp文件上传(SpringBoot+Minio) 一.Uni文件上传 (1).文件上传的问题 UniApp文件上传文档 uni.uploadFile({ url: 'https://www.e ...

  5. 94、springboot+minio实现分片上传(超大文件快速上传)

    设计由来 在实际的项目开发中常遇到超大附件上传的情况,有时候客户会上传GB大小的文件,如果按照普通的MultipartFile方式来接收上传的文件,那么无疑会把服务器给干崩溃,更别说并发操作了.于是笔 ...

  6. Springboot 一行代码实现文件上传 20个平台!少写代码到极致

    大家好,我是小富~ 技术交流,公众号:程序员小富 又是做好人好事的一天,有个小可爱私下问我有没有好用的springboot文件上传工具,这不巧了嘛,正好我私藏了一个好东西,顺便给小伙伴们也分享一下,d ...

  7. jquery.uploadify文件上传组件

    1.jquery.uploadify简介 在ASP.NET中上传的控件有很多,比如.NET自带的FileUpload,以及SWFUpload,Uploadify等等,尤其后面两个控件的用户体验比较好, ...

  8. 11、Struts2 的文件上传和下载

    文件上传 表单准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设置 ...

  9. Java FtpClient 实现文件上传服务

    一.Ubuntu 安装 Vsftpd 服务 1.安装 sudo apt-get install vsftpd 2.添加用户(uftp) sudo useradd -d /home/uftp -s /b ...

  10. 小兔Java教程 - 三分钟学会Java文件上传

    今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...

随机推荐

  1. CodeForces-1324E-Sleeping-Schedule

    题意 \(Vova\)有一个睡眠时间表,一天有\(h\)小时,\(Vova\)会睡\(n\)次觉,一次睡一天,在第\(i-1\)次睡醒后,\(Vova\)在\(a_i\)或\(a_i-1\)个小时候可 ...

  2. [WPF]使用HLSL实现百叶窗动效

    百叶窗动画是制作PPT时常用的动画之一,本文将通过实现百叶窗动画效果的例子介绍在WPF中如何使用ShaderEffect.ShaderEffect是使用高级着色器语言(High Level Shadi ...

  3. 搭建企业知识库:基于 Wiki.js 的实践指南

    一.简介 在当今知识经济时代,企业知识库的建设变得越来越重要.它不仅有助于企业知识的沉淀和共享,还能提升员工的工作效率,促进企业的创新发展.企业知识库是企业中形成结构化文档,共享知识的集群,可以促进企 ...

  4. excel的烦恼

    Smiling & Weeping ---- 他未对我好半分,偏巧这感情疯长似野草 题目链接:https://www.matiji.net 思路:与新三进制2思路相似,转化为纯26进制,然后往 ...

  5. redisson分布式锁的应用——秒杀、超卖 简单例子(分布式锁相关)

    1.常见的分布式事务锁 1.数据库级别的锁 乐观锁,给予加入版本号实现 悲观锁,基于数据库的for update实现 2.Redis,基于SETNX.EXPIRE实现 3.Zookeeper,基于In ...

  6. Cplex求解教程(基于OPL语言,可作为大规模运算输入参考)

    最近导导让牛牛改篇论文,牛牛在她的指导下把非线性问题化成了线性.然鹅,化成线性后的模型决策变量和约束条件均达到上百甚至上千个,这让牛牛犯了难,以下方法或许能为这样大规模模型的变量和约束输入提供思路(๑ ...

  7. Nearest cluster-based intrusion detection through convolutional neural networks 笔记

    Nearest cluster-based intrusion detection through convolutional neural networks 技术要点 So, the primary ...

  8. 【Azure Function App】Python Function调用Powershell脚本在Azure上执行失败的案例

    问题描述 编写Python Function,并且在Function中通过 subprocess  调用powershell.exe 执行 powershell脚本. import azure.fun ...

  9. 创业团队建设与管理mooc【第二次中期测验】

    mo'o 第二次中期测验 返回 已经超过规定的测试次数或提交截止时间已过.你可以作为自我学习进行测验,但提交的结果将无法获得学分. 1 单选(2分) PDCA循环中的P是指什么? 得分/总分 A. 处 ...

  10. Decorator 装饰者模式简介与 C# 示例【结构型4】【设计模式来了_9】

    〇.简介 1.什么是装饰者模式 一句话解释:   通过继承统一的抽象类来新增操作,再在使用时通过链式添加到对象中,达到与原有设定无关联可灵活附加. 装饰者模式是一种行为设计模式,它允许向一个现有的对象 ...