Nacos 配置中心 + OSS / Minio 文件上传实战
Nacos 配置中心 + OSS / Minio 文件上传实战
环境
| 组件 | 版本 |
|---|---|
| Spring Boot | 3.5.16 |
| Spring Cloud | 2025.0.0 |
| Spring Cloud Alibaba | 2025.0.0.0 |
| Nacos Server | 3.0.3 |
| Java | 17 |
Nacos 控制台怎么创建配置文件
登录 Nacos 控制台 http://127.0.0.1:8848/nacos,左侧菜单 配置管理 → 配置列表,点右上角 + 号。
Data ID: idle-store-oss-dev.yaml
Group: DEFAULT_GROUP
配置格式: YAML
命名空间: idlestore
配置内容: 见下面
Data ID 的命名规则是 {spring.application.name}-{profile}.{file-extension}。项目里 application-dev.yml 写的 optional:nacos:idle-store-oss-dev.yaml,所以 Data ID 就是 idle-store-oss-dev.yaml。
注意:
spring.config.import方式不会自动读取spring.application.name来拼 Data ID,你得在 import URL 里写完整。这和 bootstrap 方式不一样,老方式只需要配prefix和file-extension,框架自动拼。
OSS + Minio 完整 Nacos 配置
项目里用一个 storage.type 来控制走阿里云 OSS 还是 Minio,FileStrategyFactory 根据这个值返回对应的策略 Bean。两套 SDK 的 client 也都是从配置读参数创建的。
Nacos 里 idle-store-oss-dev.yaml 的完整内容:
storage:
type: aliyun
minio:
endpoint: http://127.0.0.1:9000
accessKey: admin
secretKey: 12345678
aliyun-oss:
accessKey: xxx
secretKey: xxx
endpoint: oss-cn-beijing.aliyuncs.com
每个字段的含义:
| 字段 | 含义 | 示例值 |
|---|---|---|
storage.type |
切换存储类型 | aliyun / minio |
storage.minio.endpoint |
Minio 服务地址 | http://127.0.0.1:9000 |
storage.minio.accessKey |
Minio 用户名 | admin |
storage.minio.secretKey |
Minio 密码 | 12345678 |
storage.aliyun-oss.accessKey |
阿里云 RAM AccessKey | LTAI5... |
storage.aliyun-oss.secretKey |
阿里云 RAM SecretKey | wxsck... |
storage.aliyun-oss.bucket |
OSS Bucket 名称 | typora-picture-0 |
storage.aliyun-oss.endpoint |
OSS 地域 Endpoint | oss-cn-beijing.aliyuncs.com |
本地 application-dev.yml 只要保留 Nacos 连接信息,不要写这些业务配置:
spring:
application:
name: idle-store-oss
config:
import:
- optional:nacos:idle-store-oss-dev.yaml?group=DEFAULT_GROUP&refreshEnabled=true
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
namespace: idlestore
discovery:
enabled: true
group: DEFAULT_GROUP
namespace: idlestore
server-addr: 127.0.0.1:8848
代码怎么绑这些配置
完整的工程结构:
idle-store-oss/idle-store-oss-biz/src/main/java/com/lh/idlestore/oss/biz/
├── config/
│ ├── StorageProperties.java ← storage.type
│ ├── MinioProperties.java ← storage.minio.*
│ ├── AliyunOSSProperties.java ← storage.aliyun-oss.*
│ ├── AliyunOSSConfig.java ← 创建 OSS Client
│ └── MinioConfig.java ← 创建 Minio Client
├── strategy/
│ ├── FileStrategy.java ← 上传接口
│ └── impl/
│ ├── AliyunOSSFileStrategy.java
│ └── MinioFileStrategy.java
├── factory/
│ └── FileStrategyFactory.java ← 根据 storage.type 选策略
├── controller/
│ └── FileController.java ← 上传接口
└── service/
├── FileService.java
└── impl/
└── FileServiceImpl.java
Properties 类——三层配置对应三个类
// storage.type
@ConfigurationProperties("storage")
@Component
@RefreshScope
@Data
public class StorageProperties {
private String type;
}
// storage.minio
@ConfigurationProperties("storage.minio")
@Component
@RefreshScope
@Data
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
}
// storage.aliyun-oss
@ConfigurationProperties("storage.aliyun-oss")
@Component
@RefreshScope
@Data
public class AliyunOSSProperties {
private String endpoint;
private String accessKey;
private String secretKey;
}
prefix 用 . 分割,Spring Boot 自动把 yaml 的嵌套结构映射到对应的 Properties 类。
Client 创建——从 Properties 读参数
// 阿里云 OSS Client
@Configuration
public class AliyunOSSConfig {
@Resource
private AliyunOSSProperties aliyunOSSProperties;
@Bean
public OSS aliyunOSSClient() {
DefaultCredentialProvider credentialsProvider = CredentialsProviderFactory
.newDefaultCredentialProvider(
aliyunOSSProperties.getAccessKey(),
aliyunOSSProperties.getSecretKey());
return new OSSClientBuilder()
.build(aliyunOSSProperties.getEndpoint(), credentialsProvider);
}
}
// Minio Client
@Configuration
public class MinioConfig {
@Resource
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(),
minioProperties.getSecretKey())
.build();
}
}
策略工厂——用 storage.type 决定走哪个
@Configuration
@Slf4j
public class FileStrategyFactory {
@Autowired
private StorageProperties storageProperties;
@Bean
public FileStrategy getFileStrategy() {
log.info("配置变为了: {}", storageProperties.getType());
if (StringUtils.equals(storageProperties.getType(), "minio")) {
return new MinioFileStrategy();
} else if (StringUtils.equals(storageProperties.getType(), "aliyun")) {
return new AliyunOSSFileStrategy();
}
throw new IllegalArgumentException("不可用的存储类型");
}
}
注意:
FileStrategyFactory上没有@RefreshScope,StorageProperties上有。因为StorageProperties加了@RefreshScope,它的代理每次getType()都会从 Environment 拿最新值,所以工厂不需要自己加@RefreshScope。
文件上传——策略模式,调用方不用管底层
// 接口
public interface FileStrategy {
String uploadFile(MultipartFile file, String bucketName);
}
// 阿里云 OSS 实现
@Slf4j
@Component("aliyun")
public class AliyunOSSFileStrategy implements FileStrategy {
@Resource
private AliyunOSSProperties aliyunOSSProperties;
@Resource
private OSS ossClient;
@Override
@SneakyThrows
public String uploadFile(MultipartFile file, String bucketName) {
String originalFileName = file.getOriginalFilename();
String key = UUID.randomUUID().toString().replace("-", "");
String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
String objectName = String.format("%s%s", key, suffix);
ossClient.putObject(bucketName, objectName,
new ByteArrayInputStream(file.getInputStream().readAllBytes()));
// OSS 访问 URL 格式:https://{bucket}.{endpoint}/{objectName}
return String.format("https://%s.%s/%s",
bucketName, aliyunOSSProperties.getEndpoint(), objectName);
}
}
// Minio 实现
@Slf4j
@Component("minio")
public class MinioFileStrategy implements FileStrategy {
@Resource
private MinioProperties minioProperties;
@Resource
private MinioClient minioClient;
@Override
@SneakyThrows
public String uploadFile(MultipartFile file, String bucketName) {
String originalFileName = file.getOriginalFilename();
String contentType = file.getContentType();
String key = UUID.randomUUID().toString().replace("-", "");
String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
String objectName = String.format("%s%s", key, suffix);
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1L)
.contentType(contentType)
.build());
// Minio 访问 URL 格式:http://{endpoint}/{bucket}/{objectName}
return String.format("%s/%s/%s",
minioProperties.getEndpoint(), bucketName, objectName);
}
}
阿里云 OSS 和 Minio 上传的区别:
| 阿里云 OSS | Minio | |
|---|---|---|
| URL 格式 | https://{bucket}.{endpoint}/{objectName} |
http://{endpoint}/{bucket}/{objectName} |
| putObject 方式 | ossClient.putObject(bucket, key, inputStream) |
minioClient.putObject(PutObjectArgs.builder()...) |
| ContentType | 不需要手动设 | PutObjectArgs.builder().contentType(...) |
| 访问协议 | HTTPS | HTTP(本地 Minio) |
调用入口
@RestController
@RequestMapping("/file")
public class FileController {
@Resource
private FileService fileService;
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Response<?> uploadFile(@RequestPart(value = "file") MultipartFile file) {
return fileService.uploadFile(file);
}
}
@Service
public class FileServiceImpl implements FileService {
@Resource
private FileStrategyFactory fileStrategyFactory;
private static final String BUCKET_NAME = "idlestore";
@Override
public Response<?> uploadFile(MultipartFile file) {
String url = fileStrategyFactory.getFileStrategy()
.uploadFile(file, BUCKET_NAME);
return Response.success(url);
}
}
切换存储类型的完整链路
在 Nacos 里把 storage.type 从 aliyun 改成 minio,不用重启:
pom.xml 和 yml 模板
依赖
<dependencies>
<!-- Nacos 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- ❌ 不要引入 spring-cloud-starter-bootstrap -->
<!-- 阿里云 OSS SDK -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!-- Minio SDK -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
application-dev.yml
spring:
application:
name: idle-store-oss
config:
import:
- optional:nacos:idle-store-oss-dev.yaml?group=DEFAULT_GROUP&refreshEnabled=true
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
namespace: idlestore
discovery:
enabled: true
group: DEFAULT_GROUP
namespace: idlestore
server-addr: 127.0.0.1:8848
# 业务配置全部放 Nacos,这里不留
Nacos 里的 idle-store-oss-dev.yaml
storage:
type: aliyun
minio:
endpoint: http://127.0.0.1:9000
accessKey: admin
secretKey: 12345678
aliyun-oss:
accessKey: your-aliyun-ak
secretKey: your-aliyun-sk
endpoint: oss-cn-beijing.aliyuncs.com
更多推荐




所有评论(0)