办公文档多人同步预览编辑服务开发
一般而言,对于接入第三方类的服务,需要的主要流程是认证,请求接口,实现回调。其中,认证和请求接口一般都很简单,实现回调这块略微复杂一些。
整体步骤
在金山开发文档的网页创建应用,用于得到认证的key。
前端接入。前端引入一个金山的sdk.js代码,然后从自己的服务器返回一个文件地址,作为参数,初始化金山里面的sdk入口函数。
服务端接入。 主要实现四个方面的接口。 这些都是:回调接口,让金山的文档服务器主动调用的接口。
- 文档预览方面专用接口
- 文档编辑方面专用接口
提示文档预览和文档编辑公用这俩回调接口,分别是第一个是最主要的,指的是获取文件元数据,在预览和编辑的时候,通过接口校验并获取文件信息。 另一个是打开文件时返回通知的回调接口。
文档新建方面专用接口
- 新建文件, 通过前端网页上的文档模板新建时候,需要提供的接口。
上面三个方面均实现的接口,
- 获取用户信息,指的是在编辑的时候获取编辑过此文件的用户信息,展示在网页的协作记录里面
- 上传文件新版本,指的是编辑的时候把文件保存到网盘,比如七牛云
- 通知文件有哪些人正在协作编辑,指的是编辑的时候把正在编辑文档的人的列表返回给前端用来展示。
- 获取特定版本的文件信息,指的是获取历史版本的文件信息,主要用于回滚操作
- 文件重命名,指的是某个用户具有重命名权限时,重命名时调用的接口。
- 获取所有版本文件文件信息,指的是把当前的文件的所有历史版本作为列表返回。
根据自己的业务,一般需要实现的接口。
核心的是,
服务器下发一个WPS的文档链接。只需要这一个接口,就能完成全部内容交互了。
其他业务辅助接口为,比如展示已有文件列表,新建文档文件上传后返回一个WPS在线文档链接。 这类辅助接口基本上属于业务上的,跟核心交互接口基本无关。
库设计
1. 文档主表
字段名 | 类型 | 说明 |
---|---|---|
uuid | char(36) | 主键 |
file_id | varchar(255) | 文件标记id,主要是让其他表关联查询用。 |
file_name | varchar(255) | 最新的文件名 |
version | varchar(100) | 最新的文件版本记录 |
file_size | int(11) | 最新文件大小,单位KB |
create_id | varchar(255) | 第一次创建人 |
create_time | varchar(255) | 第一次创建时间 |
maintainer_id | varchar(255) | 最后一次维护人 |
maintainer_time | varchar(255) | 最后一次维护时间 |
download_url | varchar(10000) | 最新的文档下载地址,比如七牛云下载地址 |
delete | enum('YES', 'NO') | 是否已经删除的文件,这就跟业务有关了,如果删除那么不展示给前端了。 |
-- 表结构,名字任取,比如`z_file`
CREATE TABLE `z_file` (
`uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`file_id` varchar(255) DEFAULT '',
`file_name` varchar(255) DEFAULT '',
`version` varchar(100) DEFAULT '1',
`file_size` int(11) DEFAULT '0',
`create_id` varchar(255) DEFAULT '',
`create_time` varchar(255) DEFAULT '',
`maintainer_id` varchar(255) DEFAULT '',
`maintainer_time` varchar(255) DEFAULT '',
`download_url` varchar(10000) DEFAULT '',
`delete` enum('YES','NO') NOT NULL DEFAULT 'NO',
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 设置主键
ALTER TABLE `z_file`
ADD PRIMARY KEY (`uuid`);
COMMIT;
2. 文档版本历史表
字段名 | 类型 | 说明 |
---|---|---|
uuid | char(36) | 主键 |
file_id | varchar(255) | 该文档对应的文档标记id,指的是最新文档表的唯一文件id。 |
file_version_id | varchar(255) | 当前文档版本的文档id,主要是不可以用文件名去区分版本,每次版本变更后,需要生成一个新的随机串,用来标识本次版本的文档id,也为了方便操作。 |
file_name | varchar(255) | 该文档版本的文件名 |
version | varchar(100) | 记录自己是第几个版本,为了区分。 |
file_size | int(11) | 记录本次版本的文件大小,单位KB |
create_id | varchar(255) | 创建文档的人,一般为第一个文档创建者的id。为了方便查询,作用和文档主表的同名字段意义一样。 |
create_time | varchar(255) | 创建文档的人,一般为第一个文档创建者的id。为了方便查询,作用和文档主表的同名字段意义一样。 |
maintainer_id | varchar(255) | 最后一次维护人。为了方便查询,作用和文档主表的同名字段意义一样。 |
maintainer_time | varchar(255) | 最后一次维护时间。为了方便查询,作用和文档主表的同名字段意义一样。 |
download_url | varchar(10000) | 当前文档版本的下载地址,比如七牛云下载地址 |
-- 表结构,名字任取,比如`z_file_version`
CREATE TABLE `z_file_version` (
`uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`file_id` varchar(255) DEFAULT '',
`file_version_id` varchar(255) DEFAULT '',
`file_name` varchar(255) DEFAULT '',
`version` varchar(100) DEFAULT '1',
`download_url` varchar(10000) DEFAULT '',
`file_size` int(11) DEFAULT '0',
`create_id` varchar(255) DEFAULT '',
`create_time` varchar(255) DEFAULT '',
`maintainer_id` varchar(255) DEFAULT '',
`maintainer_time` varchar(255) DEFAULT '',
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 设置主键
ALTER TABLE `z_file_version`
ADD PRIMARY KEY (`uuid`);
COMMIT;
3. 文档权限表
字段名 | 类型 | 说明 |
---|---|---|
uuid | char(36) | 主键 |
user_id | varchar(255) | 用户id |
file_id | varchar(255) | 文档的id |
permission | varchar(255) | 当前用户访问权限,两个值read或者write |
rename | varchar(100) | 判断用户是否具有重命名权限,1启用,0关闭 |
history | varchar(100) | 判断用户是否有查看历史版本的权限,1启用,0关闭 |
copy | varchar(100) | 复制按钮权限,1启用,0关闭 |
export | varchar(100) | 导出按钮权限,1启用,0关闭 |
varchar(100) | 打印按钮权限,1启用,0关闭 |
-- 表结构,名字任取,比如`z_file_acl`
CREATE TABLE `z_file_acl` (
`uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`user_id` varchar(255) DEFAULT '',
`file_id` varchar(255) DEFAULT '',
`permission` varchar(255) DEFAULT 'read',
`rename` varchar(100) DEFAULT '0',
`history` varchar(100) DEFAULT '0',
`copy` varchar(100) DEFAULT '0',
`export` varchar(100) DEFAULT '0',
`print` varchar(100) DEFAULT '0',
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 设置主键
ALTER TABLE `z_file_acl`
ADD PRIMARY KEY (`uuid`);
COMMIT;
4. 文档水印表
文档水印功能其实可有可无,但是为了功能完整,需要设置文档水印维护的表
字段名 | 类型 | 说明 |
---|---|---|
uuid | char(36) | 主键 |
file_id | varchar(255) | 文档的id |
type_name | varchar(255) | 水印类型, 0为无水印; 1为文字水印 |
mark_value | varchar(100) | 文字水印的文字,当type为1时,此字段必填 |
fillstyle | varchar(100) | 水印的透明度,非必填,有默认值 |
font | varchar(100) | 水印的字体,非必选,有默认值 |
rotate | double(10,2) | 水印的旋转度,非必填,有默认值 |
horizontal | double(10,2) | 水印水平间距,非必填,有默认值 |
vertical | double(10,2) | 水印垂直间距,非必填,有默认值 |
-- 表结构,名字任取,比如`z_file_watermark`
CREATE TABLE `z_file_watermark` (
`uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`file_id` varchar(255) DEFAULT '',
`type_name` int(11) DEFAULT '0',
`mark_value` varchar(255) DEFAULT '',
`fillstyle` varchar(255) DEFAULT '',
`font` varchar(255) DEFAULT '',
`rotate` double(10,2) DEFAULT '0.00',
`horizontal` double(10,2) DEFAULT '0.00',
`vertical` double(10,2) DEFAULT '0.00',
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 设置主键
ALTER TABLE `z_file_watermark`
ADD PRIMARY KEY (`uuid`);
COMMIT;
5. 用户表
用户表跟在线编辑文档的关系不大,实际业务中,使用用户id去查一下用户的基本信息。 用户要有以下几个字段。
必要字段为id
和name
,非必要的字段是用户头像。avatar_url
- id, 字符串长度小于 32,必要的
- name, 用户名,必要的
- avatar_url 用户头像,非必要的。
CREATE TABLE `z_user` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(100) NOT NULL ,
`avatar_url` VARCHAR(100) NOT NULL ,
PRIMARY KEY (`id`)) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
往表里插入下面两行数据
[
{"id":"1", "name": "用户1","avatar_url": ""},
{"id":"2", "name": "用户2","avatar_url": ""}
]
INSERT INTO `z_user` (`id`, `name`, `avatar_url`) VALUES
(1, '用户1', ''),
(2, '用户2', '');
具体实现
业务接口实现
以下均不涉及token,自身业务的token和wps服务器请求时候的token,均可以全局处理,以下均不处理token问题。
业务1新建文档
新建文档,并获得在线编辑的链接
使用id=1的用户,上传到服务器一个文档,赋予权限为可读可写权限(Read/Write)。
接收到上传的文件流后,生成一个file_id,然后上传到七牛云云存储,获取七牛云的文件下载链接,然后把数据持久化,持久化file表,fileAcl表,版本表。
业务2文档列表
查询file表,单表查询
分页查询file表,把file表的一些字段都返回即可。
业务3根据fileId查找在线编辑链接
根据文件id,请求服务器得到下发的wps链接。
使用用户id和文件id作为参数,请求服务器,服务器根据参数进行签名,拼装为一个wps在线编辑的链接。
url 规范:https://wwo.wps.cn/office/<:type>/<:fileid>?_w_appid=xxx&_w_signature=xxx&…(对接模块需要的自定义参数)
编写生成WPS在线编辑的链接逻辑如下函数getWpsUrl
// 配置文件
// appid 与 appkey获取途径:
// WPS 开放平台 -> 服务申请 -> 进入服务(金山文档在线编辑) -> 申请添加新应用 -> 审核通过
const wpsConfig = {
appid: "",
appsecret: "",
domain: "https://wwo.wps.cn/",
}
// 把所有的参数进行签名加密,生成一个前面字符串
function sign(kvList = [], secretKey = ""){
// 将 _w_secretkey 加到最后,得到待加密的字符(_w_secretkey 只在签名时加入)。
let v = kvList.join("") + "_w_secretkey=" + secretKey;
// hmac-sha1 加密
// 使用 HMAC-SHA1 哈希算法,使用注册的 appsecret 密钥对上一步骤的源字符串进行加密。
// NodeJS自带的算法。只要是hmac sha1 签名即可,
return crypto.createHmac("sha1", secretKey).update(v).digest()
// 将加密后的字符串经过 Base64 编码
.toString('base64');
}
// 根据传入的参数,格式化一个url
function getWpsUrl(data = {_w_fileId: ""}, extraData = {fileType: ""}) {
let result = "";
data._w_appid = wpsConfig.appid;// 必要的参数
// 这里强制设置为1的原因是需要判断token,如果不需要判断token,那么设置为0即可
data._w_tokentype = 1;
// 键值对列表
let kvList = [];
kvList = Object.keys(data)
// 找到_w_开头的参数,需要进行签名,其他非法传入的参数不需要
.filter(k => k.indexOf("_w_") === 0)
// 将以 _w_ 作为前缀所有参数按 key 进行字典升序排列,
.sort((a, b) => a.localeCompare(b))
// 将排序后的 key、value 字符串以 %s=%s 格式拼接起来
.map(k => (k + "=" + data[k]));
let secretKey = wpsConfig.appsecret;
// 进行签名
let hmacSha1Sign = sign(kvList, secretKey);
// 对签名进行URL转码
hmacSha1Sign = encodeURIComponent(hmacSha1Sign);
let domain = wpsConfig.domain;
let fileType = extraData.fileType;
let fileId = data._w_fileId;
let kvListString = encodeURI(kvList.join("&"));
// 这里`encodeURIComponent`和`encodeURI`的使用要注意点。`encodeURIComponent`对所有字符都编码,
// 拼接返回的url
result = `${domain}office/${fileType}/${fileId}?${kvListString}&_w_signature=${hmacSha1Sign}`
return result;
}
前端拿着参数进行的请求。
支持格式 | type | 值 文件后缀 |
---|---|---|
文字文件 | w | doc, dot, wps, wpt, docx, dotx, docm, dotm, rtf |
表格文件 | s | xls, xlt, et, xlsx, xltx, csv, xlsm, xltm |
演示文件 | p | ppt, pptx, pptm, ppsx, ppsm, pps, potx, potm, dpt, dps |
PDF 文件 | f |
let userId = body.userId;
let fileId = body.fileId;
// 文件类型参考上表
let fileType = body.fileType; // "w", "e", "p", "f"
let wpsUrl = getWpsUrl({
_w_userid: userId,
_w_fileid: fileId,
},
{fileType});
// 然后把wpsurl返给前端,打开即可
金山文档服务器回调接口
每个接口都需要有token,token字段在请求头里面的x-wps-weboffice-token
上,因此可以做统一拦截器。后面会说、
即使这些回调接口不校验token也能正常使用,但是为了安全实际生产中是需要token的。
1. 文档预览方和文档编辑接口
参考地址: https://wwo.wps.cn/docs/server/callback-api-standard/get-user-information/
接口名:获取文件元数据,包括当前文件信息和当前用户信息
接口地址: `/v1/3rd/file/info`,GET方式
实现逻辑文字描述:
根据传入的fileId,去查找表,组装文档的基本信息和权限核心和水印和用户等。
// 获取请求头里面的文件id
let fileId = ctx.header["x-weboffice-file-id"];
// 获取url参数上的请求签名
let signature = ctx.query._w_signature;
// 获取url参数上的应用id
let appId = ctx.query._w_appid;
// 获取url参数上userId,这个属于自定义参数了
let userId = ctx.query._w_userid;
// 返回给金山服务器的接口的主要结构如下
/**
{
file: {
user_acl: {},
watermark: {},
},
user: {}
}
*/
// 根据fileId查询file表,得到file的信息
let sql = `SELECT
f.file_id AS id,
f.file_name AS name,
f.version AS version,
f.file_size AS size,
f.create_id AS creator,
f.create_time AS create_time,
f.maintainer_id AS modifier,
f.maintainer_time AS modify_time,
f.download_url AS download_url
FROM
z_file AS f
WHERE
f.file_id = :fileId LIMIT 1`;
// 假定文件表查出来的数据为
let fileData = {
id: "",
name: "",
version: 0,
size: 0,
creator: "",
create_time: 0,
modifier: "",
modify_time: 0,
download_url: "",
preview_pages: 0, // 0不限制,限制预览页数 (非必填,不超过5000)
}
// 根据fileId查询file_acl表,得到file的权限
sql = 'SELECT `uuid`, `user_id`, `file_id`, `permission`, `rename`, `history`, `copy`, `export`, `print`, `createdAt`, `updatedAt` FROM `z_file_acl` WHERE file_id = :fileId AND user_id = :userId';
// 假定权限表查出来的数据为
let fileAclData = {
rename: 1, // 重命名权限,1为打开该权限,0为关闭该权限,默认为0
history: 1, // 历史版本权限,1为打开该权限,0为关闭该权限,默认为1
copy: 1, // 复制
export: 1, // 导出PDF
print: 1 // 打印
}
// 根据fileId查询z_file_watermark表,得到file的水印
sql = 'SELECT `uuid`, `file_id`, `type_name`, `mark_value`, `fillstyle`, `font`, `rotate`, `horizontal`, `vertical`, `createdAt`, `updatedAt` FROM `z_file_watermark` WHERE `file_id` = :fileId;';
// 假定水印表查出来的数据为
let fileWatermarkData = {
type: 1, // 水印类型, 0为无水印; 1为文字水印
value: "禁止传阅", // 文字水印的文字,当type为1时,此字段必填
fillstyle: "rgba( 192, 192, 192, 0.6 )", // 水印的透明度,非必填,有默认值
font: "bold 20px Serif", // 水印的字体,非必填,有默认值
rotate: -0.7853982, // 水印的旋转度,非必填,有默认值
horizontal: 50, // 水印水平间距,非必填,有默认值
vertical: 100 // 水印垂直间距,非必填,有默认值
}
// 根据userId查询用户信息。
sql = 'SELECT `id`, `name`, `avatar_url` FROM `z_user` WHERE `id` = :userId';
let userData = {
id: "1", // 用户id,长度小于32 (必填)
name: "用户1", // 用户名称 (必填)
permission: "read", // 用户操作权限,write:可编辑,read:预览 (必填)
avatar_url: "" // 用户头像地址 (非必填)
}
// 拼装数据
fileData["user_acl"] = fileAclData;
fileData["watermark"] = fileWatermarkData;
let result = {
file: fileData,
user: userData,
}
// result 就是最后返给前端的数据
2. 文档新建接口
在模板页选择对应的模板后,将新创建的文件上传到对接模块,返回访问此文件的跳转 url。
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/new-file/
接口名:通过模板新建需要提供的接口
接口地址: `/v1/3rd/file/new`,POST方式
实现逻辑文字描述:
通过拿文件流,得到文件的后缀名,判断是新建的什么类型的文档,然后生成一个fileId,再把fileId和文件后缀生成一个文件名。
然后把文档上传到七牛云,最后把各自对应的信息分别存入文档file表,权限file_acl表,版本file_version表。
完毕后,再按照通过文档fileId和用户userId的逻辑,生产一个wps的在线编辑链接即可(这块生成逻辑跟前面的一模一样)。
// 获取文件流
const stream = ctx.getFileStream();
// 得到文件后缀
let ext = path.extname(stream.filename);
// 初始化一个fileId, 使用guid这类生成uuid的函数
let fileId = guid().replace(/-/img, '');
// 创建一个新的文件名
let filenameSave = fileId + ext.toLocaleLowerCase();
// 备份原始的文件名
let filenameBackup = stream.filename;
// 上传此文件流到七牛云,并返回一个七牛云的地址、
// uploadQiniu()等等。可以自行实现,不过要返回一个七牛云的地址
let download_url = uploadQiniu(stream, filenameSave);
// 以上工作做完后,需要做的事情分别入库file表,file_acl表,file_version表。三条insert语句
// 插入file表数据
let sql = 'INSERT INTO `z_file`(`uuid`, `file_id`, `file_name`, `version`, `file_size`, `create_id`, `create_time`, `maintainer_id`, `maintainer_time`, `download_url`, `delete`) VALUES (:uuid,:fileId, :filenameBackup, 1, 0,\'1\', 0,\'1\',0 , :download_url, \'NO\')'
// 插入file_acl表数据
sql = 'INSERT INTO `z_file_acl`(`uuid`, `user_id`, `file_id`, `permission`, `rename`, `history`, `copy`, `export`, `print`) VALUES (:uuid,:userId,:fileId,\'write\',1,1,1,1,1)'
// 插入file_version表 // 具体省略
sql = 'INSERT INTO `z_file_version`(`uuid`, `file_id`, `file_version_id`, `file_name`, `version`, `download_url`, `file_size`, `create_id`, `create_time`, `maintainer_id`, `maintainer_time`, `createdAt`, `updatedAt`) VALUES ......';
// 以上操作完成之后,就是拿着fileId和userId直接生成一个wps链接即可。
// formatFileType 函数通过把后缀名匹配为标识符号
let fileType = formatFileType(ext);
let wpsUrl = getWpsUrl({
_w_userid: userId,
_w_fileid: fileId,
},
{fileType});
// result 即为返回给前端的结果
let result = {redirect_url: wpsUrl, user_id};
3. 文档公用回调接口
打开或关闭文件时,WPS 会回调一些通知,目前有 5 类回调通知(详情查看下文的请求示例)。
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/open-and-close-file-notifications/
接口名: 打开或关闭文件时需要提供的接口
接口地址: `/v1/3rd/onnotify`,POST方式
实现逻辑文字描述:
如果需要做统计类操作,需要获取参数进行统计,否则的话,直接返回任意的对象即可。
可根据回调请求参数中的cmd参数的值不同,做不同的统计分类。
// 文件id
let fileId = ctx.header["x-weboffice-file-id"]
// 请求签名
let signature = ctx.query._w_signature
// 应用id
let appId = ctx.query._w_appid
// 用户id
let userId = ctx.query.userId
// 命令参数
let cmd = ctx.request.body.cmd
// 信息内容
let bodyMsg = ctx.request.body.body
// 根据以上参数做一些统计处理等等
// ...code
// 然后返回成功即可,返回result对象即可
let result = {
code: 0,
message: "OK",
}
4. 获取用户信息
指的是在编辑的时候获取编辑过此文件的用户信息,展示在网页的协作记录里面
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/get-user-information/
接口名:获取用户信息
接口地址: /v1/3rd/user/info
,POST方式
实现逻辑文字描述:
金山服务器请求参数是
{
ids: ["1", "2"]
}
通过这些传过来的用户id,返回对应的用户名和用户头像。
// 用户id数组
let ids = ctx.request.body.ids
// 通过查user表,找到对应的用户基本信息即可。
let sql = 'SELECT `id`, `name`, `avatar_url` FROM `z_user` WHERE id IN (:ids)'
// 假定返回的参数是如下
let userList = [
{id: "1", name: "用户1", avatar_url: "" },
{id: "2", name: "用户2", avatar_url: "" },
]
// 最后的返回结果为`result`
let result = {
"users": userList
}
5. 上传文件新版本
指的是编辑的时候把文件保存到网盘,比如七牛云 当文档在线编辑并保存之后,上传该文档最新版本到对接模块,同时版本号进行相应的变更,需要对接方内部实现文件多版本管理机制。
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/upload-new-version-of-file/
接口名:上传文件新版本
接口地址: /v1/3rd/file/save
,POST方式
实现逻辑文字描述:
获取文档流,上传此文档到云存储空间,根据请求的fileId查找file表找到fileId,然后开始更新file表的这条数据,更新的时候把version加一,最后把加一后的version新增一条数据插入到file_vesrsion版本表即可。
与新建文件的逻辑差不多,
特殊在于,
- 更新file表的时候,需要修改部分字段,版本号需要自增,维护人,维护时间;
- 插入file_version表的时候,版本号需要使用file新设置的版本号。
代码逻辑,参考新建文件逻辑即可。
6. 通知文件有哪些人正在协作编辑
此接口为异步接口,只能作为统计,一致性无法保证。
指的是编辑的时候把正在编辑文档的人的列表返回给前端用来展示。
接口名:获取用户信息
接口地址: /v1/3rd/file/online
,POST方式
实现逻辑文字描述:
根据金山服务器请求的时候参数,如
{
"ids": ["1", "2"]
}
返回值:status code 为 200 表示获取数据成功。其余值表示失败,需要在返回中指定 code、message 等信息(参考常见错误码)。
如果获取成功,可以直接返回result即可。如果不想做任何处理,也可以直接返回result对象。
let result = {
code: 0,
message: "OK"
}
7. 获取特定版本的文件信息
指的是获取历史版本的文件信息,主要用于回滚操作
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/get-file-information-for-a-specific-version/
接口名:获取用户信息
接口地址: /v1/3rd/file/version/:version
,GET方式
实现逻辑文字描述:
根据传入的fileId和version,去查file_version表,得到对应的行数据即可。
// 文件id
let fileId = ctx.header["x-weboffice-file-id"];
// 请求签名
let signature = ctx.query._w_signature;
// 应用id
let appId = ctx.query._w_appid;
// 用户id
let userId = ctx.query._w_userid;
// 拿到固定版本
let version = ctx.params.version;
// 一个单表查询即可
let sql = 'SELECT `uuid`, `file_id`, `file_version_id`, `file_name`, `version`, `download_url`, `file_size`, `create_id`, `create_time`, `maintainer_id`, `maintainer_time`, `createdAt`, `updatedAt` FROM `z_file_version` WHERE `file_id` = :file_id && `version` = :version';
// 假如返回值如下
let fileData = {
id: "1", // 文件 id,字符串长度小于 40
name: "xxx.doc", // 文件名
version: 1, // 当前版本号,位数小于 11
size: 0, // 文件大小,单位为 B
create_time: 0, // 创建时间,时间戳,单位为秒
creator: "", // 创建者 id,字符串长度小于 40
modify_time: 0, // 修改时间,时间戳,单位为秒
modifier: "", // 修改者 id,字符串长度小于 40
download_url: "" // 文档下载地址
};
// 把result返回即可
let result = {
file: fileData
};
8. 文件重命名
指的是某个用户具有重命名权限时,重命名时调用的接口。
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/file-rename/
接口名:获取用户信息
接口地址: /v1/3rd/file/rename
,PUT方式
实现逻辑文字描述:
根据传入的参数name,把新名字更新到file库即可。
金山服务器请求为PUT请求,
{
"name": "rename.doc"
}
// 文件id
let fileId = ctx.header["x-weboffice-file-id"];
// 文件新名称
let name = ctx.body.name;
// 单表更新file表的name字段即可
let sql = 'UPDATE `z_file` SET `file_name`= :name WHERE `file_id` = :fileId'
返回值:status code 为 200 表示获取数据成功。其余值表示失败,需要在返回中指定 code、message 等信息(参考常见错误码)。
最后直接返回result对象即可
let result = {
code: 0,
message: "OK"
}
9. 获取所有版本文件文件信息
指的是把当前的文件的所有历史版本作为列表返回。
参考地址:https://wwo.wps.cn/docs/server/callback-api-standard/get-all-historical-version-file-information/
接口名:获取所有历史版本文件信息
接口地址: /v1/3rd/file/history
,POST方式
实现逻辑文字描述:
主要是是一个分页查询接口,查询的是file_version表。 同时在查出来的信息的基础上,找到对应的用户id,去查用户的基本信息。
// 文件id
let fileId = ctx.header["x-weboffice-file-id"]
// 记录偏移量
let offset = ctx.request.body.offset || 0
// 记录总数
let count = ctx.request.body.count || 10
// 便于说明,直接使用一个关联查询。
let sql = let sql = `SELECT
\`fv\`.\`uuid\`,
\`fv\`.\`file_id\`,
\`fv\`.\`file_name\`,
\`fv\`.\`version\`,
\`fv\`.\`download_url\`,
\`fv\`.\`file_size\`,
\`fv\`.\`create_id\`,
\`fv\`.\`create_time\`,
\`fv\`.\`maintainer_id\`,
\`fv\`.\`maintainer_time\`,
\`fv\`.\`file_version_id\`,
\`c_user\`.\`name\` AS \`create_name\`,
\`c_user\`.\`avatar\` AS \`create_avatar\`,
\`m_user\`.\`name\` AS \`maintainer_name\`,
\`m_user\`.\`avatar\` AS \`maintainer_avatar\`
FROM
\`z_file_version\` AS \`fv\`
LEFT JOIN \`user\` AS \`c_user\`
ON
\`fv\`.\`create_id\` = \`c_user\`.\`uuid\`
LEFT JOIN \`user\` AS \`m_user\`
ON
\`fv\`.\`maintainer_id\` = \`m_user\`.\`uuid\`
WHERE
\`file_id\` = :fileId
ORDER BY
\`fv\`.\`version\` * 1
DESC
LIMIT :offset, :count`
最后只需要返回指定的数据接口即可。
{
histories: [
{
id: "f132aa30a87064", // 文件 id,字符串长度小于 40
name: "example.doc", // 文件名
version: 3, // 版本号,位数小于 11
size: 200, // 文件大小
download_url: "http://www.xxx.cn/v1/file?fid=f132aa30a87064&version=3", // 文档下载地址
create_time: 1136185445, // 创建时间,以时间戳表示,单位为秒
modify_time: 1539847453, // 修改时间,以时间戳表示,单位为秒
creator: {
id: "id0", // 创建者 id,字符串长度小于 40
name: "wps-0", // 创建者名字
avatar_url: "http://xxx.cn/?id=0" // 创建者头像地址
},
modifier: {
id: "id1000", // 修改者 id,字符串长度小于 40
name: "wps-1000", // 修改者名字
avatar_url: "http://xxx.cn/?id=1000" // 修改者头像地址
}
}]
}
前端使用方式
参考链接。 https://wwo.wps.cn/docs/front-end/introduction/
以下逻辑即可包含基本情况了。其他的定义都是界面的改动,不太困难,可以参考官网说明。
// 获取 token 函数
const refreshToken = () => {
// 自身业务处理...
// 可以返回 Promise 或者 return { token, timeout }
return Promise.resolve({
token: 'yourToken', // 必需:你需要设置的 toekn
timeout: 10 * 60 * 1000, // 必需:token 超时时间,以 10 分钟示例
});
};
// 配置超时获取 token 函数
const jssdk = WebOfficeSDK.config({ refreshToken });
// 设置 token
jssdk.setToken({
token: 'yourToken', // 根据自身的业务需求,通过异步请求或者模板输出的方式,取得 token
timeout: 10 * 60 * 1000, // token 超时时间,可配合 refreshToken 配置函数使用,在超时前调用 refreshToken 重新刷新 token
});
接口请求拦截器
- 只要是v1开头的金山在线编辑的回调接口,token均在请求头里面,所以拦截器只需要进行路径匹配后,查找对应的存token的key,然后去校验token是否正确即可。
// 校验身份的token,值根据对接的企业而定
let token = ctx.header["x-wps-weboffice-token"]
- 其他业务接口,就不必解释了,均与业务有关。
总结
内容很多,但是抓住细节就是,一直都在跟file表进行交互。