简介
MinIO Java Client SDK提供简单的API来访问任何与Amazon S3兼容的对象存储服务。
官方demo: https://github.com/minio/minio-java
官方文档:https://docs.min.io/docs/java-client-api-reference.html
普通Java集成
第一步
引入pom.xml依赖。
<!-- MinIO 依赖 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
第二步
测试类:
package com.example.demo.minio;
import io.minio.*;
import io.minio.errors.MinioException;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* @author :Mall
* @date :Created in 2021-11-24
* @description :
*/
public class FileUploader {
public static void main(String[] args) {
MinioClient minioClient =
MinioClient.builder()
.endpoint("http://127.0.0.1:9000")
.credentials("admin", "maluole123")
.build();
//upload(minioClient, "asiatrip", "C:\\Users\\Administrator\\Desktop\\个人物品\\测试文件\\b.jpg", "d.jpg");
downloadMinio(minioClient, "G://ddd.jpg", "asiatrip", "d.jpg");
}
/**
* 上传
*
* @param minioClient
*/
public static void upload(MinioClient minioClient, String bucketName, String source, String targetname) {
try {
// 如果不存在“asiatrip”存储桶,则生成“asiatrip”。
boolean found =
minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
// 创建一个 'asiatrip'存储桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} else {
System.out.println("Bucket 'asiatrip' already exists.");
}
// 将“c盘文件b.jpg”作为对象名“d.jpg”上传到'asiatrip'桶里
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(targetname)
.filename(source)
.build());
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException e) {
System.out.println("Error occurred: " + e);
}
}
/**
* 删除
*
* @param fileName
* @return
* @throws Exception
*/
public static void remove(MinioClient minioClient, String bucketName, String fileName) {
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 下载
*
* @return
*/
public static void downloadMinio(MinioClient minioClient, String savepath, String bucketName, String fileName) {
try {
InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
FileOutputStream fileOutputStream = new FileOutputStream(savepath);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
fileOutputStream.write(buf, 0, bytesRead);
fileOutputStream.flush();
}
fileOutputStream.close();
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
封装的Util工具类:
package com.example.demo.minio;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.*;
/**
* @author :Mall
* @date :Created in 2021-11-26
* @description :MinIO工具类
* <p>
* 为保证代码维护性,如需修改或使用遇到问题,请与作者联系。
* 支持MinIO 8.3.X
* </p>
*/
public class JavaMinIOUtil {
//MinIO的API请求地址
private final static String ENDPOINT = "http://192.168.1.86:90";
//用户名
private final static String USERNAME = "admin";
//密码
private final static String PASSWORD = "12345678";
//单例加载
private final static MinioClient minioClient = MinioClient.builder().endpoint(ENDPOINT).credentials(USERNAME, PASSWORD).build();
/**
* 创建桶,如果不存在则创建,存在跳过
*
* @param bucketName
*/
public static void createBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 获取桶列表
*
* @returnF
*/
public static List<Bucket> findBucketList() {
try {
return minioClient.listBuckets();
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 根据桶名称,获取对象列表
*
* @param bucketName 桶名称
* @param path 桶路径 .如 aaa文件夹则传入 aaa/
* @return
*/
public static List<Item> findObjectList(String bucketName, String path) {
try {
createBucket(bucketName);
Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(path).build());
Iterator<Result<Item>> iterator = myObjects.iterator();
List<Item> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next().get());
}
return list;
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 文件状态,可查看是否存在
*
* @param bucketName 桶名称
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public static StatObjectResponse getObjectState(String bucketName, String filePath) {
try {
createBucket(bucketName);
return minioClient.statObject(
StatObjectArgs.builder().bucket(bucketName).object(filePath).build());
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件
*
* @param bucketName 桶名称
* @param file 上传资源
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public static boolean upload(String bucketName, InputStream file, String filePath) {
try {
createBucket(bucketName);
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(filePath).stream(file, file.available(), -1).build());
return true;
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
}
}
/**
* 下载文件
*
* @param bucketName 桶名称
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public static InputStream download(String bucketName, String filePath) {
try {
createBucket(bucketName);
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build());
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 删除文件
*
* @param bucketName 桶名称
* @param filePath 资源名称
* @return
*/
public static boolean remove(String bucketName, String filePath) {
try {
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(filePath).build());
return true;
} catch (InvalidKeyException e) {
e.printStackTrace();
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
} catch (ErrorResponseException e) {
e.printStackTrace();
return false;
} catch (InvalidResponseException e) {
e.printStackTrace();
return false;
} catch (ServerException e) {
e.printStackTrace();
return false;
} catch (InsufficientDataException e) {
e.printStackTrace();
return false;
} catch (XmlParserException e) {
e.printStackTrace();
return false;
} catch (InternalException e) {
e.printStackTrace();
return false;
} catch (IOException ioException) {
ioException.printStackTrace();
return false;
}
}
/**
* 文件大小转换
*
* @param fileSize 文件大小,单位b
* @return
*/
private static String formatFileSize(long fileSize) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileSize == 0) {
return wrongSize;
}
if (fileSize < 1024) {
fileSizeString = df.format((double) fileSize) + " B";
} else if (fileSize < 1048576) {
fileSizeString = df.format((double) fileSize / 1024) + " KB";
} else if (fileSize < 1073741824) {
fileSizeString = df.format((double) fileSize / 1048576) + " MB";
} else {
fileSizeString = df.format((double) fileSize / 1073741824) + " GB";
}
return fileSizeString;
}
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream(new File("G:/a.jpg"));
//上传
//upload("bucket02", fileInputStream, "ccc.jpg");
//下载
//InputStream inputStream = download("bucket02", "ccc.jpg");
//IOUtils.copy(inputStream, new FileOutputStream(new File("G:/ddd.jpg")));
//删除
//remove("bucket02", "ccc.jpg");
//查看文件状态
//StatObjectResponse statObject = getObjectState("bucket02", "b.jpg");
//获取所有桶
//findBucketList().stream().forEach(item -> System.out.println(item.name()));
//获取桶根目录所有对象
//findObjectList("bucket02", "aaa/").stream().forEach(item -> System.out.println(item.objectName()));
}
}
SpringBoot集成
第一步
引入pom.xml依赖。
<!-- MinIO 依赖 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
第二步
配置application.yml文件
minio:
endpoint: http://192.168.1.86:90
username: admin
password: 12345678
bucketname: bucket02
第三步
增加MinIOConfig配置类。
package com.example.demo.minio;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author :Mall
* @date :Created in 2021-11-26
* @description :MinIO配置类
*/
@Configuration
public class MinIOConfig {
//MinIO的API地址
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.username}")
private String username;
@Value("${minio.password}")
private String password;
@Bean
public MinioClient minioClient() {
return MinioClient.builder().endpoint(endpoint).credentials(username, password).build();
}
}
第四步
增加MinIOUtil工具类
package com.example.demo.minio;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author :Mall
* @date :Created in 2021-11-26
* @description :MinIO工具类
* <p>
* 为保证代码维护性,如需修改或使用遇到问题,请与作者联系。
* 支持MinIO 8.3.X
* </p>
*/
@Component
public class MinIOUtil {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketname}")
private String bucketName;
/**
* 创建桶,如果不存在则创建,存在跳过
*/
public void createBucket() throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 获取桶列表
*
* @returnF
*/
public List<Bucket> findBucketList() {
try {
return minioClient.listBuckets();
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 根据桶名称,获取对象列表
*
* @param path 桶路径
* @return
*/
public List<Item> findObjectList(String path) {
try {
createBucket();
Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
Iterator<Result<Item>> iterator = myObjects.iterator();
List<Item> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next().get());
}
return list;
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 文件状态,可查看是否存在
*
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public StatObjectResponse getObjectState(String filePath) {
try {
createBucket();
return minioClient.statObject(
StatObjectArgs.builder().bucket(bucketName).object(filePath).build());
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件
*
* @param file 上传资源
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public boolean upload(InputStream file, String filePath) {
try {
createBucket();
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(filePath).stream(file, file.available(), -1).build());
return true;
} catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
}
}
/**
* 下载文件
*
* @param filePath 上传的资源路径,保护名称。如果是根目录,就是文件名称
* @return
*/
public InputStream download(String filePath) {
try {
createBucket();
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build());
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (ErrorResponseException e) {
e.printStackTrace();
return null;
} catch (InvalidResponseException e) {
e.printStackTrace();
return null;
} catch (ServerException e) {
e.printStackTrace();
return null;
} catch (InsufficientDataException e) {
e.printStackTrace();
return null;
} catch (XmlParserException e) {
e.printStackTrace();
return null;
} catch (InternalException e) {
e.printStackTrace();
return null;
} catch (IOException ioException) {
ioException.printStackTrace();
return null;
}
}
/**
* 删除文件
*
* @param filePath 资源名称
* @return
*/
public boolean remove(String filePath) {
try {
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(filePath).build());
return true;
} catch (InvalidKeyException e) {
e.printStackTrace();
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
} catch (ErrorResponseException e) {
e.printStackTrace();
return false;
} catch (InvalidResponseException e) {
e.printStackTrace();
return false;
} catch (ServerException e) {
e.printStackTrace();
return false;
} catch (InsufficientDataException e) {
e.printStackTrace();
return false;
} catch (XmlParserException e) {
e.printStackTrace();
return false;
} catch (InternalException e) {
e.printStackTrace();
return false;
} catch (IOException ioException) {
ioException.printStackTrace();
return false;
}
}
/**
* 文件大小转换
*
* @param fileSize 文件大小,单位b
* @return
*/
public String formatFileSize(long fileSize) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileSize == 0) {
return wrongSize;
}
if (fileSize < 1024) {
fileSizeString = df.format((double) fileSize) + " B";
} else if (fileSize < 1048576) {
fileSizeString = df.format((double) fileSize / 1024) + " KB";
} else if (fileSize < 1073741824) {
fileSizeString = df.format((double) fileSize / 1048576) + " MB";
} else {
fileSizeString = df.format((double) fileSize / 1073741824) + " GB";
}
return fileSizeString;
}
}
第五步
增加测试Controller实现功能。
package com.example.demo.controller;
import com.example.demo.minio.MinIOUtil;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.minio.StatObjectResponse;
import io.minio.messages.Bucket;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
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;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :Mall
* @date :Created in 2021-11-26
* @description :
*/
@RestController()
@RequestMapping("/minio")
public class MinIOController {
@Autowired
private MinIOUtil minIOUtil;
/**
* Bucket列表
*
* @return
*/
@RequestMapping("/bucketlist")
public List<Map<String, String>> bucketlist() {
List<Map<String, String>> list = new ArrayList<>();
minIOUtil.findBucketList().stream().forEach(item -> {
Map<String, String> map = new HashMap<>();
map.put("name", item.name());
map.put("date", item.creationDate().toString());
list.add(map);
});
return list;
}
/**
* 根据路径获取对象列表
*
* @param path
* @return
*/
@RequestMapping("/findObjectList")
public List<Map<String, String>> findObjectList(String path) {
List<Map<String, String>> list = new ArrayList<>();
minIOUtil.findObjectList(path).stream().forEach(item -> {
Map<String, String> map = new HashMap<>();
map.put("name", item.objectName());
map.put("size", minIOUtil.formatFileSize(item.size()));
list.add(map);
});
return list;
}
/**
* 上传文件
*/
@RequestMapping("/upload")
public void upload(@RequestParam(name = "file", required = false) MultipartFile[] file) throws IOException {
for (MultipartFile multipartFile : file) {
minIOUtil.upload(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
}
}
/**
* 下载文件
*/
@RequestMapping("/download")
public void download(HttpServletResponse response, String filename) throws IOException {
InputStream download = minIOUtil.download(filename);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
IOUtils.copy(download, response.getOutputStream());
}
/**
* 删除文件
*/
@RequestMapping("/remove")
public void remove(HttpServletResponse response, String filepath) throws IOException {
minIOUtil.remove(filepath);
}
}