feat:
This commit is contained in:
parent
ba3c78baeb
commit
5e5a51425c
14
pom.xml
14
pom.xml
|
@ -160,6 +160,20 @@
|
|||
<artifactId>aspectjweaver</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MinIO -->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>8.5.7</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 文件处理 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.guwan.backend.config;
|
||||
|
||||
import io.minio.MinioClient;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "minio")
|
||||
public class MinioConfig {
|
||||
|
||||
private String endpoint;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private Bucket bucket;
|
||||
|
||||
@Data
|
||||
public static class Bucket {
|
||||
private String files;
|
||||
private String images;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MinioClient minioClient() {
|
||||
return MinioClient.builder()
|
||||
.endpoint(endpoint)
|
||||
.credentials(accessKey, secretKey)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package com.guwan.backend.util;
|
||||
|
||||
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.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MinioUtil {
|
||||
|
||||
private final MinioClient minioClient;
|
||||
|
||||
/**
|
||||
* 创建存储桶
|
||||
*/
|
||||
public void createBucket(String bucketName) {
|
||||
try {
|
||||
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||
if (!found) {
|
||||
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("创建存储桶失败", e);
|
||||
throw new RuntimeException("创建存储桶失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
public String uploadFile(String bucketName, MultipartFile file) {
|
||||
try {
|
||||
String fileName = generateFileName(file.getOriginalFilename());
|
||||
InputStream inputStream = file.getInputStream();
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(fileName)
|
||||
.stream(inputStream, file.getSize(), -1)
|
||||
.contentType(file.getContentType())
|
||||
.build()
|
||||
);
|
||||
return fileName;
|
||||
} catch (Exception e) {
|
||||
log.error("上传文件失败", e);
|
||||
throw new RuntimeException("上传文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传Base64图片
|
||||
*/
|
||||
public String uploadBase64Image(String bucketName, String base64Image, String folder) {
|
||||
try {
|
||||
String[] parts = base64Image.split(",");
|
||||
String imageData = parts[1];
|
||||
byte[] bytes = Base64.getDecoder().decode(imageData);
|
||||
|
||||
String fileName = folder + "/" + UUID.randomUUID() + ".jpg";
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
|
||||
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(fileName)
|
||||
.stream(inputStream, bytes.length, -1)
|
||||
.contentType("image/jpeg")
|
||||
.build()
|
||||
);
|
||||
return fileName;
|
||||
} catch (Exception e) {
|
||||
log.error("上传Base64图片失败", e);
|
||||
throw new RuntimeException("上传Base64图片失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*/
|
||||
public void deleteFile(String bucketName, String fileName) {
|
||||
try {
|
||||
minioClient.removeObject(
|
||||
RemoveObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(fileName)
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("删除文件失败", e);
|
||||
throw new RuntimeException("删除文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除文件
|
||||
*/
|
||||
public void deleteFiles(String bucketName, List<String> fileNames) {
|
||||
try {
|
||||
List<DeleteObject> objects = fileNames.stream()
|
||||
.map(DeleteObject::new)
|
||||
.toList();
|
||||
|
||||
Iterable<Result<DeleteError>> results = minioClient.removeObjects(
|
||||
RemoveObjectsArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.objects(objects)
|
||||
.build()
|
||||
);
|
||||
|
||||
for (Result<DeleteError> result : results) {
|
||||
DeleteError error = result.get();
|
||||
log.error("删除文件失败: {}", error.message());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("批量删除文件失败", e);
|
||||
throw new RuntimeException("批量删除文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件访问URL
|
||||
*/
|
||||
public String getFileUrl(String bucketName, String fileName) {
|
||||
try {
|
||||
return minioClient.getPresignedObjectUrl(
|
||||
GetPresignedObjectUrlArgs.builder()
|
||||
.method(Method.GET)
|
||||
.bucket(bucketName)
|
||||
.object(fileName)
|
||||
.expiry(7, TimeUnit.DAYS)
|
||||
.build()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("获取文件访问URL失败", e);
|
||||
throw new RuntimeException("获取文件访问URL失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件名
|
||||
*/
|
||||
private String generateFileName(String originalFilename) {
|
||||
String extension = FilenameUtils.getExtension(originalFilename);
|
||||
return UUID.randomUUID() + "." + extension;
|
||||
}
|
||||
}
|
|
@ -74,9 +74,14 @@ jwt:
|
|||
aliyun:
|
||||
sms:
|
||||
|
||||
|
||||
|
||||
|
||||
# MinIO配置
|
||||
minio:
|
||||
endpoint: http://localhost:9000
|
||||
accessKey: minioadmin
|
||||
secretKey: minioadmin
|
||||
bucket:
|
||||
files: files # 文件桶
|
||||
images: images # 图片桶
|
||||
|
||||
# 文件上传配置
|
||||
file:
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package com.guwan.backend.util;
|
||||
|
||||
import com.guwan.backend.config.MinioConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
class MinioUtilTest {
|
||||
|
||||
@Autowired
|
||||
private MinioUtil minioUtil;
|
||||
|
||||
@Autowired
|
||||
private MinioConfig minioConfig;
|
||||
|
||||
@Test
|
||||
void testUploadAndDeleteFile() {
|
||||
// 创建测试文件
|
||||
String content = "test content";
|
||||
MockMultipartFile file = new MockMultipartFile(
|
||||
"test.txt",
|
||||
"test.txt",
|
||||
"text/plain",
|
||||
content.getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
|
||||
// 上传文件
|
||||
String fileName = minioUtil.uploadFile(minioConfig.getBucket().getFiles(), file);
|
||||
assertNotNull(fileName);
|
||||
|
||||
// 获取文件URL
|
||||
String url = minioUtil.getFileUrl(minioConfig.getBucket().getFiles(), fileName);
|
||||
assertNotNull(url);
|
||||
assertTrue(url.contains(fileName));
|
||||
|
||||
// 删除文件
|
||||
minioUtil.deleteFile(minioConfig.getBucket().getFiles(), fileName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUploadBase64Image() {
|
||||
// 创建Base64图片
|
||||
String base64Image = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=";
|
||||
|
||||
// 上传图片
|
||||
String fileName = minioUtil.uploadBase64Image(
|
||||
minioConfig.getBucket().getImages(),
|
||||
base64Image,
|
||||
"test"
|
||||
);
|
||||
assertNotNull(fileName);
|
||||
|
||||
// 获取图片URL
|
||||
String url = minioUtil.getFileUrl(minioConfig.getBucket().getImages(), fileName);
|
||||
assertNotNull(url);
|
||||
assertTrue(url.contains(fileName));
|
||||
|
||||
// 删除图片
|
||||
minioUtil.deleteFile(minioConfig.getBucket().getImages(), fileName);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue