新增对象存储上传接口
This commit is contained in:
parent
6440a1c97e
commit
d87266b3e2
@ -6,6 +6,7 @@
|
||||
| 1.0.0 | 2025-06-05 | Luke.Ye | 添加修订记录(新增token校验接口) |
|
||||
| 1.0.1 | 2025-06-06 | Luke.Ye | 重构登录Token校验逻辑, |
|
||||
| 1.0.2 | 2025-06-09 | Luke.Ye | 添加用户角色相关逻辑,重构代码 |
|
||||
| 1.0.3 | 2025-06-16 | Luke.Ye | 新增文档上传至对象存储接口 |
|
||||
|
||||
|
||||
|
||||
|
||||
14
pom.xml
14
pom.xml
@ -44,6 +44,8 @@
|
||||
<mybatis-plus-boot-starter.version>3.5.5</mybatis-plus-boot-starter.version>
|
||||
|
||||
<org.bouncycastle.version>1.70</org.bouncycastle.version>
|
||||
|
||||
<minio.version>8.5.3</minio.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@ -213,6 +215,13 @@
|
||||
<version>${org.bouncycastle.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>${minio.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -357,6 +366,11 @@
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package com.knowledge.base.infrastructure.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "object.storage")
|
||||
@Data
|
||||
public class ObjectStorageProperties {
|
||||
private boolean useUuidPrefix = true;
|
||||
}
|
||||
@ -1,8 +1,11 @@
|
||||
package com.knowledge.base.infrastructure.north.controller;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import com.knowledge.base.application.service.UserAppService;
|
||||
import com.knowledge.base.domain.doc.service.iface.DocumentImporter;
|
||||
import com.knowledge.base.infrastructure.cache.FileCacheService;
|
||||
import com.knowledge.base.infrastructure.config.ObjectStorageProperties;
|
||||
import com.knowledge.base.infrastructure.south.ObjectStorageGateway;
|
||||
import com.knowledge.base.infrastructure.util.SafeIdUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
@ -14,7 +17,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -32,6 +38,9 @@ public class FileWriteController {
|
||||
|
||||
private final UserAppService userAppService;
|
||||
|
||||
private final ObjectStorageGateway objectStorageGateway;
|
||||
private final ObjectStorageProperties objectStorageProperties;
|
||||
|
||||
private List<DocumentImporter> importers;
|
||||
|
||||
@PostMapping("/addUserFileAuth")
|
||||
@ -119,4 +128,53 @@ public class FileWriteController {
|
||||
return ResponseEntity.status(500).body("全量清空失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/upload-files")
|
||||
public ResponseEntity<?> uploadFolderToOS(
|
||||
@RequestParam("files") MultipartFile[] files,
|
||||
@RequestParam("bucket") String bucket
|
||||
) {
|
||||
try {
|
||||
objectStorageGateway.ensureBucketExists(bucket);
|
||||
|
||||
Map<String, String> filePathMap = new LinkedHashMap<>();
|
||||
|
||||
for (MultipartFile file : files) {
|
||||
String originalName = file.getOriginalFilename();
|
||||
if (originalName == null || originalName.isBlank()) {
|
||||
originalName = file.getName();
|
||||
}
|
||||
|
||||
// 路径前缀
|
||||
String folderPrefix = "default/";
|
||||
String safeName = originalName.replace("\\", "/");
|
||||
|
||||
// 是否启用 UUID 前缀
|
||||
if (objectStorageProperties.isUseUuidPrefix()) {
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
safeName = folderPrefix + uuid + "_" + Paths.get(safeName).getFileName().toString();
|
||||
} else {
|
||||
safeName = folderPrefix + Paths.get(safeName).getFileName().toString();
|
||||
}
|
||||
|
||||
// 上传到 MinIO
|
||||
objectStorageGateway.uploadFile(bucket, safeName, file);
|
||||
|
||||
// 使用原始文件名作为 key,MinIO 对象路径作为 value
|
||||
String fileKey = Paths.get(originalName).getFileName().toString();
|
||||
filePathMap.put(fileKey, String.format("http://s3.wisdompulse.cn/%s/%s", bucket, safeName));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"msg", "上传成功",
|
||||
"count", filePathMap.size(),
|
||||
"files", filePathMap
|
||||
));
|
||||
} catch (Exception e) {
|
||||
logger.error("上传失败", e);
|
||||
return ResponseEntity.status(500).body("上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package com.knowledge.base.infrastructure.south;
|
||||
|
||||
import io.minio.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MinioOSGatewayImpl implements ObjectStorageGateway {
|
||||
|
||||
private final MinioClient minioClient;
|
||||
|
||||
public MinioOSGatewayImpl(
|
||||
@Value("${minio.endpoint:http://s3.wisdompulse.cn}") String endpoint,
|
||||
@Value("${minio.access-key:lukeye}") String accessKey,
|
||||
@Value("${minio.secret-key:lukeye@6}") String secretKey
|
||||
) {
|
||||
this.minioClient = MinioClient.builder()
|
||||
.endpoint(endpoint)
|
||||
.credentials(accessKey, secretKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureBucketExists(String bucket) throws Exception {
|
||||
boolean exists = minioClient.bucketExists(
|
||||
BucketExistsArgs.builder().bucket(bucket).build()
|
||||
);
|
||||
if (!exists) {
|
||||
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
|
||||
log.info("已创建 bucket: {}", bucket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadFile(String bucket, String objectPath, MultipartFile file) throws Exception {
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(bucket)
|
||||
.object(objectPath)
|
||||
.stream(file.getInputStream(), file.getSize(), -1)
|
||||
.contentType(Optional.ofNullable(file.getContentType()).orElse("application/octet-stream"))
|
||||
.build());
|
||||
log.info("上传成功: {}/{}", bucket, objectPath);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.knowledge.base.infrastructure.south;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public interface ObjectStorageGateway {
|
||||
|
||||
/**
|
||||
* 确保 bucket 存在,不存在则创建
|
||||
*/
|
||||
void ensureBucketExists(String bucket) throws Exception;
|
||||
|
||||
/**
|
||||
* 上传文件到指定 bucket 的路径
|
||||
*/
|
||||
void uploadFile(String bucket, String objectPath, MultipartFile file) throws Exception;
|
||||
}
|
||||
@ -26,3 +26,6 @@ import.schedule.cron=0 0 * * * *
|
||||
# Redis 开关控制
|
||||
knowledge.base.redis.enable=false
|
||||
|
||||
object.storage.use-uuid-prefix=true
|
||||
spring.servlet.multipart.max-file-size=200MB
|
||||
spring.servlet.multipart.max-request-size=500MB
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user