# 文件管理需求&方案 ## 需求列表 ### 文件夹 文件夹封层,每个对象存储当前路径 dir 和 父节点 id ,以及当前文件夹的表示。 nodeType 为节点类型,主要是为了查询根节点。 增加环境参数存储,区分不同环境下的文件夹 ##### 文件夹的属性 - 名称 - 标识 - 描述 - ParaentId - Dir: 当前路径 - nodeType: root | child - 环境参数 - 创建人 - 更新时间 - 创建时间 ##### 文件夹的API - 文件夹列表(全量) - 创建文件夹 - 更新文件夹 - 查询文件夹 > 通过id搜索 - 删除文件夹 ### 文件 上传至oss之后,存储url、文件名、备注、从属文件夹。文件url不对外公开 ##### 文件的属性 - 文件名 - 描述 - key - 文件夹id - 创建人 - url - 更新时间 - 创建时间 ##### 文件的API - 文件列表分页 - 创建文件 - 更新文件 - 删除文件 - 通过id获取文件详情 ### 文件访问控制 通过解析路径,查询数据库中存储url,并返回对应的资源 ## 方案设计 ![](https://i.imgur.com/QfAoi0u.png) ### 数据结构设计 #### 文件夹 folder ```javascript { name: { type: String }, displayName: { type: String }, parentId: { type: Schema.Types.ObjectId, ref: 'folder'}, dir: { type: String }, // 添加index,所属文件夹,如 '/' nodeType: { type: String }, // ROOT | CHILD env: { type: String }, // 环境参数 createdBy: { type: Schema.Types.ObjectId, ref: 'User'}, updatedBy: { type: Schema.Types.ObjectId, ref: 'User'} }, { timestamps: true } index + paraentId - name - env // 唯一索引 + dir // 索引,方便查询 getByDir ``` #### 文件 file ```javascript { name: { type: String }, description: { type: String }, folder: { type: Schema.Types.ObjectId, ref: 'Folder'}, url: { type: String }, // oss 存储地址 createdBy: { type: Schema.Types.ObjectId, ref: 'User'}, updatedBy: { type: Schema.Types.ObjectId, ref: 'User'}, }, { timestamps: true } index + folder - name ``` ### API设计 文件夹返回对象 FolderOutbound ```javascript { id: string, name: string, displayName: string, parentId: string, dir: string, // 所属文件夹 nodeType: 'ROOT' | 'CHILD', env: Env, // 所属环境 createdBy: User, updatedBy: User, createdAt: number, updatedAt: number } ``` 文件返回对象 FileOutbound ``` { id: string, name: string, description: string, folder: string, url: string, // 文件虚拟地址,通过 static 服务转发至 oss createdAt: string, updatedAt: string, createdBy: User, updatedBy: User } ``` ##### 文件夹列表(全量) | Method | Url | | | ------ | ------- | ---- | | get | /folder | | Response: ```javascript { code: 0, msg: '', data: FolderOutbound[] } ``` ##### 创建文件夹 | Method | Url | | | ------ | ------- | ---- | | post | /folder | | Request query ```javascript { env: 'DEV' // 环境 } ``` Request body ```javascript { name: string, displayName: string, parentId: string, // optional 缺省时,创建根目录下的文件夹 } ``` ##### 更新文件夹 重命名,拖动文件夹。 需要注意,如果拖动了文件夹,所属的文件夹dir属性需要更新 | Method | Url | | | ------ | ----------- | ---- | | put | /folder/:id | | Request param ```javascript { id: ObjectId // 文件夹id } ``` Request body ```javascript { name: string, displayName: string, parentId: string, // optional 缺省时,创建根目录下的文件夹 } ``` Response code :403 - name-existed code: 0 ```javascript { code: 0, data: FolderOutbound } ``` ##### 查询文件夹 > 通过id搜索 | Method | Url | | | ------ | ----------- | ---- | | Get | /folder/:id | | Request param ```javascript { id: ObjectId // 文件夹id } ``` Response code: 0 ```javascript { code: 0, data: FolderOutbound } ``` ##### 删除文件夹 | Method | Url | | | ------ | ----------- | ---- | | delete | /folder/:id | | Request param ```javascript { id: ObjectId // 文件夹id } ``` Response code: 0 ``` { code: 0 } ``` ----------- ##### 文件列表全量 | Method | Url | | | ------ | ----- | ---- | | get | /file | | Request quest ```javascript { folderId: ObjectId // 文件夹id } ``` Response code: 0 ``` { code: 0 data: FileOutbound[] } ``` ##### 创建文件 | Method | Url | | | ------ | ----- | ---- | | Post | /file | | Request quest ```javascript { folderId: ObjectId // 文件夹id name: string, // 文件名 description: string, // 文件描述 url: string // 文件地址 } ``` Response code: 0 ```javascript { code: 0 data: FileOutbound[] } ``` ##### 更新文件 可以更新文件夹 | Method | Url | | | ------ | --------- | ---- | | put | /file/:id | | Request param ```javascript { id: fileId } ``` Request quest ```javascript { folderId: ObjectId // 文件夹id name: string, // 文件名 description: string, // 文件描述 url: string // 文件地址 } ``` Response code: 0 ```javascript { code: 0 data: FileOutbound[] } ``` ##### 删除文件 | Method | Url | | | ------ | --------- | ---- | | delete | /file/:id | | Request param ```Javascript { id: fileId } ``` Response code: 0 ```javascript { code: 0 } ``` ##### 通过id获取文件详情 | Method | Url | | | ------ | --------- | ---- | | get | /file/:id | | Request param ```javascript { id: fileId // 文件id } ``` Response code: 0 ```javascript { code: 0 data: FileOutbound[] } ``` ------------------------------ ##### 上传文件 ###### 图片上传 上传文件至CDN | Method | Url | | | ------ | -------- | ---- | | Post | /jdImage | | Request quest ```javascript { files: Joi.binary().description('FormData文件') } ``` Response code: 0 ```javascript { code: 0 data: string[] //cdn 地址 } ``` ###### 文件上传 上传文件至oss | Method | Url | | | ------ | ---- | ---- | | Post | /oss | | Request quest ```javascript { files: Joi.binary().description('FormData文件') } ``` Response code: 0 ```javascript { code: 0 data: string[] //oss 地址 } ``` ### 文件访问控制 route /static/app/xxx/folderName/fileName?env=DEV ### 遇到的问题 新建一个服务,使用neos-backend调用该服务,权限验证没有拆出来 ####