关于minio服务的安装这里就不过多介绍了,网上都有很多现场的案例,这里主要介绍我在项目中的集成,首先就是引入依赖
<!-- minio对象存储 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.0</version>
</dependency>
yml中配置minio相关配置
minio:
endpoint: http://127.0.0.1:9000
accessKey: ***
secretKey: ***
bucketName: account-dev
businessName: 1210Head
创建minio单例客户端
package com.yl.framework.config;
import io.minio.MinioClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* @author shg
* @date 2023/1/21 15:42
* @desc Minio单例客户端
*/
@Slf4j
@Configuration
public class MinioClientSingleton {
/**
* Minio服务端地址
*/
private static String endpoint;
/**
* Minio服务端账号
*/
private static String accessKey;
/**
* Minio服务端密码
*/
private static String secretKey;
@Value("${minio.endpoint}")
public void setEndpoint(String endpoint) {
MinioClientSingleton.endpoint = endpoint;
}
@Value("${minio.accessKey}")
public void setAccessKey(String accessKey) {
MinioClientSingleton.accessKey = accessKey;
}
@Value("${minio.secretKey}")
public void setSecretKey(String secretKey) {
MinioClientSingleton.secretKey = secretKey;
}
/**
* Minio客户端
*/
private static volatile MinioClient minioClient;
public MinioClientSingleton() {
}
/**
* 获取minio客户端实例
*
* @return {@link MinioClient}
*/
public static MinioClient getMinioClient() {
if (minioClient == null) {
synchronized (MinioClientSingleton.class) {
if (minioClient == null) {
minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
log.info("MinioClientSingleton#getMinioClient,endpoint={},accessKey={},secretKey={}",
endpoint, accessKey, secretKey);
}
}
}
return minioClient;
}
}
封装minio工具类:
package com.yl.framework.util;
import com.google.common.collect.Lists;
import com.yl.framework.config.MinioClientSingleton;
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.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author shg
* @date 2023/1/21 15:42
* @desc Minio客户端工具类
*/
@SuppressWarnings("ALL")
@Slf4j
public class MinioKit {
/**
* 判断存储桶是否存在
*
* @param bucketName 存储桶名称
* @return
*/
@SneakyThrows
public static boolean bucketExists(String bucketName) {
boolean found = false;
try {
found = MinioClientSingleton.getMinioClient().
bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
log.error("MinioKit#bucketExists,查询存储桶异常,bucketName={}", bucketName, e);
throw new RuntimeException("查询存储桶异常");
}
return found;
}
/**
* 创建存储桶
*
* @param bucketName 存储桶名称
* @return
*/
@SneakyThrows
public static boolean makeBucket(String bucketName) {
if (!bucketExists(bucketName)) {
MinioClientSingleton.getMinioClient().
makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
log.info("MinioKit#makeBucket,存储桶创建成功,bucketName={}", bucketName);
return true;
}
log.info("MinioKit#makeBucket,存储桶已存在,bucketName={}", bucketName);
return false;
}
/**
* 列出所有的存储桶
*
* @return
*/
@SneakyThrows
public static List<Bucket> listBuckets() {
return MinioClientSingleton.getMinioClient().listBuckets();
}
/**
* 列出所有存储桶名称
*
* @return
*/
@SneakyThrows
public static List<String> listBucketNames() {
return StreamKit.getList(listBuckets(), Bucket::name);
}
/**
* 删除一个存储桶
* 注意:只有存储桶为空时才能删除成功
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public static boolean removeBucket(String bucketName) {
// 删除之前先检查存储桶是否存在。
boolean found = bucketExists(bucketName);
if (found) {
Iterable<Result<Item>> myObjects = listObjects(bucketName);
for (Result<Item> result : myObjects) {
Item item = result.get();
// 有对象文件,则删除失败
if (item.size() > 0) {
return false;
}
}
// 删除存储桶,注意,只有存储桶为空时才能删除成功。
MinioClientSingleton.getMinioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
found = bucketExists(bucketName);
return !found;
}
return false;
}
/**
* 列出存储桶中的所有对象名称
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public static List<String> listObjectNames(String bucketName) {
List<String> listObjectNames = new ArrayList<>();
if (bucketExists(bucketName)) {
for (Result<Item> result : listObjects(bucketName)) {
listObjectNames.add(result.get().objectName());
}
}
return listObjectNames;
}
/**
* 列出存储桶中的所有对象(递归查询)
*
* @param bucketName 存储桶名称
*/
@SneakyThrows
public static Iterable<Result<Item>> listObjects(String bucketName) {
if (bucketExists(bucketName)) {
return MinioClientSingleton.getMinioClient().
listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(true).build());
}
return Lists.newArrayList();
}
/**
* 删除文件
*
* @param bucketName 存储桶名称
* @param objectName 对象名 (文件夹名+文件名)
* @return
*/
@SneakyThrows
public static boolean removeObject(String bucketName, String objectName) {
if (bucketExists(bucketName)) {
MinioClientSingleton.getMinioClient().
removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
return true;
}
return false;
}
/**
* 批量删除文件
*
* @param bucketName 存储桶名称
* @param objectNames 对象名(文件夹名+文件名)列表
* @return
*/
@SneakyThrows
public static boolean removeObjects(String bucketName, List<String> objectNames) {
if (bucketExists(bucketName)) {
// 转换对象
List<DeleteObject> objects = StreamKit.getList(objectNames, model -> {
return new DeleteObject(model);
});
MinioClientSingleton.getMinioClient().
removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
return true;
}
return false;
}
/**
* 以流的形式获取一个文件对象
*
* @param bucketName 存储桶名称
* @param objectName 对象名 (文件夹名+文件名)
* @return {@link InputStream}
*/
@SneakyThrows
public static InputStream getObjectInputStream(String bucketName, String objectName) {
if (bucketExists(bucketName)) {
ObjectStat objectStat = MinioClientSingleton.getMinioClient()
.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
if (objectStat!=null) {
// 获取objectName的输入流。
return MinioClientSingleton.getMinioClient()
.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
}
return null;
}
/**
* 获取某个桶下某个对象的URL
*
* @param bucketName 存储桶名称
* @param objectName 对象名 (文件夹名 + 文件名)
* @return
*/
@SneakyThrows
public static String getBucketObject(String bucketName, String objectName) {
if (bucketExists(bucketName)) {
return MinioClientSingleton.getMinioClient().getObjectUrl(bucketName, objectName);
}
return null;
}
/**
* 根据文件路径得到预览文件绝对地址
*
* @param bucketName 存储桶名称
* @param objectName 对象名 (文件夹名+文件名)
* @return
*/
@SneakyThrows
public static String getPreviewFileUrl(String bucketName, String objectName) {
if (bucketExists(bucketName)) {
return MinioClientSingleton.getMinioClient().getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.method(Method.GET)
.expiry(5, TimeUnit.DAYS)
.build());
}
return null;
}
/**
* 通过MultipartFile,上传文件
*
* @param bucketName 存储桶
* @param file 文件
* @param objectName 对象名
*/
public static void putObject(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception {
InputStream inputStream = file.getInputStream();
ObjectWriteResponse objectWriteResponse = MinioClientSingleton.getMinioClient().putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType)
.stream(
inputStream, inputStream.available(), -1)
.build());
String url = MinioClientSingleton.getMinioClient().getObjectUrl(bucketName, objectName); //文件访问路径
}
/**
* 上传本地文件
*
* @param bucketName 存储桶
* @param objectName 对象名称
* @param fileName 本地文件路径
*/
public static ObjectWriteResponse putObject(String bucketName, String objectName, String fileName) throws Exception {
return MinioClientSingleton.getMinioClient().uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());
}
/**
* 通过流上传文件
*
* @param bucketName 存储桶
* @param objectName 文件对象
* @param inputStream 文件流
*/
public static ObjectWriteResponse putObjectbyStream(String bucketName, String objectName, InputStream inputStream) throws Exception {
return MinioClientSingleton.getMinioClient().putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
inputStream, inputStream.available(), -1)
.build());
}
/**
* 创建文件夹或目录
*
* @param bucketName 存储桶
* @param objectName 目录路径
*/
public ObjectWriteResponse putDirObject(String bucketName, String objectName)
throws Exception {
return MinioClientSingleton.getMinioClient().putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
new ByteArrayInputStream(new byte[]{}), 0, -1)
.build());
}
}
定义文件上传、文件下载统一接口
package com.yl.web.controller.file;
import com.yl.common.core.domain.AjaxResult;
import com.yl.framework.util.MinioKit;
import com.yl.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Value;
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.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
/**
* minio文件操作相关接口
*
* @author shg
* @date 2022-07-14
*/
@RestController
@Slf4j
@RequestMapping("/file")
public class MinioFileOperateController {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.businessName}")
private String businessName;
@PostMapping("/upload")
public AjaxResult fileUpload(MultipartFile file) {
//避免重复,生成新的文件名
String originalFilename = file.getOriginalFilename();
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = originalFilename.substring(0, originalFilename.indexOf("."));
LocalDateTime now = LocalDateTime.now();
String newFileName = fileName + "_" + now.toInstant(ZoneOffset.of("+8")).toEpochMilli() + fileType;
//生成文件存储path:业务名 + /年/月/日/原文件名_时间搓.文件类型
String filePath = businessName + "/" + now.getYear() + "/" + String.format("%02d", now.getMonthValue()) + "/" + String.format("%02d", now.getDayOfMonth()) + "/";
try {
HashMap<String, String> resultMap = new HashMap<>();
MinioKit.putObject(bucketName, file,filePath + newFileName, fileType);
resultMap.put("oldFileName", fileName + "." + fileType);
resultMap.put("fileName", filePath + newFileName);
resultMap.put("previewFileUrl", endpoint + "/" + bucketName + "/" + (filePath + newFileName));
resultMap.put("url", MinioKit.getPreviewFileUrl(bucketName, filePath + newFileName));
log.info("result: {}", resultMap);
return AjaxResult.success(resultMap);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("上传失败: "+e.getMessage());
}
}
@GetMapping("/download")
public void fileDownload(HttpServletResponse response, String name) {
if (StringUtils.isBlank(name)) {
return;
}
ServletOutputStream ops = null;
InputStream objectInputStream = MinioKit.getObjectInputStream(bucketName, name);
try {
ops = response.getOutputStream();
IOUtils.copy(objectInputStream,ops);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ops.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
后端的整合封装完毕