Demo 地址:mingyue-springboot-minio
<dependency>
<groupId>io.miniogroupId>
<artifactId>minioartifactId>
<version>8.3.9version>
dependency>
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
<version>4.9.0version>
dependency>
minio:
endpoint: http://IP:9000
port: 9000
accessKey: 登录账号
secretKey: 登录密码
secure: false
bucket-name: mingyue-test # 桶名
image-size: 10485760 # 图片文件的最大大小
file-size: 1073741824 # 文件的最大大小
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* Minio 配置
*
* @author Strive
* @date 2022/4/25 10:20
* @description
*/
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioPropertiesConfig {
/** 服务地址 */
private String endpoint;
/** TCP/IP端口号 */
private Integer port;
/** 账户 */
private String accessKey;
/** 密码 */
private String secretKey;
/** 如果是 true,则用的是 https 而不是 http,默认值是 true" */
private boolean secure;
/** 存储桶 */
private String bucketName;
/** 图片的最大大小 */
private long imageSize;
/** 其他文件的最大大小 */
private long fileSize;
/** 初始化 MinIO 客户端 */
@Bean
public MinioClient minioClient() {
return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
}
}
import com.csp.mingyue.minio.config.MinioPropertiesConfig;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.ListObjectsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveBucketArgs;
import io.minio.RemoveObjectArgs;
import io.minio.RemoveObjectsArgs;
import io.minio.Result;
import io.minio.StatObjectArgs;
import io.minio.StatObjectResponse;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
/**
* Minio 工具类
*
* @author Strive
* @date 2022/4/25 10:24
* @description minio工具类
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtil {
private final MinioPropertiesConfig minioPropertiesConfig;
private final MinioClient minioClient;
/**
* 检查存储桶是否存在
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public boolean bucketExists(String bucketName) {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (found) {
log.info("{} exists", bucketName);
} else {
log.info("{} does not exist", bucketName);
}
return found;
}
/**
* 创建存储桶
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public boolean makeBucket(String bucketName) {
boolean flag = bucketExists(bucketName);
if (!flag) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
return true;
} else {
return false;
}
}
/** 列出所有存储桶名称 */
@SneakyThrows
public List<String> listBucketNames() {
List<Bucket> bucketList = listBuckets();
List<String> bucketListName = new ArrayList<>();
for (Bucket bucket : bucketList) {
bucketListName.add(bucket.name());
}
return bucketListName;
}
/** 列出所有存储桶 */
@SneakyThrows
public List<Bucket> listBuckets() {
return minioClient.listBuckets();
}
/**
* 删除存储桶
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public boolean removeBucket(String bucketName) {
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<Item>> myObjects = listObjects(bucketName);
for (Result<Item> result : myObjects) {
Item item = result.get();
// 有对象文件,则删除失败
if (item.size() > 0) {
return false;
}
}
// 删除存储桶,注意,只有存储桶为空时才能删除成功。
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
flag = bucketExists(bucketName);
return !flag;
}
return false;
}
/**
* 列出存储桶中的所有对象名称
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public List<String> listObjectNames(String bucketName) {
List<String> listObjectNames = new ArrayList<>();
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<Item>> myObjects = listObjects(bucketName);
for (Result<Item> result : myObjects) {
Item item = result.get();
listObjectNames.add(item.objectName());
}
} else {
listObjectNames.add("存储桶不存在");
}
return listObjectNames;
}
/**
* 列出存储桶中的所有对象
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public Iterable<Result<Item>> listObjects(String bucketName) {
boolean flag = bucketExists(bucketName);
if (flag) {
return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
}
return null;
}
/**
* 文件上传
*
* @param bucketName 桶名称
* @param multipartFile 上传的文件
*/
@SneakyThrows
public void putObject(
String bucketName, MultipartFile multipartFile, String filename, String fileType) {
InputStream inputStream = new ByteArrayInputStream(multipartFile.getBytes());
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(filename).stream(
inputStream, -1, minioPropertiesConfig.getFileSize())
.contentType(fileType)
.build());
}
/**
* 文件访问路径
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @return
*/
@SneakyThrows
public String getObjectUrl(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
String url = "";
if (flag) {
url =
minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(2, TimeUnit.MINUTES)
.build());
log.info("url:{}", url);
}
return url;
}
/**
* 删除一个对象
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
*/
@SneakyThrows
public boolean removeObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
return true;
}
return false;
}
/**
* 以流的形式获取一个文件对象
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
*/
@SneakyThrows
public InputStream getObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
StatObjectResponse statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.size() > 0) {
return minioClient.getObject(
GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
}
return null;
}
/**
* 获取对象的元数据
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
*/
@SneakyThrows
public StatObjectResponse statObject(String bucketName, String objectName) {
boolean flag = bucketExists(bucketName);
if (flag) {
return minioClient.statObject(
StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
return null;
}
/**
* 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表
*
* @param bucketName 存储桶名称
* @param objectNames 含有要删除的多个object名称的迭代器对象
*/
@SneakyThrows
public boolean removeObject(String bucketName, List<String> objectNames) {
boolean flag = bucketExists(bucketName);
if (flag) {
List<DeleteObject> objects = new LinkedList<>();
for (String objectName : objectNames) {
objects.add(new DeleteObject(objectName));
}
Iterable<Result<DeleteError>> results =
minioClient.removeObjects(
RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
log.info("Error in deleting object {}: {}", error.objectName(), error.message());
}
}
return true;
}
/**
* 以流的形式获取一个文件对象(断点下载)
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @param offset 起始字节的位置
* @param length 要读取的长度 (可选,如果无值则代表读到文件结尾)
*/
@SneakyThrows
public InputStream getObject(String bucketName, String objectName, long offset, Long length) {
boolean flag = bucketExists(bucketName);
if (flag) {
StatObjectResponse statObject = statObject(bucketName, objectName);
if (statObject != null && statObject.size() > 0) {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.offset(offset)
.length(length)
.build());
}
}
return null;
}
/**
* 通过InputStream上传对象
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @param inputStream 要上传的流
* @param contentType 要上传的文件类型 MimeTypeUtils.IMAGE_JPEG_VALUE
*/
@SneakyThrows
public boolean putObject(
String bucketName, String objectName, InputStream inputStream, String contentType) {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
inputStream, -1, minioPropertiesConfig.getFileSize())
.contentType(contentType)
.build());
StatObjectResponse statObject = statObject(bucketName, objectName);
return statObject != null && statObject.size() > 0;
}
return false;
}
}
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.csp.mingyue.minio.config.MinioPropertiesConfig;
import com.csp.mingyue.minio.util.MinioUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/**
* Minio 服务层
*
* @author Strive
* @date 2022/4/25 10:32
* @description Minio Service 层
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MinioService {
private final MinioPropertiesConfig minioPropertiesConfig;
private final MinioUtil minioUtil;
/**
* 检查存储桶是否存在
*
* @param bucketName 存储桶名称
*/
public boolean bucketExists(String bucketName) {
return minioUtil.bucketExists(bucketName);
}
/**
* 创建存储桶
*
* @param bucketName 存储桶名称
*/
public void makeBucket(String bucketName) {
minioUtil.makeBucket(bucketName);
}
/**
* 文件上传
*
* @param file 上传的文件
* @param bucketName 桶名称
* @param fileType 文件类型
*/
public String upload(MultipartFile file, String bucketName, String fileType) {
if (StrUtil.isBlank(bucketName)) {
log.info("bucketName is null");
}
try {
if (!this.bucketExists(bucketName)) {
this.makeBucket(bucketName);
}
String fileName = file.getOriginalFilename();
assert fileName != null;
String objectName =
IdUtil.randomUUID().replace("-", "") + fileName.substring(fileName.lastIndexOf("."));
minioUtil.putObject(bucketName, file, objectName, fileType);
return minioPropertiesConfig.getEndpoint() + "/" + bucketName + "/" + objectName;
} catch (Exception e) {
e.printStackTrace();
return "上传失败";
}
}
/**
* 获取文件路径
*
* @param bucketName 桶名称
* @param objectName 对象名称
*/
public String getObjectUrl(String bucketName, String objectName) {
return minioUtil.getObjectUrl(bucketName, objectName);
}
}
import com.csp.mingyue.minio.config.MinioPropertiesConfig;
import com.csp.mingyue.minio.service.MinioService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
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;
/**
* Minio 接口
*
* @author Strive
* @date 2022/4/25 10:48
* @description
*/
@RestController
@RequestMapping("/minio")
@RequiredArgsConstructor
public class MinioController {
private final MinioPropertiesConfig minioPropertiesConfig;
private final MinioService minioService;
@PostMapping("/upload")
public String upload(@RequestParam(name = "multipartFile") MultipartFile multipartFile) {
return minioService.upload(
multipartFile, minioPropertiesConfig.getBucketName(), multipartFile.getContentType());
}
@GetMapping("/getObjectUrl")
public String getObjectUrl(String objectName) {
return minioService.getObjectUrl(minioPropertiesConfig.getBucketName(), objectName);
}
}
Post http://127.0.0.1:8080/minio/upload 上传接口
接口返回如下:
http://ip:port/mingyue-test/60396cc92fec4e2cbb4a974d810e7115.jpg
Get http://127.0.0.1:8080/minio/getObjectUrl?objectName=60396cc92fec4e2cbb4a974d810e7115.jpg 查询接口
接口返回如下:
http://ip:port/mingyue-test/60396cc92fec4e2cbb4a974d810e7115.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20220425%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220425T055235Z&X-Amz-Expires=120&X-Amz-SignedHeaders=host&X-Amz-Signature=35eeffddca22f8211a1af0e936066e848a988e82b73548cfc87f2294e0861f01
只写了两个接口,想要查询桶列表或者其他功能具体看
MinioUtil
函数,主要可以参考如下文档: