refactor(file-upload): 移除MinIO,新增RustFS存储支持
- 删除MinIO相关实现及配置 - 新增RustFS配置类,支持RustFS客户端初始化 - 新增RustFS存储服务实现,实现文件上传接口 - FileController添加日志打印上传异常信息 - pom.xml替换MinIO依赖为AWS SDK S3依赖 - 代码结构优化,提升文件上传模块的扩展性和稳定性
This commit is contained in:
parent
22075e0f63
commit
17bc951289
|
|
@ -20,6 +20,7 @@ import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
@ -33,6 +34,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* 文件管理相关接口
|
* 文件管理相关接口
|
||||||
**/
|
**/
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/file")
|
@RequestMapping("/file")
|
||||||
public class FileController extends BaseController {
|
public class FileController extends BaseController {
|
||||||
|
|
@ -58,6 +60,7 @@ public class FileController extends BaseController {
|
||||||
String url = fileUploadService.upload(buildFilePath(fileType), file);
|
String url = fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
return ApiResult.success(new FileUploadVO(0L, fileName, url));
|
return ApiResult.success(new FileUploadVO(0L, fileName, url));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
log.error("上传文件失败", ex);
|
||||||
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
|
@ -94,18 +93,6 @@
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>jakarta.servlet</groupId>
|
<groupId>jakarta.servlet</groupId>
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
|
|
@ -126,9 +113,9 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.minio</groupId>
|
<groupId>software.amazon.awssdk</groupId>
|
||||||
<artifactId>minio</artifactId>
|
<artifactId>s3</artifactId>
|
||||||
<version>8.5.17</version>
|
<version>2.39.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue