refactor(file-upload): 移除MinIO,新增RustFS存储支持

- 删除MinIO相关实现及配置
- 新增RustFS配置类,支持RustFS客户端初始化
- 新增RustFS存储服务实现,实现文件上传接口
- FileController添加日志打印上传异常信息
- pom.xml替换MinIO依赖为AWS SDK S3依赖
- 代码结构优化,提升文件上传模块的扩展性和稳定性
This commit is contained in:
曹鹏飞 2025-12-22 17:36:59 +08:00
parent 22075e0f63
commit 17bc951289
6 changed files with 113 additions and 134 deletions

View File

@ -20,6 +20,7 @@ import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@ -33,6 +34,7 @@ import java.util.List;
/**
* 文件管理相关接口
**/
@Slf4j
@RestController
@RequestMapping("/file")
public class FileController extends BaseController {
@ -58,6 +60,7 @@ public class FileController extends BaseController {
String url = fileUploadService.upload(buildFilePath(fileType), file);
return ApiResult.success(new FileUploadVO(0L, fileName, url));
} catch (Exception ex) {
log.error("上传文件失败", ex);
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
}
}

View File

@ -55,7 +55,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@ -94,18 +93,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>cn.hutool</groupId>-->
<!-- <artifactId>hutool-all</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.baomidou</groupId>-->
<!-- <artifactId>mybatis-plus-jsqlparser</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.mysql</groupId>-->
<!-- <artifactId>mysql-connector-j</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
@ -126,9 +113,9 @@
</exclusions>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.17</version>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.39.5</version>
</dependency>
</dependencies>

View File

@ -1,59 +0,0 @@
package com.nflg.wms.starter.config;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.SetBucketPolicyArgs;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Slf4j
@Configuration
@ConditionalOnProperty(name = "file.upload.type", havingValue = "minio")
public class MinIOConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.access-key}")
private String accessKey;
@Value("${minio.secret-key}")
private String secretKey;
@Value("${minio.bucket-name}")
private String bucketName;
private MinioClient client;
@Bean
@Lazy
public MinioClient initMinioClient() throws Exception{
client= MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
// 自动创建 bucket如果不存在
if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
String policyJsonString = """
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":"*","Action":"s3:GetObject","Resource":"arn:aws:s3:::%s/*"}]}""".formatted(bucketName);
client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(policyJsonString).build());
return client;
}
@PreDestroy
public void destroy() {
try {
client.close();
} catch (Exception e) {
log.error("MinIO 销毁出错", e);
}
}
}

View File

@ -0,0 +1,39 @@
package com.nflg.wms.starter.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import java.net.URI;
@Slf4j
@Configuration
@ConditionalOnProperty(name = "file.upload.type", havingValue = "rustfs")
public class RustFSConfig {
@Value("${rustfs.endpoint}")
private String endpoint;
@Value("${rustfs.access-key}")
private String accessKey;
@Value("${rustfs.secret-key}")
private String secretKey;
@Bean
public S3Client s3Client() {
return S3Client.builder()
.endpointOverride(URI.create(endpoint))
.region(Region.US_EAST_1) // 自建服务通常可设为任意值
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(accessKey, secretKey)))
.forcePathStyle(true) // RustFS 必须启用 Path-Style
.build();
}
}

View File

@ -1,51 +0,0 @@
package com.nflg.wms.starter.service.impl;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.starter.service.FileUploadService;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
@Slf4j
@Service
@ConditionalOnProperty(name = "file.upload.type", havingValue = "minio")
public class MinIOServiceImpl implements FileUploadService {
@Value("${minio.bucket-name}")
private String bucketName;
@Value("${minio.endpoint}")
private String domain;
@Resource
private MinioClient minioClient;
@Override
public String upload(String filePath, MultipartFile file) throws Exception {
return upload(filePath, file.getInputStream(), file.getContentType());
}
@Override
public String upload(String filePath, InputStream stream, String contentType) throws Exception {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(filePath)
.stream(stream, stream.available(), -1)
.contentType(contentType)
.build());
// return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
// .method(Method.GET)
// .bucket(bucketName)
// .object(filePath)
// .expiry(7, TimeUnit.DAYS)
// .build());
return StrUtil.format("{}/{}/{}", domain,bucketName, filePath);
}
}

View File

@ -0,0 +1,60 @@
package com.nflg.wms.starter.service.impl;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.starter.service.FileUploadService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import java.io.InputStream;
@Slf4j
@Service
@ConditionalOnProperty(name = "file.upload.type", havingValue = "rustfs")
public class RustFSServiceImpl implements FileUploadService {
@Value("${rustfs.bucket-name}")
private String bucketName;
@Value("${rustfs.domain}")
private String domain;
@Resource
private S3Client s3Client;
@Override
public String upload(String filePath, MultipartFile file) throws Exception {
return upload(filePath, file.getInputStream(), file.getContentType());
}
@Override
public String upload(String filePath, InputStream stream, String contentType) throws Exception {
ensureBucketExists();
s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucketName)
.key(filePath)
.contentType(contentType)
.build(),
RequestBody.fromInputStream(stream, stream.available())
);
return StrUtil.format("{}/{}/{}", domain, bucketName, filePath);
}
private void ensureBucketExists() {
try {
s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build());
} catch (NoSuchBucketException e) {
s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build());
}
}
}