附件统一处理starter,含附件客户端和附件服务端
文章来源:原创
作者:许秋冬
发布时间:2020-09-22
阅读:746
标签:springboot
许秋冬偷偷隐藏起来的markdown原文,测试对蜘蛛是否友好
[toc]
## 007-附件统一处理starter,含附件客户端和附件服务端
[项目地址](https://gitee.com/lcxm/boot/tree/master/boot-starter-attachment)
文章来源:[临窗旋墨的博客](http://www.xuqiudong.cn/detail/13)
### 一 关于项目中附件的概述
附件(文件上传)在每一个项目中都是必不可少的。
现在的选择也比较多,可以使用nginx + fastDFS搭建一个轻量级文件存储系统,也可以直接上云上的OSS等;
但是有的时候可能只是单纯写一个小的项目,不一定会使用到这些东西。
所以本人这里写一个简单的附件starter,方便集成到springboot中。
### 二 概要描述
我的初步的关于附件的构想:
1. 统一管理附件,统一入一个表;
2. 前端异步上传,返回id(和访问地址等)
3. 异步上传的文件入表后,默认的状态为临时的
4. 表单提交的时候,提交的是id或者ids或者是富文本中的完整url(xxxx/xxx/{id})
5. 保存表单的时候根据注解,调用sdk 修改表单实体中附件的状态为持久或临时
6. 定时器清理临时的附件:即上传但是没有使用的附件
7. 附件模块分客户端和服务端模块
> 主要是作为服务端使用完整的功能, 但是有的时候可能需要几个项目使用一套附件管理系统,
>
> 则一套作为服务端配置,
>
> 其他作为客户端使用;
>
> 作为客户端使用的时候,前端建议直接调用附件服务器的接口,
>
> 后台子附件字段入库的时候,通过附件客户端提供的SDK调用服务端修改附件状态
8. 客户端调用服务端附件的时候需简单校验
### 三 附件starter功能划分
#### 3.1 附件服务器,真实的存储附件
##### 3.1.1 为前端提供的接口
1. 异步上传
2. 批量异步上传
3. 根据id访问单个附件
4. 访问一个空附件(当访问一个附件不存在时,重定向到此接口)
5. 根据id下载一个附件
##### 3.3.2 为附件客户端提供的接口
1. 修改附件状态
2. 批量修改附件状态
3. 接收附件客户端的文件上传(一般不推荐,应直接前端异步上传)
#### 3.2 附件客户端,中转附件状态,依然调用附件服务器的存储
1. 修改附件服务端的附件状态SDK
2. 上传附件到服务端的SDK(不推荐)
### 四 通用配置说明-前缀统一为attachment
1. 是否启用附件功能`enable` 默认true
2. 当前服务是客户端还是服务端 `type` (1-服务端 2-客户端)
3. 附件存储的位置 `position` 服务端专用
4. 附件访问的主机 `host`:
1. 根据相对地址访问附件
2. 主机+ 相对地址 = 附件访问地址
3. 此主机一般使用nginx
5. 附件访问的前缀:`visit`(一般前端使用)
1. 根据id访问附件
2. 附件地址 = 前缀 + /attachment/visit/{id}
6. 空附件的相对位置`broken`,配合3中nginx使用
7. 是否启用清除附件定时器: `cleaner` 依赖spring的schedule
8. 从富文本中提取附件id的正则:`textAttachmentReg`, 默认:
> String DEFAULT_ATTACHMENT_REG = "/attachment/(download|visit)/(\\d+)\"";
8. 作为客户端时候配置的服务端的项目地址:`server` 用于调用服务端接口
9. 是否在启动时检测附件表是否存在 `checkTable`
10. 作为客户端调用附件服务端时候是检验码:`password` 客户端和服务端都需要配置 且一致
###### 附件配置示例
```properties
#附件配置attachment作为前缀
# 是否启用附件模块 默认true
attachment.enable=true
# 当前附件模块的类型,默认1;1-服务端; 2-客户端(只提供修改附件SDK,调用客户端接口修改)
attachment.type=1
#附件存储位置
attachment.position=E:/upload
#附件访问主机; url = 主机 + 相对地址,一般是交给nginx处理
attachment.host=localhost:10083/attachment/
# 附件访问地址:相对于项目; 附件地址 = attachment.visit + /attachment//visit/{id}
attachment.visit=http://localhost:81/boot
# 附件访问地址:附件服务器项目地址; 附件地址 = attachment.visit + /attachment//visit/{id}
attachment.server=http://localhost:81/boot
# 空的附件的相对地址 配合attachment.host使用
attachment.broken=/test/avatar.jpg
#是否开启定时清除临时态附件
attachment.cleaner=true
# 是否在启动时检测附件表是否存在
attachment.checkTable=false
#为附件客户端提供的接口的校验密码, 客户端需要和服务端保持一致才能调用接口
attachment.password=xasdadxasdasd
#附件客户端时的配置 附件服务器项目地址; type=2 时须配置,调用附件接口使用
attachment.server=http://localhost:81/boot
```
#### 五 附件表建表语句
```sql
CREATE TABLE `attachment` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '附件表id',
`absolute_path` varchar(255) DEFAULT NULL COMMENT '绝对地址',
`relative_path` varchar(255) DEFAULT NULL COMMENT '相对地址',
`temporary` tinyint(1) DEFAULT '0' COMMENT '是否是临时的',
`module` varchar(32) DEFAULT NULL COMMENT '所属模块',
`content_type` varchar(128) DEFAULT NULL COMMENT 'mimetype',
`size` int(11) DEFAULT NULL COMMENT '文件大小',
`filename` varchar(128) DEFAULT NULL COMMENT '文件名',
`original_name` varchar(128) DEFAULT NULL COMMENT '原文件名',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='附件表';
```
#### 六 部分接口简单说明
##### 6.1 `一般通用返回JSON格式说明`
```json
{
code:0,//返回码 0-默认 成功
msg:"",//错误码说明信息
data:null//接口需求的具体数据 或List 或String 等
}
```
##### 6.2 为前端提供的接口
###### 6.2.1 单文件上传接口
**请求地址**
`POST` `/attachment/upfile`
**请求参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| ------ | -------- | ---- | ----------------------- |
| upfile | file | Y | 上传的文件 |
| module | String | N | 所属模块 ,根据需要填写 |
**错误码说明**
| code | 错误原因 | 返回消息 |
| ---- | -------------- | ---------------- |
| 204 | 空文件 | 没有上传任何文件 |
| 500 | 不可预期的异常 | ..... |
**响应结果:**
```javascript
{
"code": 0,//成功为0
"message":"",
"data": {
"id":1,//id
"module":"....",//模块
"contentType":"image/jpeg",
"size":10220,/文件大小
"url":"",//附件访问地址
"originalName" :"",//附件原名
"filename":"",//转化后的名称
"createTime":"2020-12-12 12:12" //上传时间
}
}
```
###### 6.2.2 多文件上传接口
**请求地址**
`POST` `/attachment/upfiles`
**请求参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| ------- | -------- | ---- | ----------------------- |
| upfiles | file数组 | Y | 上传的文件 |
| module | String | N | 所属模块 ,根据需要填写 |
**错误码说明**
| code | 错误原因 | 返回消息 |
| ---- | -------------- | ---------------- |
| 204 | 空文件 | 没有上传任何文件 |
| 500 | 不可预期的异常 | ..... |
**响应结果:**
```javascript
{
"code": 0,//成功为0
"message":"",
"data": {
"id":1,//id
"module":"....",//模块
"contentType":"image/jpeg",
"size":10220,/文件大小
"url":"",//附件访问地址
"originalName" :"",//附件原名
"filename":"",//转化后的名称
"createTime":"2020-12-12 12:12" //上传时间
}
}
```
###### 6.2.3 根据id访问一个附件(一般图片)
**请求地址**
`GET ` :`/attachment/visit/{id}`
**URL参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| ---- | -------- | ---- | -------- |
| id | int | Y | 附件id |
**响应结果:**
> 重定向访问的附件,
>
> 不存在的时候返回空附件
###### 6.2.4 访问一个空附件
**请求地址**
`GET ` :`/attachment/visit/null`
**URL参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| ---- | -------- | ---- | -------- |
| 无 | i | | |
**响应结果:**
> 返回配置的空附件
###### 6.2.5 流下载一个附件
**请求地址**
`GET ` :`/attachment/download/{id}`
**URL参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| ---- | -------- | ---- | -------- |
| id | int | Y | 附件id |
**响应结果:**
> 下载附件id对应的文件
###### 6.3 为附件客户端提供的接口(会检验安全码)
###### 6.3.1 单文件文件状态修改
**请求地址**
`POST` `/attachment/temporary/update`
**请求参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| --------- | -------- | ---- | ------------------------- |
| id | int | Y | 文件id |
| temporary | boolean | N | true-临时态,false-持久态 |
**错误码说明**
| code | 错误原因 | 返回消息 |
| ---- | -------- | -------- |
| | | |
**响应结果:**
```javascript
{
"code": 0,//成功为0
"message":"",
"data":null
}
```
###### 6.3.2 多文件文件状态修改
**请求地址**
`POST` `/attachment/temporary/update`
**请求参数:**
| 参数 | 数据类型 | 必填 | 参数说明 |
| --------- | -------- | ---- | ------------------------- |
| ids | string | Y | 文件id,形如1-2-3-4 |
| temporary | boolean | N | true-临时态,false-持久态 |
**错误码说明**
| code | 错误原因 | 返回消息 |
| ---- | -------- | -------- |
| | | |
**响应结果:**
```javascript
{
"code": 0,//成功为0
"message":"",
"data":null
}
```
文章来源:[临窗旋墨的博客](http://www.xuqiudong.cn/detail/13)
项目地址:https://gitee.com/lcxm/boot/tree/master/boot-starter-attachment
作者:临窗旋墨 2020年9月21日