java后端尝试使用WebOffice在线编辑

概述

近期需要在项目中实现在线编辑word文档需求,因此尝试使用WebOfffice实现。官网手册十分详细,也可以加入他们的技术群。群内会有人解答技术问题。免费的方案下同时编辑的文件不多于20个,如果编辑需求量大,需要计费。对于用户较少的小网站来说已经足够使用。

官网手册

https://wwo.wps.cn/docs/introduce/

原理 流程图

图

来自<https://wwo.wps.cn/docs/introduce/technical-architecture/flow-chart/>

申请账号

申请服务商流程: https://open.wps.cn/apply-developer

填写回调地址,回调域名需要带有协议头,且已部署于外网可访问

签名算法

1.新建Signature.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import static org.apache.commons.codec.binary.Base64.encodeBase64String;
//import static org.apache.tomcat.util.codec.binary.Base64.encodeBase64String;

/*生成signature签名算法*/
public class Signature {

	public static String getUrlParam(Map < String, String > params) throws UnsupportedEncodingException {
		StringBuilder builder = new StringBuilder();
		for (Map.Entry < String, String > entry : params.entrySet()) {
			if (builder.length() > 0) {
				builder.append('&');
			}
			builder.append(URLEncoder.encode(entry.getKey(), "utf-8")).append('=').append(URLEncoder.encode(entry.getValue(), "utf-8"));
		}
		return builder.toString();
	}

	public static String getSignature(Map < String, String > params, String appSecret) {

		//params appSecret 密钥

		List < String > keys=new ArrayList();
		for (Map.Entry < String, String > entry : params.entrySet()) {
			keys.add(entry.getKey());
		}

		// 将所有参数按 key 的升序排序
		Collections.sort(keys, new Comparator<String>() {
			public int compare(String o1, String o2) {
				return o1.compareTo(o2);
			}
		});

		// 构造签名的源字符串
		StringBuilder contents = new StringBuilder("");
		for (String key : keys) {
			if (key == "_w_signature") {
				continue;
			}
			contents.append(key + "=").append(params.get(key));
			System.out.println("key:" + key + ",value:" + params.get(key));
		}
		contents.append("_w_secretkey=").append(appSecret);

		// 进行 hmac sha1 签名
		byte[] bytes = hmacSha1(appSecret.getBytes(), contents.toString().getBytes());
		// 字符串经过 Base64 编码
		String sign = encodeBase64String(bytes);
		try {
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		System.out.println(sign);
		return sign;
	}

	public static byte[] hmacSha1(byte[] key, byte[] data) {
		try {
			SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
			Mac mac = Mac.getInstance(signingKey.getAlgorithm());
			mac.init(signingKey);
			return mac.doFinal(data);
		}
		catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		return null;
	}

}

2.生成签名

官网测试示例 https://wwo.wps.cn/docs/server/description-of-signature-algorithm/

"contents": "_w_appid=123456_w_fname=222.docx_w_userid=id1000_w_secretkey=7890"

"signature": "dL3ce9l0l+GKTz+i0R++H2qWwrQ=" (未 URL 编码)

	// 官网生成签名 测试示例
	public String getSignature() throws UnsupportedEncodingException {
		Map< String, String > paramMap= new HashMap<>();
		String _w_appid="123456";
		String _w_appkey="7890";
		paramMap.put("_w_appid", _w_appid);
		paramMap.put("_w_fname", "example.doc");
		paramMap.put("_w_userid", "id1000");
		String signature = Signature.getSignature(paramMap, _w_appkey);//_w_appkey 密钥
		System.out.println(Signature.getUrlParam(paramMap) + "&_w_signature=" + signature);
		return  signature; // "Mo2s%2FL1RdBnIuo%2FuEMC4ZSQyhnk%3D"
	}

后端实现回调接口

需要实现文件预览,需要完成以下两个回调接口才能实现。文件编辑与文件新建也是需要完成对应的回调接口。

文件预览

回调地址

方法

功能

描述

/v1/3rd/file/info

GET

获取文件元数据

在预览或编辑的时候,通过接口校验权限并获取文件信息

/v1/3rd/onnotify

POST

通知

打开文件时返回通知的接口

来自 <https://wwo.wps.cn/docs/server/access-mode/>

文件编辑

回调地址

方法

功能

描述

/v1/3rd/file/info

GET

获取文件元数据

在预览或编辑的时候,通过接口校验权限并获取文件信息

/v1/3rd/user/info

POST

获取用户信息

在编辑的时候获取编辑过此文件的用户信息,展示在协作记录里面

/v1/3rd/file/save

POST

上传文件新版本

编辑完保存回对应云盘

/v1/3rd/file/online

POST

通知文件有那些人在协作协作

通知此文件目前有那些人正在协作

/v1/3rd/file/version/:version

GET

获取特定版本的文件信息

在回滚版本的时候需要获取历史版本的文件信息

/v1/3rd/file/rename

PUT

文件重命名

当用户有重命名权限时,重命名时调用的接口

/v1/3rd/file/history

POST

获取所有历史版本文件信息

显示在历史版本列表中

/v1/3rd/onnotify

POST

通知

打开文件时返回通知的接口

来自 <https://wwo.wps.cn/docs/server/access-mode/file-editing/>

文件新建

回调地址

方法

功能

描述

/v1/3rd/file/new

POST

新建文件

通过模板新建需要提供的接口

来自 <https://wwo.wps.cn/docs/server/access-mode/new-file/>

示例:文件预览-回调接口/v1/3rd/file/info

1.接口地址必须: "域名"  + "/v1/3rd/file/info"

2.写接口逻辑

3.返回接口参数必须与官方文档内的数据结构一致

{

  file: {

    id: "132aa30a87064", //文件id,字符串长度小于40

    name: "example.doc", //文件名(必须带文件后缀)

    version: 1, //当前版本号,位数小于11

    size: 200, //文件大小,单位为B(文件真实大小,否则会出现异常)

    creator: "id0", //创建者id,字符串长度小于40

    create_time: 1136185445. //创建时间,时间戳,单位为秒

    modifier: "id1000", //修改者id,字符串长度小于40

    modify_time: 1551409818, //修改时间,时间戳,单位为秒

    download_url: "http://www.xxx.cn/v1/file?fid=f132aa30a87064", //自己的文档外网下载地址

    preview_pages: 3 //限制预览页数

    user_acl: {

      rename: 1, //重命名权限,1为打开该权限,0为关闭该权限,默认为0

      history: 1, //历史版本权限,1为打开该权限,0为关闭该权限,默认为1

      copy: 1, //复制

      export: 1, //导出PDF

      print: 1 //打印

    },

    watermark: {

      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 //水印垂直间距,非必选,有默认值

    }

  },

  user: {

    id: "id1000", //用户id,长度小于32

    name: "wps-1000", //用户名称

    permission: "read", //用户操作权限,write:可编辑,read:预览

    avatar_url: "http://xxx.cn/id=1000" //用户头像地址

  }

}

4.调用地址

https://wwo.wps.cn/office/<:type>/<:fileid>?_w_appid=xxx&_w_signature=xxx&…(对接模块需要的自定义参数)

·必须参数:type值对应文件格式

支持格式

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

pdf

·必须参数:fileid 文件唯一标识id

·必须参数:_w_appid申请的appid

·必须参数:_w_signature 使用Signature生成的签名

·其他参数:根据需要增加参数,需要以“_w_”开头拼接在调用地址中,同时生成签名时要加上参数

·示例:

文件名 _w_fname、用户id _w_userid

url: https://wwo.wps.cn/office/w/132aa30a87064?_w_userid=id1000&_w_appid=123456&_w_fname=example.doc&_w_signature=Mo2s%2FL1RdBnIuo%2FuEMC4ZSQyhnk%3D

来自 <https://wwo.wps.cn/docs/server/access-mode/>

5.访问页面效果

注意事项

  • 服务要部署在公网,局域网 内网无法测试使用。
  • 回调地址要登录开放平台配置,与官方文档地址要一致
  • 对应功能的回调接口要实现,返回数据要与官方文档内的数据结构一致
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
版本修改记录: V2.2.0.2修改: 修改了HttpPost相对路径的一些问题。 V2.2.0.0增加: [id(0x00010041), helpstring("Get Rev Index")] HRESULT GetRevCount( [out,retval] long * pbool); [id(0x00010042), helpstring("Get Rev Index Info")] HRESULT GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); [id(0x00010043), helpstring("Set Doc Prop")] HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); [id(0x00010044), helpstring("Set Doc Variable")] HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); [id(0x00010045), helpstring("Save page To Doc")] HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- LoadDso.js var s = "" s += "" s += "" document.write(s) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 接口文档: /* 1.新建 */ //新建Word document.all.FramerControl1.CreateNew("Word.Document"); //新建Excel document.all.FramerControl1.CreateNew("Excel.Sheet"); /* 2.打开文件 */ //打开制定的本地文件 document.all.FramerControl1.Open("C:\\TestBook.xls"); //制定用Word来打开c:\plain.txt文件 document.all.FramerControl1.Open("C:\\Plain.txt",false, "Word.Document"); //打开服务器的文件 document.all.FramerControl1.Open "https://secureserver/test/mytest.asp?id=123",true, "Excel.Sheet", "MyUserAccount", "MyPassword"); //打开服务器的文件 document.all.FramerControl1.Open("http://localhost/1.doc", true); /* 3.保存文件 */ //到本地 document.all.FramerControl1.Save("c:\\1.doc",true); //服务器 /*增加Http协议Post上传接口,可以Post一个动态页面(jsp,asp,php...),由动态页面负责解析数据 bool HttpInit(); bool HttpAddPostString(BSTR strName, BSTR strValue); bool HttpAddPostCurrFile(BSTR strFileID, BSTR strFileName); BSTR HttpPost(BSTR bstr); */ //初始化Http引擎 document.all.FramerControl1.HttpInit(); //增加Post变量 document.all.FramerControl1.HttpAddPostString("RecordID","20060102200"); document.all.FramerControl1.HttpAddPostString("UserID","李局长"); //上传打开的文件 document.all.FramerControl1.HttpAddPostCurrFile("FileData", "文档名.doc"); //执行上传动作 document.all.FramerControl1.HttpPost("http://xxxx.com/uploadfile.asp"); /* 4.修订留痕 */ //进入留痕状态 document.all.FramerControl1.SetTrackRevisions(1); //进入非留痕状态 document.all.FramerControl1.SetTrackRevisions(0); //接受当前修订 document.all.FramerControl1.SetTrackRevisions(4); /* 5.设置当前用户 */ document.all.FramerControl1.SetCurrUserName("张三"); /* 6.设置当前时间(笔迹留痕会显示("Like 2006:02:07 11:11:11") */ document.all.FramerControl1.SetCurrTime("2006:02:07 11:11:11"); /* 7.设置和创建书签,此功能比较强大,设置书签数据、添加书签和添加红头文件就靠他了 SetFieldValue(BSTR strFieldName, BSTR strValue, BSTR strCmdOrSheetName) strFieldName:书签名 strValue:要设置的值 strCmdOrSheetName: 命令 ::ADDMARK:: 添加BookMark ::DELMARK:: 删除这个BookMark ::GETMARK:: 定位到这个BookMark ::FILE:: 插入的是文件 ::JPG:: 插入的是图片 一般来说:WORD中书签是做好的,可以通过此接口把外界数据设置进书签中去。 */ //在当前WORD位置插入标签,标签名为"book1",数值为"test" document.all.FramerControl1.SetFieldValue("book1","test","::ADDMARK::"); //设置书签"Time",数值为"2006-03-16 22:22:22" document.all.FramerControl1.SetFieldValue("Time","2006-03-16 22:22:22",""); //在书签位置"hongtou",插入红头文件"http://222.222.222.222/hongtou1.doc" 这样,红头就自动插进去了 document.all.FramerControl1.SetFieldValue("hongtou","http://222.222.222.222/hongtou1.doc","::FILE::"); /* 8.设置菜单显示情况 BOOL SetMenuDisplay(long lMenuFlag) lMenuFlag为以下数值的组合 #define MNU_NEW 0x01 #define MNU_OPEN 0x02 #define MNU_CLOSE 0x04 #define MNU_SAVE 0x08 #define MNU_SAVEAS 0x16 #define MNU_PGSETUP 0x64 #define MNU_PRINT 0x256 #define MNU_PROPS 0x32 #define MNU_PRINTPV 0x126 */ //只有“新建”菜单可用 document.all.FramerControl1..SetMenuDisplay(1); //只有“打开”菜单可用 document.all.FramerControl1.SetMenuDisplay(2); //只有“打开”和“新建”菜单可用 document.all.FramerControl1.SetMenuDisplay(3); /* 9.保护文档和解保护文档 lProOrUn:1:保护文档;0:解除保护 lProType: wdNoProtection = -1, wdAllowOnlyRevisions = 0, wdAllowOnlyComments = 1, wdAllowOnlyFormFields = 2 strProPWD:密码 */ //完全保护文档,密码为"pwd" document.all.FramerControl1.ProtectDoc(1,1,"pwd"); //解除文档保护 document.all.FramerControl1.ProtectDoc(0,1,"pwd"); /* 10.显示或隐藏修订内容 ShowRevisions(long nNewValue) nNewValue = 0 则隐藏修订 = 1 则显示修订 */ //显示修订留痕 document.all.FramerControl1.ShowRevisions(1); //隐藏修订留痕 document.all.FramerControl1.ShowRevisions(0); /* 11.插入合并文件, strFieldPath 文件路径,可以是http,ftp的路径 pPos = 0 //当前鼠标位置 1;文件开头 2;文件末尾 pPos的第4位为1的时候,代表插入的是图片 InSertFile(BSTR strFieldPath, long lPos) */ //文件头部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",1); //文件尾部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",2); //当前光标位置插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",0); //文件头部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",9); //文件尾部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",10); //当前光标位置插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",8); /* 0x31. 文档另存为 HRESULT SaveAs([in] VARIANT strFileName, [in] VARIANT dwFileFormat, [out,retval] long* pbool); 参数: strFileName:文件本地路径,如c:\\11.doc dwFileFormat: 文件格式 dwFileFormat的数值为: Excel: Type enum XlFileFormat { xlAddIn = 18, xlCSV = 6, xlCSVMac = 22, xlCSVMSDOS = 24, xlCSVWindows = 23, xlDBF2 = 7, xlDBF3 = 8, xlDBF4 = 11, xlDIF = 9, xlExcel2 = 16, xlExcel2FarEast = 27, xlExcel3 = 29, xlExcel4 = 33, xlExcel5 = 39, xlExcel7 = 39, xlExcel9795 = 43, xlExcel4Workbook = 35, xlIntlAddIn = 26, xlIntlMacro = 25, xlWorkbookNormal = -4143, xlSYLK = 2, xlTemplate = 17, xlCurrentPlatformText = -4158, xlTextMac = 19, xlTextMSDOS = 21, xlTextPrinter = 36, xlTextWindows = 20, xlWJ2WD1 = 14, xlWK1 = 5, xlWK1ALL = 31, xlWK1FMT = 30, xlWK3 = 15, xlWK4 = 38, xlWK3FM3 = 32, xlWKS = 4, xlWorks2FarEast = 28, xlWQ1 = 34, xlWJ3 = 40, xlWJ3FJ3 = 41, xlUnicodeText = 42, xlHtml = 44 }; Word: Type enum WdSaveFormat { wdFormatDocument = 0, wdFormatTemplate = 1, wdFormatText = 2, wdFormatTextLineBreaks = 3, wdFormatDOSText = 4, wdFormatDOSTextLineBreaks = 5, wdFormatRTF = 6, wdFormatUnicodeText = 7, wdFormatEncodedText = 7, wdFormatHTML = 8 }; PPT: enum PpSaveAsFileType { ppSaveAsPresentation = 1, ppSaveAsPowerPoint7 = 2, ppSaveAsPowerPoint4 = 3, ppSaveAsPowerPoint3 = 4, ppSaveAsTemplate = 5, ppSaveAsRTF = 6, ppSaveAsShow = 7, ppSaveAsAddIn = 8, ppSaveAsPowerPoint4FarEast = 10, ppSaveAsDefault = 11, ppSaveAsHTML = 12, ppSaveAsHTMLv3 = 13, ppSaveAsHTMLDual = 14, ppSaveAsMetaFile = 15, ppSaveAsGIF = 16, ppSaveAsJPG = 17, ppSaveAsPNG = 18, ppSaveAsBMP = 19 }; */ /* 0x32. 删除本地文件 HRESULT DeleteLocalFile([in] BSTR strFilePath); 参数: strFileName:文件本地路径,如c:\\11.doc */ /* 0x33.创建临时文件 HRESULT GetTempFilePath([out,retval] BSTR* strValue); 返回: 临时文件的路径地址。使用完后,用DeleteLocalFile 删除 */ /* 0x34.设置文档显示模式 HRESULT ShowView([in] long dwViewType, [out,retval] long * pbool); dwViewType的可取值为: enum WdViewType { wdNormalView = 1, wdOutlineView = 2, wdPrintView = 3, wdPrintPreview = 4, wdMasterView = 5, //这个是大纲 wdWebView = 6 }; */ //大纲模式 document.all.FramerControl1.ShowView(5); /* 0x39:下载远程文件 HRESULT DownloadFile( [in] BSTR strRemoteFile, [in] BSTR strLocalFile, [out,retval] BSTR* strValue); 参数: strRemoteFile:远程路径地址,http or Ftp strLocalFile: 本地保存地址,if strLocalFile == NULL then Create Temp File and return TempFile's Path */ /* 0x40:增加Http上传时候的,附加其他文件 HRESULT HttpAddPostFile([in] BSTR strFileID, [in] BSTR strFileName, [out,retval] long* pbool); 参数: strFileID:文件的ID,供服务器端页面解析 strFileName: 本地文件地址 */ /* 0x41,0x42.获取详细的修订信息。 GetRevCount( [out,retval] long * pbool); GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); 例子如下 */ var vCount; vCount = document.all.FramerControl1.GetRevCount(); alert(vCount); var vOpt = 0; var vDate; for(var i=1; i<= vCount; i++){ vOpt = document.all.FramerControl1.GetRevInfo(i,2); if("1" == vOpt){ vOpt = "插入"; }else if("2" == vOpt){ vOpt = "删除"; }else{ vOpt = "未知操作"; } vDate = new String(document.all.FramerControl1.GetRevInfo(i,1)); vDate = parseFloat(vDate); alert(vDate); dateObj = new Date(vDate); alert(dateObj.getYear() + "年" + dateObj.getMonth() + 1 + "月" + dateObj.getDate() +"日" + dateObj.getHours() +"时" + dateObj.getMinutes() +"分" + dateObj.getSeconds() +"秒" ); alert("用户:"+document.all.FramerControl1.GetRevInfo(i,0) + "\r\n操作:" + vOpt + "\r\n内容:" + document.all.FramerControl1.GetRevInfo(i,3)); } /* 0x43.设置基本信息: HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); 1.设置文件只读密码 SetValue("password","::DOCPROP:PassWord"); 2.设置文件修改密码 SetValue("password","::DOCPROP:WritePW"); 返回值: 0 正确 -1:不支持此命令,请确定您的第二个参数没有传错 -127:异常 */ //设置文件只读密码 document.all.FramerControl1.SetValue("password","::DOCPROP:PassWord"); //设置文件修改密码 document.all.FramerControl1.SetValue("password","::DOCPROP:WritePW"); /* 0x44.设置文档变量,这个很少能用到 HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); strVarName: 变量名 strVlaue:变量值 lOpt: 操作类型, 按位 第一位为1: 表示update域关联的 第二位为1: 表示如果没有这个变量则添加 第三位为1: 未来支持 return: 0:OK -127:异常 */ /* 0x45: 分页保存 HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); strLocalFile:本地路径 lPageNum:页数 */

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

loa_loa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值