initial commit
This commit is contained in:
45
public-common/yelink-minio-starter/pom.xml
Normal file
45
public-common/yelink-minio-starter/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.yelink.example</groupId>
|
||||
<artifactId>public-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>yelink-minio-starter</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.yelink.minio.configure;
|
||||
|
||||
import com.yelink.minio.properties.MinioConfig;
|
||||
import com.yelink.minio.service.MinioService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* MinioAutoconfigure.
|
||||
*
|
||||
* @author cwp
|
||||
* @date 2024-05-16 17:45
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({MinioConfig.class})
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class MinioAutoconfigure {
|
||||
|
||||
@Bean
|
||||
public MinioService minioService(MinioConfig minioConfig) {
|
||||
return new MinioService(minioConfig);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.yelink.minio.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* MinioConfig.
|
||||
* @author cwp
|
||||
* @date 2024-05-16 17:19
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "minio")
|
||||
@Data
|
||||
public class MinioConfig {
|
||||
|
||||
private String endpoint;
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String bucket;
|
||||
|
||||
private String applicationName;
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package com.yelink.minio.service;
|
||||
|
||||
import com.yelink.minio.properties.MinioConfig;
|
||||
import io.minio.CopyObjectArgs;
|
||||
import io.minio.CopySource;
|
||||
import io.minio.GetObjectArgs;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.PutObjectArgs;
|
||||
import io.minio.RemoveObjectArgs;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* MinioService.
|
||||
*
|
||||
* @author cwp
|
||||
* @date 2024-05-16 17:33
|
||||
*/
|
||||
@Slf4j
|
||||
public class MinioService {
|
||||
|
||||
private static final Map<String, String> MIME_TYPES = new HashMap<>();
|
||||
|
||||
static {
|
||||
MIME_TYPES.put("txt", "text/plain");
|
||||
MIME_TYPES.put("html", "text/html");
|
||||
MIME_TYPES.put("css", "text/css");
|
||||
MIME_TYPES.put("js", "application/javascript");
|
||||
MIME_TYPES.put("json", "application/json");
|
||||
MIME_TYPES.put("xml", "application/xml");
|
||||
MIME_TYPES.put("jpg", "image/jpeg");
|
||||
MIME_TYPES.put("jpeg", "image/jpeg");
|
||||
MIME_TYPES.put("png", "image/png");
|
||||
MIME_TYPES.put("gif", "image/gif");
|
||||
MIME_TYPES.put("bmp", "image/bmp");
|
||||
MIME_TYPES.put("pdf", "application/pdf");
|
||||
// 添加更多扩展名和 Content-Type 对应关系
|
||||
}
|
||||
|
||||
private final MinioConfig config;
|
||||
|
||||
private final SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
|
||||
private MinioClient client;
|
||||
|
||||
public MinioService(MinioConfig config) {
|
||||
this.config = config;
|
||||
try {
|
||||
client = MinioClient.builder().endpoint(config.getEndpoint())
|
||||
.credentials(config.getAccessKey(), config.getSecretKey()).build();
|
||||
} catch (Exception ex) {
|
||||
log.error("Minio 初始化失败!Trace:", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件扩展名获取 Content-Type 不使用MultipartFile.getContentType(),是因为它基于客户端传输的content_type,不一定准确.
|
||||
*
|
||||
* @param fileName 文件名,包含后缀
|
||||
* @return MIME 类型
|
||||
*/
|
||||
private String getContentType(String fileName) {
|
||||
String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||
return MIME_TYPES.getOrDefault(extension, "application/octet-stream");
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传.
|
||||
*
|
||||
* @param file 文件
|
||||
* @param path minio 远程路径
|
||||
* @return 公网访问 url
|
||||
*/
|
||||
public String upload(MultipartFile file, String path) throws Exception {
|
||||
String contentType;
|
||||
if (ObjectUtils.isEmpty(file.getOriginalFilename())) {
|
||||
contentType = file.getContentType();
|
||||
} else {
|
||||
contentType = getContentType(file.getOriginalFilename());
|
||||
}
|
||||
return upload(file, path, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传.
|
||||
*
|
||||
* @param file 文件
|
||||
* @param path minio 远程路径
|
||||
* @param contentType 文件类型
|
||||
* @return 公网访问 url
|
||||
*/
|
||||
public String upload(MultipartFile file, String path, String contentType) throws Exception {
|
||||
String filename = genPath(path, getExtension(file));
|
||||
return upload(file.getInputStream(), filename, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传.
|
||||
*
|
||||
* @param content 文件内容
|
||||
* @param fileExtension 后缀名
|
||||
* @return 内网访问 url
|
||||
*/
|
||||
public String upload(String content, String fileExtension) throws Exception {
|
||||
// 转换字符串为输入流
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
|
||||
// 构建对象名称
|
||||
String objectName = config.getApplicationName() + "/" + format.format(new Date()) + "." + fileExtension;
|
||||
return upload(inputStream, objectName, "text/plain");
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传.
|
||||
*
|
||||
* @param inputStream inputStream
|
||||
* @param objectName 文件名
|
||||
* @param contentType 文件类型
|
||||
* @return 内网访问 url
|
||||
* @throws Exception e
|
||||
*/
|
||||
public String upload(InputStream inputStream, String objectName, String contentType) throws Exception {
|
||||
try {
|
||||
PutObjectArgs args = PutObjectArgs.builder().contentType(contentType).object(objectName)
|
||||
.bucket(config.getBucket()).stream(inputStream, inputStream.available(), -1).build();
|
||||
client.putObject(args);
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
return config.getBucket() + "/" + objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据完整 URL 来移除 minio 服务器中的对象.
|
||||
*
|
||||
* @param url 例:<a href="http://127.0.0.1:9000/furniture/materials/20230315/7375e567-d771-46a7-bccf-bb48886ab3d2.png">...</a>
|
||||
*/
|
||||
public void removeObjectByUrl(String url) {
|
||||
removeObject(extractObjectName(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据对象名移除 minio 服务器中的对象.
|
||||
*
|
||||
* @param name 例:materials/20230315/7375e567-d771-46a7-bccf-bb48886ab3d2.png
|
||||
*/
|
||||
public void removeObject(String name) {
|
||||
try {
|
||||
RemoveObjectArgs args = RemoveObjectArgs.builder().bucket(config.getBucket()).object(name).build();
|
||||
client.removeObject(args);
|
||||
} catch (Exception e) {
|
||||
log.error("MinIO 文件删除错误", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象文件公网访问 url.
|
||||
*
|
||||
* @param filename 对象名称
|
||||
* @return 公网访问 url
|
||||
*/
|
||||
public String minioPublicUrl(String filename) {
|
||||
return config.getBucket() + "/" + filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成对象路径.
|
||||
*
|
||||
* @param basicPath 根路径
|
||||
* @param extension 文件扩展名
|
||||
* @return basicPath/yyyyMMdd/uuid.extension
|
||||
*/
|
||||
public String genPath(String basicPath, String extension) {
|
||||
return "iot/" + basicPath + extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的扩展名.
|
||||
*
|
||||
* @param file 文件
|
||||
* @return 例:.jpg
|
||||
*/
|
||||
public String getExtension(MultipartFile file) {
|
||||
return getExtension(Objects.requireNonNull(file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的扩展名.
|
||||
*
|
||||
* @param name 文件名称
|
||||
* @return 例:.jpg
|
||||
*/
|
||||
public String getExtension(String name) {
|
||||
return name.substring(name.lastIndexOf('.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件,用于受保护的 minio 服务器 此方法未测试.
|
||||
*/
|
||||
public String download(String object) {
|
||||
GetObjectArgs args = GetObjectArgs.builder().bucket(config.getBucket()).object(object).build();
|
||||
try {
|
||||
// 读取对象内容
|
||||
try (InputStream inputStream = client.getObject(args)) {
|
||||
// Read the input stream and print to the console till EOF.
|
||||
byte[] buf = new byte[16384];
|
||||
int bytesRead;
|
||||
StringBuilder content = new StringBuilder();
|
||||
while ((bytesRead = inputStream.read(buf, 0, buf.length)) >= 0) {
|
||||
String readContent = new String(buf, 0, bytesRead, StandardCharsets.UTF_8);
|
||||
content.append(readContent);
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("MinIO 文件下载错误:", ex);
|
||||
throw new RuntimeException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据url下载文件 此方法未测试.
|
||||
*/
|
||||
public String downloadByUrl(String url) {
|
||||
return download(extractObjectName(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 url 中的 minio 对象路径.
|
||||
*
|
||||
* @param url 例:<a href="http://127.0.0.1:9000/furniture/materials/20230315/7375e567-d771-46a7-bccf-bb48886ab3d2.png">...</a>
|
||||
* @return 例:/materials/20230315/7375e567-d771-46a7-bccf-bb48886ab3d2.png
|
||||
*/
|
||||
public String extractObjectName(String url) {
|
||||
return url.substring(minioPublicUrl("").length());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个对象拷贝到指定路径.
|
||||
*
|
||||
* @param objectName minio 中需要拷贝的对象
|
||||
* @param path minio 要拷贝到的路径
|
||||
* @return 拷贝后路径的公网访问 url
|
||||
*/
|
||||
public String copy(String objectName, String path) {
|
||||
String extension = getExtension(objectName);
|
||||
String targetObject = genPath(path, extension);
|
||||
CopyObjectArgs args = CopyObjectArgs.builder().bucket(config.getBucket()).object(targetObject)
|
||||
.source(CopySource.builder().bucket(config.getBucket()).object(objectName).build()).build();
|
||||
try {
|
||||
client.copyObject(args);
|
||||
} catch (Exception ex) {
|
||||
log.error("minIO 文件拷贝失败:", ex);
|
||||
throw new RuntimeException(ex.getMessage());
|
||||
}
|
||||
return minioPublicUrl(targetObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 url 拷贝.
|
||||
*
|
||||
* @see MinioService#copy(String, String)
|
||||
*/
|
||||
public String copyByUrl(String url, String path) {
|
||||
return copy(extractObjectName(url), path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.yelink.minio.configure.MinioAutoconfigure
|
||||
Reference in New Issue
Block a user