OSS文件存储
sz-admin采用两个相互配合的模块处理文件存储,职责明确分离:
模块 职责 配置前缀 sz-common-oss厂商适配层。封装 MinIO / 阿里云 / 腾讯云 / 七牛云等底层 S3 SDK,负责 bucket 接入凭据管理。 sz.oss.*sz-common-resource业务抽象层。以「场景(sceneCode)」为核心,统一管理文件上传、路径规则、命名策略、访问模式和安全白名单。 sz.resource.*业务代码只需调用
ResourceService,不再直接依赖OssClient;底层存储介质(本地/OSS)和访问方式(直链/预签名/代理)均通过 yml 配置切换,代码无需改动。
配置指南
新版配置分为两段写在 oss.yml 中:
sz:
# oss 存储配置(厂商接入凭据)
oss:
# 支持 S3 协议的厂商: MINIO / ALIYUN / TENCENT / QINIU
provider: MINIO
endpoint: 192.168.100.176:9000
accessKey: your-access-key
secretKey: your-secret-key
# 全局存储桶(场景未指定 bucket 时回退使用)
bucketName: test
domain: http://192.168.100.176:9000
scheme: http
# 场景资源配置(业务资源体系)
resource:
# 本地存储根目录(LOCAL 类型场景使用)
root: ./data
# 全局默认存储类型
default-storage-type: LOCAL
# 全局安全白名单
security:
allowed-exts: [jpg, jpeg, png, gif, bmp, webp, svg, ico, pdf, doc, docx, xls, xlsx, ppt, pptx, rtf, txt, csv, zip, rar, 7z, tar, gz, mp3, wav, ogg, mp4, mov, avi, wmv]
max-size: 50MB
scenes:
# ========= 场景示例:账户头像 =========
# 同一个 sceneCode 可注释切换三种模式,根据环境选择一种激活
# 【模式一:本地存储 + Java 服务代理访问】(当前激活)
- code: admin.user.logo
type: LOCAL
serve-mode: DIRECT
base-url: http://127.0.0.1:9991/api/admin/resource/file/logo
path: logo
naming: ORIGINAL
path-strategy: BIZ_DATE
exts: [svg, png, jpg, jpeg, webp, gif]
max-size: 3
# 【模式二:OSS 私有桶 + 预签名 URL 访问】(注释状态)
# - code: admin.user.logo
# type: OSS
# serve-mode: PRESIGNED
# bucket: client-logos
# base-url: http://192.168.100.176:9000/client-logos
# naming: ORIGINAL
# path-strategy: BIZ_DATE
# exts: [svg, png, jpg, jpeg, webp, gif]
# max-size: 3
# 【模式三:OSS 公有桶 + 直链访问】(注释状态)
# - code: admin.user.logo
# type: OSS
# serve-mode: DIRECT
# bucket: client-logos-public
# base-url: http://192.168.100.176:9000/client-logos-public
# naming: UUID
# path-strategy: BIZ_DATE
# exts: [svg, png, jpg, jpeg, webp, gif]
# max-size: 3三种访问模式说明
| 模式 | type | serve-mode | 适用场景 | 注意事项 |
|---|---|---|---|---|
| 本地 + Java 代理 | LOCAL | DIRECT | 开发/测试环境,无需 OSS | base-url 需配置为 Java 服务的资源代理地址或 Nginx 代理地址 |
| OSS 私有 + 预签名 | OSS | PRESIGNED | 生产环境,需要访问控制 | 生成的 URL 有时效性(默认 3600 秒),适合合同、证件等敏感资源 |
| OSS 公有 + 直链 | OSS | DIRECT | 公开资源,无访问控制需求 | bucket 需设为公读,base-url 填写 OSS 公网访问地址 |
场景核心配置字段说明
| 字段 | 说明 | 可选值 |
|---|---|---|
code | 场景唯一标识(即前端 sceneCode),全局不可重复 | 自定义字符串,建议 模块.用途 格式 |
type | 存储类型 | LOCAL(本地磁盘)/ OSS(对象存储) |
path | LOCAL 类型必填,相对于 root 的存储子目录 | 字符串路径 |
bucket | OSS 类型必填,对应的 bucket 名称 | 字符串 |
naming | 文件命名规则 | UUID(随机)/ ORIGINAL(原文件名,冲突时补时间戳) |
path-strategy | 路径生成策略 | FLAT(扁平)/ DATE(按日期)/ BIZ_DATE(bizKey + 日期) |
serve-mode | 访问模式 | DIRECT(直链)/ PRESIGNED(预签名,仅 OSS)/ TOKEN(token 鉴权) |
base-url | DIRECT 模式必填,文件访问根地址 | URL 字符串 |
exts | 场景级文件扩展名白名单(覆盖全局 security.allowed-exts) | 字符串列表 |
max-size | 场景级最大文件大小 | 如 3(MB)或 3MB |
TIP
完整配置说明及各云厂商(MinIO / 阿里云 / 腾讯云 / 七牛云)的详细接入指引,请阅读项目源码中的 sz-common-oss/docs/oss-provider-guide.md。
使用场景
文件上传
统一通过 POST /resource/upload 接口上传,由前端传入 sceneCode 决定存储策略:
POST /resource/upload
Content-Type: multipart/form-data
sceneCode = admin.user.logo (必填,对应 yml 中的 scene code)
pathSegments = {userId} (可选,BIZ_DATE 策略的业务路径分段,多段逗号分隔)
file = <文件>上传成功后的返回结果示例:
{
"objectKey": "logo/1001/20260424/avatar.png",
"originName": "avatar.png",
"size": 98304,
"contentType": "image/png",
"accessUrl": "http://127.0.0.1:9991/api/admin/resource/file/logo/1001/20260424/avatar.png",
"resourceId": 10086
}IMPORTANT
accessUrl 仅用于上传后即时预览,不要入库。入库值始终存 objectKey。
查询时由 @OssUrlFill 注解自动将 objectKey 转换为完整访问 URL 返回给前端。
前端上传组件
所有上传组件统一使用 sceneCode 属性(旧版 dir 属性已废弃):
<!-- 单图上传 -->
<Img :sceneCode="'admin.user.logo'" v-model="form.avatar" />
<!-- 多图上传 -->
<Imgs :sceneCode="'teacher.attachment'" v-model="form.images" />
<!-- 多文件上传 -->
<UploadFiles :sceneCode="'admin.user.logo'" v-model="form.fileList" />
<!-- 富文本编辑器 -->
<JoditEditor scene-code="system.richtext" v-model="form.content" />@OssUrlFill 注解
数据库存储 objectKey,查询接口返回 VO 时需自动将其转换为可访问 URL。在 VO 字段上标注 @OssUrlFill,框架在 Controller 返回前自动完成替换:
public class UserVO {
/**
* 头像字段,数据库存储的是 objectKey(如 admin/20260430/avatar.jpg)
* @OssUrlFill 会在返回时自动按 admin.user.logo 场景配置转换为完整 accessUrl
*/
@OssUrlFill(sceneCode = "admin.user.logo")
private String avatar;
}Controller 无需额外处理,框架自动拦截 @RestController 方法返回值完成替换。
存储设计:数据库只存 objectKey
数据库存储的是 objectKey,而不是完整的访问 URL。
objectKey 是文件在存储介质中的相对路径,例如:
# 本地存储场景下的 objectKey 示例
admin/20260430/avatar.jpg
# OSS 存储场景下的 objectKey 示例
logo/admin/20260430/a3f9c1.jpg完整的访问 URL 在运行时由 base-url(场景配置) + objectKey 动态拼装,不持久化到数据库。
为什么这样设计? 如果将完整 URL 存入数据库,一旦发生服务器 IP 变更、存储类型切换(本地 → OSS)、访问模式变更等,历史数据全部失效。而存储 objectKey 后,只需修改 oss.yml 中对应场景的 base-url 或 serve-mode,配置一处,全局生效,数据库无需改动。
完整数据流:
【上传时】
前端 → POST /resource/upload(携带 sceneCode)
→ 返回 { accessUrl, objectKey, resourceId, ... }
→ 业务代码:入库保存 objectKey(不保存 accessUrl)
【查询时】
数据库读取 objectKey
→ @OssUrlFill 切面根据 sceneCode 的当前配置(base-url / serve-mode)
动态拼装或生成 accessUrl
→ 接口返回完整可访问的 accessUrl 给前端