wps加载项概述
WPS 加载项是一套基于 Web 技术用来扩展 WPS 应用程序的解决方案。每个 WPS 加载项都对应打开了一个网页,并通过调用网页中 JavaScript 方法来完成其功能逻辑。 WPS 加载项打开的网页可以直接与 WPS 应用程序进行交互,同时一个 WPS 加载项中的多个网页形成了一个整体, 相互之间可以进行数据共享。 开发者不必关注浏览器兼容的问题,因为 WPS 加载项的底层是以 Chromium 开源浏览器项目为基础进行的优化扩展。 WPS 加载项具备快速开发、轻量化、跨平台的特性,目前已针对Windows/Linux操作系统进行适配。
简而言之:wps加载项不需要关注浏览器兼容的问题,之前的wps内嵌模式只适用于支持NPAPI的浏览器。
1. wps加载项准备工作
1.1 http上传下载服务
wps加载项需要wps程序先从远程拉取wps加载项的内容至本地,故需要一个http上传下载服务为wps程序提供加载项。wps官方程序提供的是nodejs的http上传下载服务,我这里提供的是一个简单的基于java的http上传下载服务。这里提供一个webservlet服务,代码如下:
package com.zzs.demo;
/**
* @Author ZechariahZheng
* @Date 2021-4-20 16:32
* @Version 1.0
* @description
*/
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.factory.annotation.Value;
@WebServlet({ "/WpsServlet/*" })
@Slf4j
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final boolean isWin = System.getProperty("os.name").toLowerCase().contains("win");
@Value("${wps.oa.downloadfile}")
String downloadPath;
@Value("${wps.oa.uploadfile}")
String uploadPath;
/**
* 下载文件
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uri = request.getRequestURI();
String filename = uri.substring(uri.lastIndexOf("/")+1);
String path = uri.substring(uri.indexOf("/", 1), uri.lastIndexOf("/"));
log.info("----path is:"+path);
log.info("----filename is:"+filename);
if (filename == null || filename.isEmpty()) {
log.info("please set file name ");
} else {
// 假设文件都在服务的根目录下
//String realFileName = request.getServletContext().getRealPath("/") + filename;
//如果是windows机器,替换路径
path = path.replaceAll("/", Matcher.quoteReplacement(File.separator))+'\\';
String realFileName = downloadPath + path + filename;
log.info("------"+realFileName);
// 实例化一个向客户端输出文件流
OutputStream outputStream = response.getOutputStream();
// 输出文件用的字节数组,每次向输出流发送600个字节
byte b[] = new byte[600];
// 要向客户端输出的文件
File fileload = new File(realFileName);
log.info(filename);
String utf8filename = URLEncoder.encode(filename, "UTF-8");
log.info(utf8filename);
response.setHeader("Content-disposition", "attachment; filename=" + utf8filename);
// 通知客户端:文件的MIME类型
response.setContentType("application/msword");
// 通知客户端:文件的长度
long fileLength = fileload.length();
String length = String.valueOf(fileLength);
response.setHeader("Content-length", length);
// 读取文件,并发送给客户端下载
FileInputStream inputStream = new FileInputStream(fileload);
int n = 0;
while ((n = inputStream.read(b)) != -1) {
outputStream.write(b, 0, n);
}
inputStream.close();
outputStream.close();
}
}
/**
* 上传文件
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
log.info("添加任务");
HttpSession session = request.getSession();
Cookie[] cookies = request.getCookies();
String value = "";
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload((FileItemFactory) factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
boolean isOk = false;
Map<Object, Object> param = new HashMap<>();
for (Object object : items) {
FileItem fileItem = (FileItem) object;
if (fileItem.isFormField()) {
log.info(fileItem.getFieldName() + ":" + fileItem.getString("utf-8") + ", size:"
+ fileItem.getSize());
param.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
continue;
}
String fieldName = fileItem.getFieldName();
// 必须要有文件名,需要客户端传参时注意
String fileName = fileItem.getName();
if (fileName.equals("blob"))
if (param.containsKey("filename")) {
fileName = param.get("filename").toString();
} else if (param.containsKey("fileName")) {
fileName = param.get("fileName").toString();
}
//String filePath = request.getSession().getServletContext().getRealPath("/") + fileName;
String filePath = uploadPath + fileName;
log.info(fieldName + ":" + filePath);
FileOutputStream fileOut = new FileOutputStream(filePath);
InputStream in = fileItem.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) > 0) {
fileOut.write(buffer, 0, len);
}
in.close();
fileOut.close();
response.setHeader("Content-disposition", "attachment; filename*=UTF-8''" + fileName);
response.getWriter().write(fileName.concat("上传成功"));
return;
}
} catch (FileUploadException e) {
e.printStackTrace();
}
response.sendError(404, "no ssison");
}
}
1.2 下载文件
将wps加载项文件jsplugins.xml存放在某个目录中,该目录在application.properties文件夹进行配置如图所示:(我配置在E:/file)
jsplugins.xml文件配置如下:
<!-- WPS加载项配置信息,在线和离线只有一个生效,不可同时存在 -->
<!-- WPS加载项:在线模式配置 Start -->
<!-- https://kdocs.cn/l/cBk8tsBIf [金山文档] jsplugins.xml配置文档.docx -->
<!--<jsplugins> -->
<!--<jspluginonline name="EtOAAssist" type="et" url="http://127.0.0.1:3888/plugin/et"/> -->
<!--<jspluginonline name="WpsOAAssist" type="wps" url="http://127.0.0.1:8080/WpsServlet/WpsOAAssist"/> -->
<!--<jspluginonline name="WppOAAssist" type="wpp" url="http://127.0.0.1:3888/plugin/wpp"/> -->
<!--<</jsplugins>-->
<!-- WPS加载项:在线模式配置 End -->
<!-- WPS加载项:离线模式配置 Start -->
<jsplugins>
<!--<jsplugin name="EtOAAssist" type="et" url="http://127.0.0.1:3888/plugins/v0.1/EtOAAssist.7z" version="0.1" /> -->
<jsplugin name="WpsOAAssist" type="wps" url="http://127.0.0.1:8080/WpsServlet/WpsOAAssist.7z" version="0.1" />
<!--<jsplugin name="WppOAAssist" type="wpp" url="http://127.0.0.1:3888/plugins/v0.1/WppOAAssist.7z" version="0.1" /> -->
</jsplugins>
<!-- WPS加载项:离线模式配置 End -->
这里采用wps加载项离线模式,在file文件夹中保存jsplugins.xml文件和WpsOAAssist.7z加载项文件。
1.3 wps配置设置
设置wps的配置文件,进行wps安装目录的如:D:\Kingsoft\WPS Office\11.8.2.8875\office6\cfgs,修改oem.ini文件。将JSPluginsServer配置为刚刚设置的下载路径,如下:
[Support]
Support2016SN=true
JsApiPlugin=true
JsApiShowWebDebugger=true
[setup]
OfdDefaultServiceProvider=0
LANG_ID=2052
BUILD_VERSION=11.8.2.8875
Industry=
SourceDir=oeminfo
[Server]
JSPluginsServer=http://127.0.0.1:8080/WpsServlet/jsplugins.xml
FinishActionFile=oeminfo\oem.exe
FinishActionParameter="/copydir=OemFile\\office6 /ShellVarContext=all /RelativeDir=INSTDIR /todir='office6'"
FinishActionWait=1
PlacedDir2=
FinishActionFile2=oeminfo\oem.exe
FinishActionParameter2="/leveladmin=1 /regdllfile='office6\\wpsdocframe.dll' /ShellVarContext=all /RelativeDir=INSTDIR"
FinishActionWait2=1
UninstActionFile=office6\cfgs\oeminfo\oem.exe
UninstActionParameter="/leveladmin=1 /unregdllfile='office6\\wpsdocframe.dll' /ShellVarContext=all /RelativeDir=INSTDIR"
UninstActionWait=1
UninstActionFile2=office6\cfgs\oeminfo\oem.exe
UninstActionParameter2="/ShellVarContext=all /RelativeDir=INSTDIR /rmdir='office6'"
UninstActionWait2=1
InstExeCount=2
UninstExeCount=2
[feature]
xn3QfP-XIpyKSU9I2xbCubad10=gn3QfP-XIpy4U3A385v-NVGs10
2. vue适配wps
wps提供官方的文件wpsjsrpcsdk.js,我对其做了重新封装wpsInvoke.js,如下:
export function _WpsInvoke(funcs, front, jsPluginsXml) {
var bUseHttps = false;
var info = {};
info.funcs = funcs;
var func = bUseHttps ? WpsInvoke.InvokeAsHttps : WpsInvoke.InvokeAsHttp;
func(WpsInvoke.ClientType.wps, // 组件类型
"WpsOAAssist", // 插件名,与wps客户端加载的加载的插件名对应
"dispatcher", // 插件方法入口,与wps客户端加载的加载的插件代码对应,详细见插件代码
info, // 传递给插件的数据
function (result) { // 调用回调,status为0为成功,其他是错误
if (result.status) {
if (bUseHttps && result.status == 100) {
WpsInvoke.AuthHttpesCert('请在稍后打开的网页中,点击"高级" => "继续前往",完成授权。')
return;
}
alert(result.message)
} else {
console.log(result.response)
showresult(result.response)
}
},
front,
jsPluginsXml)
}
vue初始化wps的时候,先导入两个js文件,然后初始化。如下:
import {wps_sdk} from '../api/wpsjsrpcsdk.js'
import {_WpsInvoke} from '../api/wpsInvoke.js'
createDocument() { //初始化插件
var uploadPath = prompt("请输入文档上传路径:", "http://127.0.0.1:8000/WpsServlet/")
var uploadFieldName = prompt("请输入文档上传到业务系统时自定义字段:", ".doc")
_WpsInvoke([{
"NewDoc": {
"uploadPath": uploadPath, // 保存文档上传路径
"uploadFieldName": uploadFieldName,
}
}],
true,
"http://127.0.0.1:8080/WpsServlet/jsplugins.xml") //后端提供的下载路径
},