說明 onlyoffice為一款開源的office線上編輯組件,提供word/excel/ppt編輯保存操作 以下操作均基於centos8系統,officeonly鏡像版本7.1.2.23 鏡像下載地址:https://yunpan.360.cn/surl_y87CKKcPdY4 (提取碼:1f92 ...
說明
onlyoffice為一款開源的office線上編輯組件,提供word/excel/ppt編輯保存操作
- 以下操作均基於centos8系統,officeonly鏡像版本7.1.2.23
- 鏡像下載地址:https://yunpan.360.cn/surl_y87CKKcPdY4 (提取碼:1f92)
- 已破解20連接限制
- 已導入常用中文字體,修改了字型大小
- 已取消上傳文件大小的限制,修改為500M
- 隱藏所有操作按鈕,隱藏onlyoffice圖標和名稱,只保基礎操作欄目
- 僅用於word文件和excel文件編輯/保存/查看
Linux安裝
yum設置
- 進入yum的repos目錄 cd /etc/yum.repos.d/
cd /etc/yum.repos.d/
- 修改所有的CentOS文件內容
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
- 更新yum源為阿裡鏡像
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo
yum clean all
yum makecache
- yum安裝測試是否可以yum安裝
yum install wget –y
- 安裝依賴包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
docker安裝
- 設置鏡像源
sudo yum-config-manager --add-repo
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 安裝docker-ce社區版
sudo yum install docker-ce --allowerasing
- 創建用戶組
建立 Docker 用戶組
sudo groupadd docker
添加當前用戶到 docker 組
sudo usermod -aG docker $USER
啟動docker
systemctl start docker.service
服務開機啟動
systemctl enable docker.service
- 安裝docker圖形化管理頁面
docker volume create portainer_data
docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
訪問http://localhost:9000/進行管理端初始化設置
onlyoffice部署
- 上傳鏡像文件到伺服器
- 載入鏡像
docker load < onlyoffice.tar
- 查看鏡像
docker images
- 啟動容器
sudo docker run --name=onlyoffice -i -t -d -p 8088:80 --restart=always 鏡像id
Windows安裝
- 安裝VMWare虛擬機,安裝centos8系統,參照上述步驟
- 網路配置成NAT模式,虛擬機進入centos系統後配置固定ip
- NAT網卡設置埠轉發,轉發9000和8088埠,主機埠和虛擬埠一致
添加字體
- 找到對應字體,如果是windows下的字體進入C:\Windows\Fonts 搜索
- 安裝High-Logic FontCreator 運行Keygen.exe 點擊generate獲取激活碼
- 工具下載:https://yunpan.360.cn/surl_y87CK8RNr8N (提取碼:7059)
- 打開字體 font=>properties
- 修改 font family 為custom 中對應的中文 ,導出字體
- 上傳修改後的字體到liunx文件下 eg:/home/fonts/
- 查看OnlyOffice容器id
docker ps
- 進入OnlyOffice容器
docker exec -it 容器id /bin/bash
- 刪除字體緩存
cd /var/www/onlyoffice/documentserver/fonts
rm -rf *
- 複製字體到 /var/www/onlyoffice/documentserver/core-fonts 下
docker cp /home/fonts onlyoffice:/var/www/onlyoffice/documentserver/core-fonts
- 進入onlyoffice容器執行刷新
/usr/bin/documentserver-generate-allfonts.sh
- 瀏覽器清除緩存重新刷新
對接業務系統
onlyfiice部署完畢後會有一個服務地址,例如 http://localhost:8088/
引入api.js
不能下載文件本地引用,一定要線上引用
<script type="text/javascript" src="http://localhost:8088/web-apps/apps/api/documents/api.js"></script>
聲明dom
頁面添加一個div,用於渲染編輯器
<div id="placeholder" class="nav" style="width: 100%; height: 100%"></div>
頁面渲染
參數說明
key:對應文檔的一個標識,建議前端隨機生成,防止重覆
url:打開文檔的地址,返迴流數據
fileType:文檔類型,例如:doc/docx
title:文件名稱,例如:2022年工作方案.docx
model:打開模式,例如:edit(編輯模式)/view(閱讀模式)
callbackUrl:文件修改後保存回調地址
function initDoc(key, url, fileType, title, model, callbackUrl) {
let config = {
"document": {
"documentType": "text",
"width": "100%", //打開視窗寬度
"height": "100%", //打開視窗高度
"fileType": fileType, //文檔類型
"key": key, //定義用於服務識別文檔的唯一文檔標識符。每次編輯和保存文檔時,都必須重新生成密鑰。長度限製為128個符號。
"title": title, //為查看或編輯的文檔定義所需的文件名,該文件名也將在下載文檔時用作文件名。長度限製為128個符號。
"url": url, //定義存儲原始查看或編輯的文檔的絕對URL
"info": {
"owner": "王重陽", //文件創建者名稱
"sharingSettings": [ //文件對應用戶的操作許可權配置
{
"permissions": "Full Access", // 完全操作許可權-Full Access,只讀許可權-Read Only 拒絕訪問-Deny Access
"user": "林朝英" //有次許可權的用戶
},
{
"permissions": "Read Only",
"user": "周伯通"
},
],
"uploaded": "2010-07-07 3:46 PM" //文件創建時間
},
//文檔許可權參數
"permissions": {
"edit": true, //(文件是否可以編輯,false時文件不可編輯)
"fillForms": true, //定義是否能在文檔中填充表單
"print": true, //定義文檔是否能列印
"review": false, //第一是否顯示審閱文檔菜單
"comment": true, //定義是否可以註釋文檔。如果註釋許可權設置為“ true”,則文檔側欄將包含“註釋”菜單選項;只有將mode參數設置為edit時才生效,預設值與edit參數的值一致。
"copy": true, //是否允許您將內容複製到剪貼板。預設值為true。
"download": true, //定義是否可以下載文檔或僅線上查看或編輯文檔。如果下載許可權設置為“false”下載為菜單選項將沒有。預設值為true。
"modifyContentControl": true, //定義是否可以更改內容控制項設置。僅當mode參數設置為edit時,內容控制項修改才可用於文檔編輯器。預設值為true。
"modifyFilter": true, //定義過濾器是否可以全局應用(true)影響所有其他用戶,或局部應用(false),即僅適用於當前用戶。如果將mode參數設置為edit,則過濾器修改僅對電子錶格編輯器可用。預設值為true。
}
},
// type: "embedded",
//打開文檔類型
// text對應各種文檔類型(.doc, .docm, .docx, .dot, .dotm, .dotx, .epub, .fodt, .htm, .html, .mht, .odt, .ott, .pdf, .rtf, .txt, .djvu, .xps)
//spreadsheet對應表格類型(.csv, .fods, .ods, .ots, .xls, .xlsm, .xlsx, .xlt, .xltm, .xltx)
//presentation對應PPT類型(.fodp, .odp, .otp, .pot, .potm, .potx, .pps, .ppsm, .ppsx, .ppt, .pptm, .pptx)
"editorConfig": { //編輯配置
"createUrl": "http://docServer:port/url-to-create-document/", //指定創建文件的頁面,添加該配置後文檔伺服器插件才會顯示新建文件按鈕
"mode": model, //文檔操作模式 view 視圖模式不可編輯 edit 編輯模式可編輯文檔
"callbackUrl": callbackUrl, //保存文件時的回調地址
"lang": "zh-CN", //語言環境
"customization": { //定製部分允許自定義編輯器界面,使其看起來像您的其他產品,並更改是否存在其他按鈕,鏈接,更改徽標和編輯者所有者詳細信息。
"help": false, //定義是顯示還是隱藏“幫助”菜單按鈕。預設值為true。
"hideRightMenu": false, //定義在第一次載入時是顯示還是隱藏右側菜單。預設值為false。
"autosave": false, //定義是啟用還是禁用“自動保存”菜單選項。請註意,如果您在菜單中更改此選項,它將被保存到瀏覽器的localStorage中。預設值為true。
"forcesave": true, //定義保存按鈕是否顯示預設false
"chat": false, //定義“聊天”菜單按鈕是顯示還是隱藏;請註意,如果您隱藏“聊天”按鈕,則相應的聊天功能也將被禁用。預設值為true。
"commentAuthorOnly": false, //定義用戶是否只能編輯和刪除他的評論。預設值為false。
"comments": false, //定義是顯示還是隱藏“註釋”菜單按鈕;請註意,如果您隱藏“評論”按鈕,則相應的評論功能將僅可用於查看,評論的添加和編輯將不可用。預設值為true。
"compactHeader": false, //定義是否將菜單欄放在在徽標旁邊使界面更加緊湊預設false。
"compactToolbar": false, //定義顯示的頂部工具欄類型是完整(false)還是緊湊true。預設值為false 多餘菜單將在右側摺疊點擊顯示。
"compatibleFeatures": false, //定義僅與OOXML格式相容的功能的使用。例如,不要在整個文檔上使用註釋。預設值為false。
"macros": false, //定義是否將運行文檔巨集以及可用的巨集設置。預設值為true。
"macrosMode": "warn", //定義是否將運行文檔巨集。可以採用以下值: disable -根本不運行;enable -自動運行所有巨集;warn -警告巨集並請求允許運行。預設值為original。
"plugins": false, //定義是否將啟動插件並可用。預設值為true。
"showReviewChanges": false, //定義在載入編輯器時是否自動顯示或隱藏審閱更改面板。預設值為false。
"spellcheck": false, //定義在載入編輯器時是否自動打開或關閉拼寫檢查器。拼寫檢查器僅適用於文檔編輯器和演示文稿編輯器。預設值為true。
"toolbarNoTabs": false, //定義是突出顯示頂部工具欄選項卡樣式。預設值為false。
"unit": "cm", //定義在標尺和對話框中使用的度量單位。可以採用以下值:cm -釐米,pt-點,inch -英寸。預設值為釐米(cm)。
"zoom": 100, //定義以百分比為單位的文檔顯示縮放值。可以取大於0的值。對於文本文檔和演示文稿,可以將此參數設置為-1(使文檔適合頁面選項)或-2(使文檔頁面寬度適合編輯器頁面)。預設值為100。
"customer": { //關於 文檔編輯器的顯示信息
"address": "My City, 123a-45", //有權訪問編輯或編輯作者的公司或個人的郵政地址,
"info": "Some additional information", //有關您希望其他人認識的公司或個人的一些其他信息,
"logo": "https://example.com/logo-big.png", //圖片徽標的路徑(此文件沒有特別建議,但是如果使用透明背景的.png格式會更好)。圖片必須具有以下尺寸:432x70,
"mail": "[email protected]", //有權訪問編輯者或編輯者的公司或個人的電子郵件地址
"name": "歐陽鋒", //該公司或個人的誰可以訪問編輯或編輯作者,名稱
"www": "example.com" //以上公司或個人的家庭網站地址,
},
"feedback": { //反饋配置信息
"url": "https://example.com", //單擊“反饋和支持”菜單按鈕時將打開的網站地址的絕對URL ,
"visible": false //顯示或隱藏“反饋和支持”菜單按鈕,
},
"goback": { //定義“打開文件位置”菜單按鈕和右上角按鈕的設置。該對象具有以下參數:
"blank": true, //在新的瀏覽器選項卡/視窗(如果值設置為true)或當前選項卡(如果值設置為false)中打開網站。預設值為true,
"requestClose": false, //定義如果單擊“打開文件位置”按鈕,則調用events.onRequestClose事件,而不是打開瀏覽器選項卡或視窗。預設值為false,
"text": "Open file location", //將在“打開文件位置”菜單按鈕和右上角按鈕(即,而不是“轉到文檔”)上顯示的文本,
"url": "https://example.com" //單擊“打開文件位置”菜單按鈕時將打開的網站地址的絕對URL ,
},
"logo": {
"image": "https://example.com/logo.png", //圖像文件的路徑,用於在普通工作模式下顯示(即,在所有編輯器的查看和編輯模式下)。圖片必須具有以下尺寸:172x40,
"imageEmbedded": "https://example.com/logo_em.png", //用於以嵌入式模式顯示的圖像文件的路徑(請參閱config部分以瞭解如何定義嵌入式文檔類型)。圖片必須具有以下尺寸:248x40,
"url": "https://www.baidu.com" //某人單擊徽標圖像時將使用的絕對URL(可用於轉到您的網站等)。保留為空字元串或null以使徽標不可單擊,
},
},
"user": { //用戶信息
"id": "admin", //用戶ID
"name": "操作員" //用戶全名稱
},
"embedded": { //Embedded部分僅適用於嵌入式文檔類型(請參閱config部分以瞭解如何定義嵌入式文檔類型)。它允許更改設置,這些設置定義嵌入式模式下按鈕的行為。
"embedUrl": "https://example.com/embedded?doc=exampledocument1.docx", //定義文檔的絕對URL,以作為嵌入到網頁中的文檔的源文件
"fullscreenUrl": "https://example.com/embedded?doc=exampledocument1.docx#fullscreen", //定義將以全屏模式打開的文檔的絕對URL。
"saveUrl": "https://example.com/download?doc=exampledocument1.docx", //定義允許將文檔保存到用戶個人電腦上的絕對URL。
"shareUrl": "https://example.com/view?doc=exampledocument1.docx", //定義允許其他用戶共用此文檔的絕對URL。
"toolbarDocked": "top" //定義嵌入式查看器工具欄的位置,可以為top或bottom。
}
},
"events": { //事件配置
// onAppReady,//-將應用程式載入到瀏覽器時調用的函數。
// onCollaborativeChanges //-當文檔由其他用戶在嚴格共同編輯模式下共同編輯時調用的函數。
// onDocumentReady,//-將應用程式載入到瀏覽器時調用的函數。
// onDocumentStateChange,//-修改文檔時調用的函數。這就是所謂的使用參數:{真正的“數據”}在當前用戶編輯文檔以及與參數:{“數據”:假}在當前用戶的更改發送到文檔編輯服務。
// onDownloadAs,//-調用downloadAs方法時,使用指向已編輯文件的絕對URL調用的函數。在data參數中發送要下載的文檔的絕對URL 。
// onError,//-發生錯誤或其他特定事件時調用的函數。錯誤消息在data參數中發送。
// onInfo,//-應用程式打開文件時調用的函數。該模式在data.mode參數中發送。可以查看或編輯。
// onMetaChange,//-通過meta命令更改文檔的元信息時調用的函數。文檔名稱通過data.title參數發送。
// onOutdatedVersion,//-使用舊的document.key值打開文檔進行編輯時,顯示錯誤後調用的函數,該值用於編輯先前的文檔版本並已成功保存。調用此事件時,必須使用新的document.key重新初始化編輯器。
// onReady,//-將應用程式載入到瀏覽器時調用的函數。自從5.0版本不推薦使用,請使用onAppReady代替
// onRequestClose,//-結束編輯器的工作並且必須關閉編輯器時調用的函數。
// onRequestCompareFile,//-用戶嘗試通過單擊“存儲中的文檔”按鈕來選擇要比較的文檔時調用的函數。要選擇要比較的文檔,必須調用setRevisedFile方法。如果未聲明該方法,則不會顯示“來自存儲的文檔”按鈕。
// onRequestCreateNew,//-用戶嘗試通過單擊“新建”按鈕來創建文檔時調用的函數。使用此方法代替createUrl欄位。如果未聲明該方法且未指定createUrl,則將不會顯示“創建新”按鈕。
// onRequestEditRights,//-用戶嘗試通過單擊“編輯文檔”按鈕嘗試將文檔從視圖切換到編輯模式時調用的函數。調用該函數時,必須在編輯模式下再次初始化編輯器。如果未聲明該方法,則不會顯示“編輯”按鈕。
// onRequestHistory,//-用戶嘗試通過單擊“版本歷史記錄”按鈕顯示文檔版本歷史記錄時調用的函數。要顯示文檔版本歷史,您必須調用refreshHistory方法。如果未聲明該方法和onRequestHistoryData方法,則不會顯示“版本歷史記錄”按鈕。
// onRequestHistoryClose,//-當用戶嘗試通過單擊“關閉歷史記錄”按鈕來查看文檔版本歷史記錄時,試圖調用該文檔時調用的函數。調用該函數時,必須在編輯模式下再次初始化編輯器。如果未聲明該方法,則不會顯示“關閉歷史記錄”按鈕。
// onRequestHistoryData,//-用戶嘗試單擊文檔版本歷史記錄中的特定文檔版本時調用的函數。
// onRequestInsertImage,//-用戶嘗試通過單擊“保存圖像”按鈕插入圖像時調用的函數。圖像插入的類型在參數data.c中指定。
// onRequestRename,//-用戶嘗試通過單擊“重命名...”按鈕重命名文件時調用的函數。
// onRequestRestore,//-用戶單擊版本歷史記錄中的“還原”按鈕來還原文件版本時調用的函數。
// onRequestSaveAs,//-用戶嘗試通過單擊“另存為...”按鈕保存文件時調用的函數。文檔的標題和要下載的文檔的絕對URL在data參數中發送。如果未聲明該方法,則不會顯示“另存為...”按鈕。
// onRequestSharingSettings,//-用戶單擊“更改訪問許可權”按鈕來管理文檔訪問許可權時調用的函數。必須調用setSharingSettings方法來更新有關允許與其他用戶共用文檔的設置的信息。如果未聲明該方法,則不會顯示“更改訪問許可權”按鈕。
// onRequestUsers,//-評論者可以選擇要在評論中提及的其他用戶時調用的函數。要設置用戶列表,必須調用setUsers方法。
// onWarning,//-發生警告時調用的函數。警告消息在data參數中發送。
// "onDocumentStateChange": function() {
// }, //文檔改變後的回調
//"onDocumentReady" : onDocumentReady, //文檔初始化準備好後的回調
},
};
var docEditor = new DocsAPI.DocEditor("placeholder", config);
}
數據介面
- 下載文件
返回數據流即可,示例如下
@GetMapping("/download")
@ResponseBody
public void download(@RequestParam("attguid") String attguid, HttpServletRequest request, HttpServletResponse response) throws Exception {
AttachmentDO attachment = attachmentService.selectOne(attguid);
String filePath = "";
//雲上傳的附件
if (attachment.getVirtualpath().contains("ReadAlOSS")) {
if (attachment.getCanedit() == null || attachment.getCanedit() == 20) {
String fileurl = aliUtil.readOSSFile(attachment);
if (!StringUtil.isEmpty(fileurl)) {
response.sendRedirect(fileurl);
}
} else if (attachment.getCanedit() == 30) {
String fileurl = huaWeiUtil.readOBSFile(attachment);
System.out.println(fileurl);
if (!StringUtil.isEmpty(fileurl)) {
response.sendRedirect(fileurl);
}
} else if (attachment.getCanedit() == 40) {
String fileurl = minioUtil.readMinioFile(attachment);
System.out.println(fileurl);
if (!StringUtil.isEmpty(fileurl)) {
response.sendRedirect(fileurl);
}
}
}
//本地文件
String configPath = frameConfig.getAttachPath();
filePath = configPath + attachment.getVirtualpath();
File file = new File(filePath);
if (file.exists()) {
String filename = attachment.getFilename();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
response.setCharacterEncoding("utf-8");
response.setContentLength((int) file.length());
byte[] buff = new byte[(int) file.length()];
BufferedInputStream bufferedInputStream = null;
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
int i = 0;
while ((i = bufferedInputStream.read(buff)) != -1) {
outputStream.write(buff, 0, i);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 保存文件
解析傳遞的參數,獲取文件url下載到本地後,進行自定義業務操作
@PostMapping("/save")
@ResponseBody
public void save(@RequestParam Map<String, String> map, HttpServletRequest request, HttpServletResponse response) {
PrintWriter writer = null;
String body = "";
String attguid = request.getParameter("attguid");
try {
writer = response.getWriter();
Scanner scanner = new Scanner(request.getInputStream());
scanner.useDelimiter("\\A");
body = scanner.hasNext() ? scanner.next() : "";
scanner.close();
} catch (Exception ex) {
writer.write("get request.getInputStream error:" + ex.getMessage());
return;
}
if (body.isEmpty()) {
throw new CustomerRuntimeException("ONLYOFFICE回調保存請求體未空");
}
JSONObject jsonObj = JSONObject.parseObject(body);
int status = (Integer) jsonObj.get("status");
int saved = 0;
String key = jsonObj.get("key").toString();
if (status == 2 || status == 3 || status == 6) //MustSave, Corrupted
{
String downloadUri = (String) jsonObj.get("url");
System.out.println(downloadUri);
try {
String filePath = "tempfiles/onlyoffice/savedownload/";
FileUtil.initfloderPath(filePath);
String fileName = CommonUtil.getNewGuid();
HttpUtil.downLoadFromUrl(downloadUri, filePath, fileName);
attachLogic.updateAttachContent(attguid, FileUtil.getBytes(filePath + fileName));
} catch (Exception ex) {
saved = 1;
ex.printStackTrace();
}
}
writer.write("{\"error\":" + saved + "}");
}
外部按鈕接入
以保存按鈕為例
獲取編輯器iframe按鈕中的slot-btn-dt-save節點元素,定位div下的button按鈕,進行js模擬點擊實現保存操作
通過監聽iframe的message來捕獲到保存結束頁面彈出自定義提示
上述操作因編輯器html頁面和onlyoffice服務存在跨域問題,需要配置nginx代理到統一ip埠下
function HandleSave() {
var frameDocument = document.getElementsByTagName("iframe")[0].contentDocument;
frameDocument.getElementById("slot-btn-dt-save").getElementsByTagName("button")[0].click();
}
window.onmessage = function (event) {
var data = JSON.parse(event.data);
if (data.event == "onDocumentStateChange" && data.data == false) {
OpenSuccessMessage("保存成功")
}
}