springboot如何整合minio呢?
下文笔者讲述SpringBoot中整合minio的方法及示例分享,如下所示
SpringBoot整合minio的实现思路
1.添加依赖 2.设置相应的配置文件 3.编写minio配置类 4.编写minio工具类 5.编写控制器代码例:SpringBoot使用minio的示例
第一步:添加依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
</dependency>
第二步:application.yml配置
spring:
# 配置文件上传大小限制
servlet:
multipart:
max-file-size: 200MB
max-request-size: 200MB
minio:
endpoint: http://127.0.0.1:9005
accessKey: minioadmin
secretKey: minioadmin
bucketName: java265-simple
第三步:编写minio配置类
@Configuration
public class MinioClientConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
/**
* 注入minio 客户端
* @return
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
第四步:minio工具类
@Slf4j
@Component
public class MinioUtil {
@Resource
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
桶操作 /
/**
* 查看bucket是否存在
* @return boolean
*/
public boolean bucketExists(String bucketName) {
try {
return minioClient.bucketExists(BucketExistsArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
log.error("查看bucket是否存在", e);
return false;
}
}
/**
* 创建存储bucket
* @return Boolean
*/
public boolean createBucket(String bucketName) {
if (bucketExists(bucketName)) {
return true;
}
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
return true;
} catch (Exception e) {
log.error("创建桶失败", e);
return false;
}
}
/**
* 删除存储bucket
*
* @return boolean
*/
public boolean removeBucket(String bucketName) {
if (!bucketExists(bucketName)) {
return true;
}
//获取桶中所有的对象
list<Item> items = getBucketObjects(bucketName);
if (items.size() > 0) {
//有对象文件,则删除失败
return false;
}
try {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
return true;
} catch (Exception e) {
log.error("根据名称删除桶失败", e);
return false;
}
}
/**
* 获取存储桶策略
*
* @param bucketName 存储桶名称
* @return json
*/
public String getBucketPolicy(String bucketName) {
String bucketPolicy = null;
try {
bucketPolicy = minioClient.getBucketPolicy(GetBucketPolicyArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
log.error("获取存储桶策略失败", e);
}
return bucketPolicy;
}
/**
* 根据bucketName获取信息
*
* @param bucketName bucket名称
*
* return 如果不存在返回null
*/
public Bucket getBucket(String bucketName) {
try {
return minioClient.listBuckets()
.stream()
.filter(b -> b.name().equals(bucketName))
.findFirst()
.orElse(null);
} catch (Exception e) {
log.error("根据bucketName获取桶信息", e);
}
return null;
}
/**
* 获取全部bucket
*/
public List<Bucket> getAllBuckets() {
try {
return minioClient.listBuckets();
} catch (Exception e) {
log.error("获取所有的桶信息", e);
}
return null;
}
/**
* 创建文件夹或目录
*
* @param directoryName 目录路径
*/
public boolean createDirectory(String bucketName, String directoryName) {
if (!bucketExists(bucketName)) {
createBucket(bucketName);
}
try {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(directoryName)
.stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
.build());
return true;
} catch (Exception e) {
log.error("创建文件夹或目录失败", e);
return false;
}
}
/ 文件操作 ///
/**
* 判断文件是否存在
*
* @param bucketName 存储桶
* @param objectName 对象
* @return 存在返回true,不存在发生异常返回false
*/
public boolean objectExist(String bucketName, String objectName) {
if (!bucketExists(bucketName)) {
return false;
}
try {
minioClient.statObject(StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
return true;
} catch (Exception e) {
log.error("判断文件是否存在失败", e);
return false;
}
}
/**
* 判断文件夹是否存在【注意是文件夹而不是目录】
* @param folderName 文件夹名称(去掉前后的/)
* @return
*/
public boolean folderExist(String bucketName, String folderName) {
if (!bucketExists(bucketName)) {
return false;
}
try {
Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(folderName)
.recursive(false)
.build());
if (results != null) {
for (Result<Item> result : results) {
Item item = result.get();
folderName += "/";
if (item.isDir() && folderName.equals(item.objectName())) {
return true;
}
}
}
} catch (Exception e) {
log.error("判断文件夹是否存在失败", e);
return false;
}
return false;
}
/**
* 文件上传
* @param multipartFile 待上传文件
* @param folderName 目录
* @param aimFileName 最终保存到minio中的文件名,不需要后缀
* @return
*/
public String putObject(String bucketName, MultipartFile multipartFile, String folderName, String aimFileName) {
if (!bucketExists(bucketName)) {
createBucket(bucketName);
}
if (!StringUtils.hasText(aimFileName)) {
aimFileName = UUID.randomUUID().toString();
}
//获取文件后缀
String originalFilename = multipartFile.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
aimFileName += suffix;
//带路径的文件名
String lastFileName = "";
if (StringUtils.hasText(folderName)) {
lastFileName = "/" + folderName + "/" + aimFileName;
} else {
lastFileName = aimFileName;
}
try (InputStream inputStream = multipartFile.getInputStream();) {
//上传文件到指定目录,文件名称相同会覆盖
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(lastFileName)
.stream(inputStream, multipartFile.getSize(), -1)
.contentType(multipartFile.getContentType())
.build());
return getObjectUrl(bucketName, lastFileName);
} catch (Exception e) {
log.error("文件上传失败", e);
return null;
}
}
/**
* 上传文件【不指定文件夹】
* @param multipartFile
* @param fileName
* @return
*/
public String putObject(String bucketName, MultipartFile multipartFile, String fileName) {
return putObject(bucketName, multipartFile, null, fileName);
}
/**
* 上传文件【不指定文件夹,不指定目标文件名】
* @param multipartFile
* @return
*/
public String putObject(String bucketName, MultipartFile multipartFile) {
return putObject(bucketName, multipartFile, null, null);
}
/**
* 自动创建桶并存储文件
*
* @param inputStream
* @param aimFileName 必须,minio桶中文件的名字,需要带后缀
* @return
*/
public String putObject(String bucketName, InputStream inputStream, String aimFileName) {
if (!bucketExists(bucketName)) {
createBucket(bucketName);
}
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(aimFileName)
.stream(inputStream, inputStream.available(), -1)
.build();
minioClient.putObject(putObjectArgs);
inputStream.close();
return getObjectUrl(bucketName, aimFileName);
} catch (Exception e) {
log.error("文件上传失败", e);
return null;
}
}
/**
* 拷贝文件
*
* @param bucketName bucket名称
* @param objectName 文件名称
* @param srcBucketName 目标bucket名称
* @param srcObjectName 目标文件名称
*/
public boolean copyObject(String srcBucketName, String srcObjectName, String bucketName, String objectName) {
try {
minioClient.copyObject(
CopyObjectArgs.builder()
.source(CopySource.builder()
.bucket(srcBucketName)
.object(srcObjectName)
.build())
.bucket(bucketName)
.object(objectName)
.build());
return true;
} catch (Exception e) {
log.error("拷贝文件失败", e);
return false;
}
}
/**
* 文件下载
* @param fileName 文件名称
* @param response response
* @return Boolean
*/
public void getObject(String bucketName, String fileName, HttpServletResponse response) {
if (!bucketExists(bucketName)) {
return;
}
GetObjectArgs getObjectArgs = GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build();
try (ServletOutputStream outputStream = response.getOutputStream();
GetObjectResponse objectResponse = minioClient.getObject(getObjectArgs)) {
response.setCharacterEncoding("utf-8");
//设置强行下载不打开
//response.setContentType("application/force-download");
//response.setContentType("APPLICATION/OCTET-STREAM");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
ByteStreams.copy(objectResponse, outputStream);
outputStream.flush();
} catch (Exception e) {
log.error("文件下载失败", e);
}
}
/**
* 以流的形式获取一个文件对象
*
* @param objectName 对象名称
* @return {@link InputStream}
*/
public InputStream getObject(String bucketName, String objectName) {
if (!bucketExists(bucketName)) {
return null;
}
try {
StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
if (statObjectResponse.size() > 0) {
// 获取objectName的输入流。
return minioClient.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
}
} catch (Exception e) {
log.error("文件下载失败", e);
}
return null;
}
/**
* 获取文件信息, 如果抛出异常则说明文件不存在
*
* @param objectName 文件名称
*/
public StatObjectResponse getObjectInfo(String bucketName, String objectName) {
if (!bucketExists(bucketName)) {
return null;
}
StatObjectResponse statObjectResponse = null;
try {
statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
} catch (Exception e) {
log.error("获取文件信息失败", e);
}
return statObjectResponse;
}
/**
* 获取图片的路径
*
* @param fileName
* @return
*/
public String getObjectUrl(String bucketName, String fileName) {
try {
if (fileName.startsWith("/")) {
fileName = fileName.substring(1);
}
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.method(Method.GET)
//过期时间(分钟数)
.expiry(60 * 60)
.build();
return minioClient.getPresignedObjectUrl(build);
} catch (Exception e) {
log.error("获取文件路径失败", e);
}
return null;
}
/**
* 断点下载
*
* @param objectName 文件名称
* @param offset 起始字节的位置
* @param length 要读取的长度
* @return 流
*/
public InputStream getObject(String bucketName, String objectName, long offset, long length) {
if (!bucketExists(bucketName)) {
return null;
}
GetObjectResponse objectResponse = null;
try {
objectResponse = minioClient.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.offset(offset)
.length(length)
.build());
} catch (Exception e) {
e.printStackTrace();
}
return objectResponse;
}
/**
* 获取指定桶中的所有文件对象
*
* @return 存储bucket内文件对象信息
*/
public List<Item> getBucketObjects(String bucketName) {
if (!bucketExists(bucketName)) {
return null;
}
List<Item> items = new ArrayList<>();
Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.build());
if (results != null) {
try {
for (Result<Item> result : results) {
items.add(result.get());
}
} catch (Exception e) {
log.error("获取指定桶中的所有文件对象", e);
}
}
return items;
}
/**
* 获取路径下文件列表
*
* @param prefix 路径名称
* @param recursive 是否递归查找,如果是false,就模拟文件夹结构查找
* @return 二进制流
*/
public Iterable<Result<Item>> getObjects(String bucketName, String prefix, boolean recursive) {
if (!bucketExists(bucketName)) {
return null;
}
Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.build());
return results;
}
/**
* 根据文件前置查询文件
*
* @param prefix 前缀
* @param recursive 是否递归查询
* @return MinioItem 列表
*/
public List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
if (!bucketExists(bucketName)) {
return null;
}
List<Item> items = new ArrayList<>();
Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.build());
if (objectsIterator != null) {
try {
for (Result<Item> o : objectsIterator) {
Item item = o.get();
items.add(item);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return items;
}
/**
* 删除文件
* @param fileName 文件名
* @return
* @throws Exception
*/
public boolean removeObject(String bucketName, String fileName) {
if (!bucketExists(bucketName)) {
return false;
}
try {
minioClient.removeObject(RemoveObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
return true;
} catch (Exception e) {
log.error("根据文件删除文件失败", e);
return false;
}
}
/**
* 批量删除文件对象【没有测试成功】
* @param objects 需要删除的文件列表
*/
public boolean removeObjects(String bucketName, String... objects) {
if (!bucketExists(bucketName)) {
return false;
}
List<DeleteObject> deleteObjects = new LinkedList<>();
Arrays.stream(objects).forEach(s -> {
deleteObjects.add(new DeleteObject(s));
});
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder()
.bucket(bucketName)
.objects(deleteObjects)
.build());
//Minio处理批量删除的时候, 采用的延迟执行, 需要通过迭代返回的Iterable<Result<DeleteError>>以执行删除
if (results != null) {
try {
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
log.error("Error in deleting object " + error.objectName() + "; " + error.message());
}
} catch (Exception e) {
log.error("批量删除文件失败", e);
}
}
return true;
}
}
第五步:Controller编写
@RestController
@RequestMapping("/minio")
public class MinioController {
@Resource
private MinioUtil minioUtil;
/**
* 添加桶
*/
@GetMapping(value = "/create/{bucketName}")
public String create(@PathVariable("bucketName") String bucketName) {
minioUtil.createBucket(bucketName);
return "创建成功";
}
/**
* 检查桶是否存在
*/
@GetMapping(value = "/exist/{bucketName}")
public String exist(@PathVariable("bucketName") String bucketName) {
boolean exists = minioUtil.bucketExists(bucketName);
return "存在:" + exists;
}
/**
* 删除桶
*/
@GetMapping(value = "/remove/{bucketName}")
public String remove(@PathVariable("bucketName") String bucketName) {
boolean res = minioUtil.removeBucket(bucketName);
return "删除:" + res;
}
/**
* 获取所有的桶
* @return
*/
@GetMapping(value = "/getAllBuckets")
public List<Bucket> getAllBuckets() {
List<Bucket> allBuckets = minioUtil.getAllBuckets();
return allBuckets;
}
/**
* 上传图片,直接上传的跟目录
* @param file
* @return
*/
@PostMapping("/upload1")
public String upload1(MultipartFile file) {
if (file.isEmpty() || file.getSize() == 0) {
return "文件为空";
}
try {
String newName = "";
String fileUrl = minioUtil.putObject("java265-simple", file, newName);
return fileUrl;
} catch (Exception e) {
e.printStackTrace();
return "上传失败";
}
}
/**
* 上传图片,指定上传到的目录及重命名
* @param file
* @return
*/
@PostMapping("/upload2")
public String upload2(MultipartFile file) {
if (file.isEmpty() || file.getSize() == 0) {
return "文件为空";
}
try {
String newName = "静静";
String fileUrl = minioUtil.putObject("java265-simple", file, "haha/xixi", newName);
return fileUrl;
} catch (Exception e) {
e.printStackTrace();
return "上传失败";
}
}
/**
* 获取图片的路径【带问号后面的内容】
* @param filename
* @return
*/
@GetMapping("/get1/{filename}")
public String getPic1(@PathVariable("filename") String filename) {
String fileUrl = minioUtil.getObjectUrl("java265-info",filename);
return fileUrl;
}
/**
* 获取图片的路径【不带问号后面的坐标】
* @param filename
* @return
*/
@GetMapping("/get2/{filename}")
public String getPic2(@PathVariable("filename") String filename) {
String fileUrl = minioUtil.getObjectUrl("java265-info",filename);
fileUrl = fileUrl.substring(0, fileUrl.indexOf("?"));
return fileUrl;
}
/**
* 删除图片【不带路径】 localhost/java265/minio/delete1/lisi.jpg
* @param filename
* @return
*/
@DeleteMapping("/delete1/{filename}")
public String delete1(@PathVariable("filename") String filename) {
boolean remove = minioUtil.removeObject("java265-simple",filename);
return remove ? "删除成功" : "失败";
}
/**
* 删除图片【带路径】 localhost/java265/minio/delete2?filename=aa/lisi.jpg
* @param filename
* @return
*/
@DeleteMapping("/delete2")
public String delete2(String filename) {
boolean remove = minioUtil.removeObject("java265-simple",filename);
return remove ? "删除成功" : "失败";
}
/**
* 批量删除,localhost/java265/minio/delete3?filename=aa.jpg&filename=bb.jpg
* @param filename
* @return
*/
@DeleteMapping("/delete3")
public String delete3(String... filename) {
boolean remove = minioUtil.removeObjects("java265-simple",filename);
return remove ? "删除成功" : "失败";
}
@GetMapping("/getBucketObjects")
public List<Item> getBucketObjects() {
List<Item> bucketObjects = minioUtil.getBucketObjects("java265-simple");
return bucketObjects;
}
/**
* 下载图片
* @param filename
*/
@GetMapping("/download/{filename}")
public void downloadPic(@PathVariable("filename") String filename) {
InputStream is = minioUtil.getObject("java265-simple",filename);
byte[] buffer = new byte[1024];
int len = -1;
try {
FileOutputStream fos = new FileOutputStream("aa32.jpg");
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 下载图片
* @param filename
*/
@GetMapping("/download2/{filename}")
public void downloadPic2(@PathVariable("filename") String filename, HttpServletResponse response) {
minioUtil.getObject("java265-simple",filename, response);
}
}
第六步:启动项目 测试Controller
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


