Minio是用来存储文件的服务,代替FastDFS,和阿里云OSS差不多,本文介绍搭建和工具类
version: '3.1'
services:
minio:
image: minio/minio
container_name: minio
restart: always
ports:
- 9000:9000
command: server /data # 指定容器中的目录/data
environment:
MINIO_ACCESS_KEY: minio # 管理后台用户名,最小3个字符
MINIO_SECRET_KEY: minioxxx # 密码,最小8个字符
volumes:
- ./data:/data
- ./config:/root/.minio/
启动后,访问IP:9000,输入access key和secret key登录
点击右下角+号,选择Create bucket,输入存储桶的名称,创建成功后在左边会显示新创建的存储桶
默认情况下这个存储桶中的文件外部访问不了,需要修改策略,点击上图的三个小点,选择Edit policy,
输入*号,选择Read Only,点击Add即可,到这里Minio配置完毕
下面提供工具类,可以在Minio官网上找到各种常用语言的SDK
Setting类
@Data
public class MinioSetting {
private String accessKey;
private String secretKey;
private String bucket;
private String host;
private Integer port;
private Boolean ssl;
}
Config类
@Configuration
public class MinioConfig {
@Bean
@ConfigurationProperties(prefix = "minio")
public MinioSetting minioSetting() {
return new MinioSetting();
}
}
工具类
public class MinioUtil {
@Autowired
private MinioSetting setting;
private static String bucketName;
private static MinioClient client;
private static Map<String, String> contentTypes;
@PostConstruct
private void init() {
client = MinioClient.builder()
.endpoint(setting.getHost(), setting.getPort(), setting.getSsl())
.credentials(setting.getAccessKey(), setting.getSecretKey())
.build();
bucketName = setting.getBucket();
contentTypes = new HashMap<>(20);
contentTypes.put("html", "text/html");
contentTypes.put("htm", "text/html");
contentTypes.put("txt", "text/plain");
contentTypes.put("xml", "text/xml");
contentTypes.put("gif", "image/gif");
contentTypes.put("jpeg", "image/jpeg");
contentTypes.put("jpg", "image/jpeg");
contentTypes.put("png", "image/png");
contentTypes.put("json", "application/json");
contentTypes.put("pdf", "application/pdf");
contentTypes.put("mp4", "video/mp4");
}
/**
* 上传文件
* @param key
* @param is
* @param size
* @throws Exception
*/
public static void put(String key, InputStream is, long size) throws Exception {
PutObjectArgs args = PutObjectArgs.builder()
.bucket(bucketName)
.object(key)
.stream(is, size, -1)
.contentType(getContentType(key))
.build();
client.putObject(args);
}
/**
* 获取文件meta信息,返回null就表示文件不存在
* @param key
* @return
* @throws Exception
*/
public static ObjectStat stat(String key) throws Exception {
StatObjectArgs args = StatObjectArgs.builder()
.bucket(bucketName)
.object(key)
.build();
try {
return client.statObject(args);
} catch (ErrorResponseException e) {
return null;
} catch (Exception e) {
throw e;
}
}
/**
* 获取指定文件内容
* @param key
* @return
* @throws Exception
*/
public static byte[] get(String key) throws Exception {
GetObjectArgs args = GetObjectArgs.builder()
.bucket(bucketName)
.object(key)
.build();
InputStream is = client.getObject(args);
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int n = 0;
while (-1 != (n = is.read(buffer))) {
os.write(buffer, 0, n);
}
is.close();
return os.toByteArray();
}
/**
* 删除指定文件
* @param key
* @throws Exception
*/
public static void remove(String key) throws Exception {
RemoveObjectArgs args = RemoveObjectArgs.builder()
.bucket(bucketName)
.object(key)
.build();
client.removeObject(args);
}
/**
* 删除多个文件
* @param keys
* @return
* @throws Exception
*/
public static Iterable<Result<DeleteError>> remove(List<String> keys) throws Exception {
List<DeleteObject> objects = new LinkedList<>();
keys.forEach(it -> {
objects.add(new DeleteObject(it));
});
RemoveObjectsArgs args = RemoveObjectsArgs.builder()
.bucket(bucketName)
.objects(objects)
.build();
return client.removeObjects(args);
}
/**
* 获取contentType
* @param key
* @return
*/
public static String getContentType(String key) {
String ext = StringUtils.getFileExt(key);
if (contentTypes.containsKey(ext)) {
return contentTypes.get(ext);
}
return "application/octet-stream";
}
public static String getUploadUrl(String ext) {
StringBuilder sb = new StringBuilder();
sb.append("group/");
sb.append(TimeUtils.format(new Date(), "yyyy-MM")).append("/");
sb.append(StringUtils.randomNumberAndString(30)).append(".").append(ext);
return sb.toString();
}
}