easy-oss 使用文档
easy-oss 提供后端中立的对象存储客户端门面——业务层通过
ObjectStorage接口完成上传/下载/元数据/预签名 URL,底层由 SPI 屏蔽 MinIO 等 S3 兼容后端差异。MinIO SDK 为 optional scope,按需引入并配置easy.oss.*即自动装配。上传用「端点 + 文件名」由ObjectKeyFactory生成对象 key,返回的objectName供下载/删除/预签名复用。
1. 引入依赖
<!-- 核心依赖(必需) -->
<dependency>
<groupId>io.matrix</groupId>
<artifactId>easy-oss</artifactId>
<version>${revision}</version>
</dependency>
<!-- MinIO 后端(optional,引入后才会装配 MinIO Connector) -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
minio依赖版本由kernel-dependenciesBOM(minio.version)统一管理,无需手动指定。后续扩展 OSS/COS 时,只需替换为对应 SDK 并新增 Connector。
2. 配置 MinIO 后端
easy:
oss:
enabled: true # 总开关,默认 false
default-bucket: matrix # 默认桶(小写、3 位以上,上传时自动创建)
tenant: default # 对象 key 的租户前缀
minio:
endpoint: http://127.0.0.1:9000
access-key: admin
secret-key: password
region: us-east-1
secure: false # 是否 HTTPS(endpoint 未带协议时按此补全)
| 属性 | 默认值 | 说明 |
|---|---|---|
easy.oss.enabled | false | 总开关,false 时不创建任何 Bean |
easy.oss.default-bucket | matrix | 默认桶,未显式指定 bucket 的调用走它 |
easy.oss.tenant | default | 对象 key 的租户前缀 |
easy.oss.minio.endpoint | — | MinIO 服务地址 |
easy.oss.minio.access-key / secret-key | — | 访问凭据 |
easy.oss.minio.region | us-east-1 | 区域 |
easy.oss.minio.secure | false | 是否 HTTPS(endpoint 无协议时补全) |
同一应用只启用一个后端:
OssAutoConfiguration用@ConditionalOnBean(BackendObjectStorage)+@ConditionalOnMissingBean(ObjectStorage)互斥,业务方也可自定义ObjectStorageBean 覆盖默认门面。
3. 上传文件
注入 ObjectStorage,按业务端点 + 文件名上传:
@Autowired
private ObjectStorage objectStorage;
// 字符串
FileObject fo = objectStorage.putString("report", "summary.txt", "hello", "text/plain");
// 字节
FileObject fo2 = objectStorage.putBytes("avatar", "head.png", bytes, "image/png");
// 流
FileObject fo3 = objectStorage.putStream("firmware", "fw.bin", inputStream, "application/octet-stream", size);
// 文件
FileObject fo4 = objectStorage.putFile("report", "export.xlsx", new File("/tmp/export.xlsx"),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
返回值 FileObject 的关键字段:
| 字段 | 说明 |
|---|---|
objectName | 对象 key(含路径),作为后续下载/删除/预签名入参 |
bucket / contentType | 所属桶与 MIME 类型 |
size / etag | 字节数与服务端 ETag |
4. 下载 / 元数据 / 删除
均以 objectName 为入参,内部自动落到默认桶:
// 下载为字节
byte[] bytes = objectStorage.getBytes(fo.getObjectName());
// 下载为流(记得 close)
try (InputStream in = objectStorage.getStream(fo.getObjectName())) { ... }
// 元数据
FileObject meta = objectStorage.statObject(fo.getObjectName());
// 删除
boolean ok = objectStorage.deleteObject(fo.getObjectName());
5. 预签名 URL
用于浏览器直下 / 直传大文件,后端不经过 JVM:
import java.time.Duration;
// 下载 URL(浏览器直接打开即可下载)
String getUrl = objectStorage.presignedGetUrl(fo.getObjectName(), Duration.ofMinutes(30));
// 上传 URL(浏览器 PUT 直传)
String putUrl = objectStorage.presignedPutUrl(fo.getObjectName(), "image/png", Duration.ofMinutes(10));
6. 桶管理与对象列表
// 桶是否存在 / 创建桶
boolean exists = objectStorage.bucketExists("another-bucket");
objectStorage.makeBucket("another-bucket", "us-east-1");
// 前缀检索对象
List<String> names = objectStorage.listObjects("matrix", "report/2026/");
7. 对象 key 规范与自定义
默认 key 格式:{tenant}/{endpoint}/{yyyy/MM/dd}/{uuid}-{name}.{ext}
- 多租户隔离、按天分区前缀检索、UUID 防重名
- 文件名中的路径分隔符与前导点会被清洗,防止越权穿越(
../、..)
自定义 key 生成:实现 ObjectKeyFactory 并注册为 Bean(默认实现会被覆盖):
@Component
public class BizObjectKeyFactory implements ObjectKeyFactory {
@Override
public String newKey(String endpoint, String fileName) {
return "biz/" + endpoint + "/" + System.currentTimeMillis() + "/" + fileName;
}
}
ObjectKeyFactory、ObjectStorage均可用@ConditionalOnMissingBean覆盖,业务方按需自定义。
8. 常见问题
| 问题 | 说明 |
|---|---|
没有 ObjectStorage Bean | 检查 easy.oss.enabled=true、已引入 minio 依赖、已配置 easy.oss.minio.endpoint 三点 |
| MinIO 桶不存在报错 | 无需手动建桶,putObject 前会按 default-bucket 自动 bucketExists→makeBucket |
报 NoSuchElementException / 连接失败 | 校验 endpoint、access-key、secret-key,MinIO 服务是否可达、region 是否一致 |
| 预签名 URL 403 | 确认对象存在、URL 未过期、凭据对该桶有权限 |
| 如何切换对象存储提供商 | 当前仅 MinIO;新增 BackendObjectStorage 实现 + 对应 AutoConfiguration 即可,业务代码零改动 |
| 更多服务端能力(浏览器上传凭证、URL 代理) | 属中间件 easy-oss-server 规划范围,本期未实现 |