Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de93471c32 | ||
|
|
bbfb6ea88d | ||
|
|
cad0747ac4 | ||
|
|
af8acf5516 | ||
|
|
98e82fce76 | ||
|
|
986ba53816 | ||
|
|
88052b6986 | ||
|
|
c593e47adc | ||
|
|
1ae3b82282 | ||
|
|
7c9681b236 | ||
|
|
ff6f67a160 |
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
@@ -0,0 +1,127 @@
|
||||
木兰宽松许可证, 第2版
|
||||
|
||||
木兰宽松许可证, 第2版
|
||||
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体”是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
6. 语言
|
||||
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
|
||||
|
||||
条款结束
|
||||
|
||||
如何将木兰宽松许可证,第2版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
||||
|
||||
Mulan Permissive Software License,Version 2
|
||||
|
||||
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
||||
January 2020 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular Contributor under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its Affiliates.
|
||||
|
||||
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
6. Language
|
||||
|
||||
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
|
||||
|
||||
END OF THE TERMS AND CONDITIONS
|
||||
|
||||
How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software
|
||||
|
||||
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
|
||||
|
||||
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
|
||||
|
||||
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
|
||||
|
||||
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
|
||||
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
@@ -1,3 +1,336 @@
|
||||
# OnlyOffice-Backend
|
||||
|
||||
OnlyOffice在线文档
|
||||
# Spring-Boot-onlyOffice(集成onlyOffice服务)
|
||||
|
||||
springboot集成onlyOffice的实现。在参考网络上的资料结合自身实际情况总结,让集成oo方便快捷。 封装了oo服务的API和统一了配置。
|
||||
- 在线编辑,查看,转换
|
||||
|
||||
|
||||
* onlyOffice.yml配置文件
|
||||
* 如果解决了你地方问题,请给个 **star**
|
||||
-----------------------------------
|
||||
# 对外使用的java类 —— OnlyServiceAPI
|
||||
## 核心方法
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>方法名称</th>
|
||||
<th>参数</th>
|
||||
<th>参数说明</th>
|
||||
<th>返回值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">openDocument()</td>
|
||||
<td> Map<String,Object> map</td>
|
||||
<td> 文件数据信息<br>
|
||||
{<br>
|
||||
必填 fileId<br>
|
||||
必填 fileName<br>
|
||||
必填 fileType<br>
|
||||
必填 fileSize<br>
|
||||
可用携带其它值<br>
|
||||
}
|
||||
</td>
|
||||
<td rowspan="3">
|
||||
<pre>
|
||||
{
|
||||
"editorConfig": {
|
||||
"mode": "edit",
|
||||
"customization": {
|
||||
"feedback": {
|
||||
"visible": false
|
||||
},
|
||||
"help": false,
|
||||
"goback": {
|
||||
"blank": false
|
||||
},
|
||||
"macros": false,
|
||||
"autosave": false,
|
||||
"comments": false,
|
||||
"review": {},
|
||||
"hideRightMenu": true,
|
||||
"anonymous": {
|
||||
"request": false
|
||||
},
|
||||
"forcesave": true,
|
||||
"logo": {},
|
||||
"hideNotes": true
|
||||
},
|
||||
"plugins": {
|
||||
"pluginsData": [],
|
||||
"autostart": []
|
||||
},
|
||||
"callbackUrl": "http://172.31.240.1:9090/onlyOffice/save",
|
||||
"lang": "zh-CN",
|
||||
"user": {
|
||||
"name": "TongHuic7bba5",
|
||||
"id": "c7bba5"
|
||||
}
|
||||
},
|
||||
"docServiceApiUrl": "http://172.31.240.1:8886/web-apps/apps/api/documents/api.js",
|
||||
"documentType": "word",
|
||||
"document": {
|
||||
"permissions": {
|
||||
"edit": true,
|
||||
"chat": false,
|
||||
"review": false
|
||||
},
|
||||
"title": "fdfs.docx",
|
||||
"fileType": "docx",
|
||||
"key": "63f560ec03a94654b10cd4fdeebec05a",
|
||||
"url": "http://172.31.240.1:9090/download/09cee8767dd3476280fa865bacfaf213",
|
||||
"info": {
|
||||
"sharingSettings": [{
|
||||
"isLink": true,
|
||||
"permissions": ["Full Access"],
|
||||
"user": "TongHuic7bba5"
|
||||
}],
|
||||
"created": "2023-08-05 21:38:25"
|
||||
}
|
||||
},
|
||||
"type": "desktop",
|
||||
"token": ""
|
||||
}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String mode</td>
|
||||
<td>打开方式 <br>edit<br>view</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>boolean collaborativeEditing</td>
|
||||
<td>是否协同编辑</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>handlerStatus()</td>
|
||||
<td>JSONObject jsonObject</td>
|
||||
<td>onlyOffice 回调传来的值。<br>https://api.onlyoffice.com/editors/callback</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">save():触发保存回调。</td>
|
||||
<td>String key</td>
|
||||
<td>是openDocument()返回值中的key</td>
|
||||
<td rowspan="2">String : 提示信息</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String userId</td>
|
||||
<td>用户Id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="5">converted()</td>
|
||||
<td>String filetype</td>
|
||||
<td>文件类型</td>
|
||||
<td rowspan="5">转换后的文件下载地址</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String fileId</td>
|
||||
<td>文件Id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String outputtype</td>
|
||||
<td>转化类型</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String title</td>
|
||||
<td>转换后的文件名称</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String password</td>
|
||||
<td>文档密码</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**注意:**
|
||||
* 外部触发保存操作,save()方法。
|
||||
* `autosave`/`forcesave` 参数为默认值时有效
|
||||
* 修改文件后,没有执行回调方法。在点击保存后执行回调
|
||||
|
||||

|
||||
|
||||
|
||||
快速使用
|
||||
-----------------------------------
|
||||
|
||||
- 必须的依赖
|
||||
|
||||
``` pom
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.inversoft</groupId>
|
||||
<artifactId>prime-jwt</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
- 定义关键接口(oo服务回调使用) `重要`
|
||||
|
||||
1.保存接口
|
||||
```
|
||||
参考:demo/controller/IndexController.saveFile()
|
||||
对应配置文件参数:oo.call-back-url
|
||||
回调状态
|
||||
0 - 找不到具有密钥标识符的文档
|
||||
1 - 正在编辑文档(打开文件回调)
|
||||
2 - 文档已准备好保存
|
||||
3 - 发生文档保存错误
|
||||
4 - 不作任何更改就关闭文档(关闭回调)
|
||||
6 - 正在编辑文档,但保存当前文档状态(保存回调)
|
||||
7 - 强制保存文档时发生错误
|
||||
```
|
||||
|
||||
2.下载文件地址
|
||||
```
|
||||
参考:demo/controller/IndexController.download()
|
||||
对应配置文件参数:oo.download-file
|
||||
对应openDocument()方法返回值中的 document.url
|
||||
打开文件后oo服务要下载对应的文件
|
||||
```
|
||||
- 实现SaveFileProcessor类
|
||||
```
|
||||
参考:demo.service.DemoService
|
||||
```
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> 方法名称 </th>
|
||||
<th> 方法说明 </th>
|
||||
<th> 参数 </th>
|
||||
<th> 参数说明 </th>
|
||||
<th> 返回值 </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">saveBeforeInitialization()</td>
|
||||
<td rowspan="3">保存前置方法</td>
|
||||
<td>Map<String, Object> map</td>
|
||||
<td>在openDocument()方法中传入的文件数据信息</td>
|
||||
<td rowspan="3"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>byte[] bytes</td>
|
||||
<td>文件二进制数据</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String fileExtension</td>
|
||||
<td>文件后缀</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="4">save()</td>
|
||||
<td rowspan="4">保存方法,实现自己的保存逻辑</td>
|
||||
<td>Map<String, Object> map</td>
|
||||
<td>在openDocument()方法中传入的文件数据信息</td>
|
||||
<td rowspan="4">Map<String, Object> 更新内存中的信息</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>byte[] bytes</td>
|
||||
<td>文件二进制数据</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>byte[] changes</td>
|
||||
<td>当前文件和保存之前文件的区别。changes.zip</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String key</td>
|
||||
<td>是openDocument()返回值中的key</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="3">saveAfterInitialization()</td>
|
||||
<td rowspan="3">保存后置方法</td>
|
||||
<td>Map<String, Object> map</td>
|
||||
<td>在openDocument()方法中传入的文件数据信息</td>
|
||||
<td rowspan="3"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>byte[] bytes</td>
|
||||
<td>文件二进制数据</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>String fileExtension</td>
|
||||
<td>文件后缀</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## 更新记录
|
||||
|
||||
- [x] 修复关闭文件后快速再次打开该文件后,保存时报错的bug 2023/11/10
|
||||
- [x] 修复内存文件信息在保存后没有修改的bug 2023/10/23
|
||||
- [x] 实现和编辑器的数据通信 2023/9/9 (更新链接)
|
||||
https://blog.xenosp.cn/posts/87468caf/
|
||||
- [x] 修复文件转pdf时只有第一页的bug 2023/8/13
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
|
||||
|
||||
# 页面集成
|
||||
### html
|
||||
```
|
||||
参考 onlyOffice.html
|
||||
style.js 中的openDocument()
|
||||
```
|
||||
### vue
|
||||
```
|
||||
参考 onlyOffice.vue
|
||||
```
|
||||
-----------------------------------
|
||||
|
||||

|
||||
### 编辑
|
||||
|
||||

|
||||

|
||||

|
||||
### 查看
|
||||
|
||||

|
||||

|
||||

|
||||
### 文件转换
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,3 @@
|
||||
## Overview
|
||||
|
||||
(Linux服务器安装好)把当前文件夹放到路径: /var/www/onlyoffice/documentserver/sdkjs-plugins
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name" : "Listener",
|
||||
"guid" : "asc.{A8705DEE-7544-4C33-B3D5-168406D92F72}",
|
||||
"baseUrl" : "",
|
||||
"variations" : [
|
||||
{
|
||||
"description" : "Listener",
|
||||
"url" : "index.html",
|
||||
"icons" : ["resources/img/icon.png", "resources/img/icon@2x.png"],
|
||||
"isViewer" : false,
|
||||
"EditorsSupport" : ["word", "cell", "slide"],
|
||||
"isVisual" : false,
|
||||
"isModal" : true,
|
||||
"isInsideMode" : false,
|
||||
"isSystem" : true,
|
||||
"initDataType" : "none",
|
||||
"initData" : "",
|
||||
"isUpdateOleOnResize" : true,
|
||||
"buttons" : [],
|
||||
"events" : [
|
||||
"onExternalPluginMessage"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
(c) Copyright Ascensio System SIA 2020
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Listener</title>
|
||||
<script type="text/javascript" src="../v1/plugins.js"></script>
|
||||
<script type="text/javascript" src="../v1/plugins-ui.js"></script>
|
||||
<link rel="stylesheet" href="../v1/plugins.css">
|
||||
<script type="text/javascript" src="scripts/code.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2020
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
(function(window, undefined){
|
||||
|
||||
window.Asc.plugin.init = function() {
|
||||
console.log("插件初始化")
|
||||
|
||||
// none
|
||||
window.parent.Common.Gateway.on('internalcommand', function(data){
|
||||
console.log(data); // 接受到123参数console.log(data.data); // 接受到321参数
|
||||
var data_ = data.data
|
||||
switch (data.command){
|
||||
case "insertText":
|
||||
let text = "${"+data_.text+"}"
|
||||
window.Asc.plugin.executeMethod ("PasteText", [text]);
|
||||
if(window.Asc.plugin.info.editorType == 'cell'){
|
||||
CorrectText('insertText')
|
||||
}
|
||||
break;
|
||||
case 'getText':
|
||||
CorrectText('getText')
|
||||
break
|
||||
}
|
||||
});
|
||||
|
||||
var _info = window.Asc.plugin.info;
|
||||
var userName =_info.userName
|
||||
var userId = _info.userId
|
||||
|
||||
function CorrectText (command) {
|
||||
let data = {
|
||||
command:command,
|
||||
text:""
|
||||
}
|
||||
switch (window.Asc.plugin.info.editorType) {
|
||||
case 'word':
|
||||
case 'slide': {
|
||||
window.Asc.plugin.executeMethod ("GetSelectedText", [{"Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9)}], function (e) {
|
||||
let text = e.trim()
|
||||
data.text = text
|
||||
window.parent.parent.postMessage(JSON.stringify(data),'*');
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'cell': {
|
||||
Asc.scope.command = command;
|
||||
window.Asc.plugin.callCommand (function () {
|
||||
var oWorksheet = Api.GetActiveSheet();
|
||||
var oActiveCell = oWorksheet.GetActiveCell();
|
||||
let str = oActiveCell.Text
|
||||
if(str.indexOf("${") != -1){
|
||||
str = str.substring(2,str.length-1)
|
||||
}
|
||||
let data = {
|
||||
command:Asc.scope.command,
|
||||
sheetName:oWorksheet.Name,
|
||||
text:str,
|
||||
x:oActiveCell.Row,
|
||||
y:oActiveCell.Col
|
||||
}
|
||||
|
||||
localStorage.setItem('dataInfo', JSON.stringify(data))
|
||||
}, false,false,function(){
|
||||
window.parent.parent.postMessage(localStorage.getItem('dataInfo'),'*');
|
||||
localStorage.removeItem('dataInfo')
|
||||
});
|
||||
/* window.Asc.plugin.executeMethod ("GetSelectedText", [{"Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9)}], function (e) {
|
||||
let text = e.trim()
|
||||
console.log(text)
|
||||
data.text = text
|
||||
if (text == '') {
|
||||
text = text.replace (/\t/g, '\n');
|
||||
window.parent.parent.postMessage(JSON.stringify(data),'*');
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
});*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.Asc.plugin.button = function(id) {
|
||||
};
|
||||
|
||||
})(window, undefined);
|
||||
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"zh-CN"
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.6</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.oo</groupId>
|
||||
<artifactId>Spring-Boot-onlyOffice</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>Spring-Boot-onlyOffice</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.1.22</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.17</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.inversoft</groupId>
|
||||
<artifactId>prime-jwt</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<!--websocket-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.oo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
|
||||
|
||||
@SpringBootApplication(exclude = {MultipartAutoConfiguration.class,})
|
||||
public class OnlyofficeDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OnlyofficeDemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.oo.demo.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @Author: ymbgy
|
||||
* @Date: 2022-06-13 13:31
|
||||
*/
|
||||
@Configuration
|
||||
public class CrossOriginConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins("*")
|
||||
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
|
||||
.maxAge(3600)
|
||||
.allowCredentials(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.oo.demo.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.multipart.MultipartResolver;
|
||||
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.config
|
||||
*
|
||||
* @CreateTime: 2022-12-01 17:37
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class MultipartResolverConfig {
|
||||
@Bean(name="multipartResolver")
|
||||
public MultipartResolver multipartResolver() {
|
||||
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
|
||||
resolver.setDefaultEncoding("UTF-8");
|
||||
resolver.setResolveLazily(true);
|
||||
resolver.setMaxInMemorySize(102400000);
|
||||
resolver.setMaxUploadSize(102400000);
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.oo.demo.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @Author TongHui MybatisPlusConfig.java
|
||||
* @Description 配置分页插件
|
||||
* @Date 2022/3/24 9:51
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.oo.demo.config;
|
||||
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package com.oo.demo.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.demo.entity.Result;
|
||||
import com.oo.demo.entity.WebsocketResult;
|
||||
import com.oo.demo.service.FileService;
|
||||
import com.oo.demo.service.OnFileService;
|
||||
import com.oo.demo.service.Oprator;
|
||||
import com.oo.demo.service.WebSocketServer;
|
||||
import com.oo.onlyoffice.api.OnlyServiceAPI;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.tools.FileUtil;
|
||||
import com.oo.onlyoffice.tools.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.controller
|
||||
* @CreateTime: 2022-11-08 18:11
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
public class OnlyOfficeController {
|
||||
|
||||
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
@Autowired
|
||||
private OnFileService onFileService;
|
||||
@Autowired
|
||||
private FileService fileService;
|
||||
@Autowired
|
||||
private OnlyServiceAPI onlyServiceAPI;
|
||||
@Value("${filepath}")
|
||||
private String filepath;
|
||||
|
||||
@RequestMapping("/")
|
||||
public String filesView(Model model) {
|
||||
return "/index";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有的文件
|
||||
* @param parameter
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/file/all")
|
||||
@ResponseBody
|
||||
public Object file(@RequestParam Map<String, String> parameter) {
|
||||
int page = Integer.parseInt(parameter.get("page"));
|
||||
int limit = Integer.parseInt(parameter.get("limit"));
|
||||
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
// queryWrapper.notLike("id","MD");
|
||||
queryWrapper.orderByDesc("created_time");
|
||||
|
||||
Page<OnFile> p = new Page<>(page, limit);
|
||||
p = onFileService.page(p, queryWrapper);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("code", 0);
|
||||
map.put("msg", "SUCCESS");
|
||||
map.put("count", p.getTotal());
|
||||
map.put("data", p.getRecords());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @param file
|
||||
* @param caseId
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/files/upload/{caseId}")
|
||||
@ResponseBody
|
||||
public Object upload(@RequestParam("file") MultipartFile[] file, @PathVariable(required = true) String caseId) {
|
||||
List<OnFile> result = new ArrayList<>();
|
||||
int i = 0;
|
||||
for (MultipartFile multipartFile : file) {
|
||||
CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile) multipartFile;
|
||||
|
||||
String filename = multipartFile.getOriginalFilename();
|
||||
// 获取文件后缀
|
||||
String suffix = filename.substring(filename.lastIndexOf(".") + 1);
|
||||
String fileId = "";
|
||||
try {
|
||||
fileId = onFileService.saveFile(commonsMultipartFile.getBytes(), suffix);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
OnFile onFile = new OnFile();
|
||||
onFile.setFileId(fileId);
|
||||
onFile.setFileName(filename);
|
||||
onFile.setVersion("1.0.0");
|
||||
onFile.setCreatedTime(sdf.format(new Date()));
|
||||
onFile.setFileSize(commonsMultipartFile.getSize());
|
||||
onFile.setFileType(suffix);
|
||||
onFile.setFilePath(filepath + "/" + fileId + "." + suffix);
|
||||
onFile.setCaseId(caseId);
|
||||
FileUser userSession = SecurityUtils.getUserSession();
|
||||
if (userSession != null) {
|
||||
onFile.setUserName(userSession.getName());
|
||||
onFile.setUserId(userSession.getId());
|
||||
}
|
||||
onFileService.save(onFile);
|
||||
result.add(onFile);
|
||||
i++;
|
||||
}
|
||||
if (file.length == i) {
|
||||
log.info("文件上传成功");
|
||||
return result;
|
||||
}
|
||||
return Result.error("文件上传失败");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
final static String REDISUSERPREFIX = "user_key:";
|
||||
|
||||
/**
|
||||
* 获取config配置信息
|
||||
*/
|
||||
@RequestMapping("/onlyOfficeConfig/{mode}/{id}/{userId}/{clientType}/{collaborativeEditing}")
|
||||
@ResponseBody
|
||||
public Object openDocument(@PathVariable(required = false) String mode, @PathVariable(required = false) String id, @PathVariable(required = true) Integer userId, @PathVariable(required = false) String clientType, @PathVariable(required = false) Boolean collaborativeEditing, Model model) {//@RequestParam("url") String url,
|
||||
log.info("only office file:" + id);
|
||||
OnFile onFile = onFileService.getById(id);
|
||||
if (onFile == null) {
|
||||
return Result.error("文件不存在");
|
||||
}
|
||||
/**
|
||||
* 必要步骤
|
||||
*/
|
||||
FileUser user = new FileUser();
|
||||
//获取缓存Redis中的用户信息
|
||||
String userString = stringRedisTemplate.opsForValue().get(REDISUSERPREFIX + userId);
|
||||
if (userString != null && !"".equals(userString)) {
|
||||
JSONObject userObj = JSON.parseObject(userString);
|
||||
String userId1 = userObj.getString("userId");
|
||||
String userName1 = userObj.getString("userName");
|
||||
String nickName1 = userObj.getString("nickName");
|
||||
user.setId(userId1);
|
||||
user.setName(userName1);
|
||||
user.setNickname(nickName1);
|
||||
SecurityUtils.setUserSession(user);
|
||||
} else {
|
||||
return Result.error("当前用户不存在");
|
||||
}
|
||||
/**
|
||||
* 必要步骤
|
||||
*/
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("fileId", onFile.getFileId());
|
||||
map.put("fileName", onFile.getFileName());
|
||||
map.put("fileType", onFile.getFileType());
|
||||
map.put("fileSize", onFile.getFileSize());
|
||||
map.put("version", onFile.getVersion());
|
||||
map.put("caseId", onFile.getCaseId());
|
||||
if (clientType == null || clientType == "") {
|
||||
clientType = "desktop";
|
||||
}
|
||||
if (collaborativeEditing == null) {
|
||||
collaborativeEditing = false;
|
||||
}
|
||||
/**
|
||||
*打开文件获取config配置信息
|
||||
*/
|
||||
Map config = onlyServiceAPI.openDocument(map, mode, collaborativeEditing, clientType);
|
||||
|
||||
SecurityUtils.removeUserSession();
|
||||
|
||||
String s = JSON.toJSONString(config);
|
||||
log.info("only office config:" + s);
|
||||
return s;
|
||||
}
|
||||
// @RequestMapping("/onlyOffice/{mode}/{id}")
|
||||
// public ModelAndView openDocument(@PathVariable String mode,@PathVariable String id, Model model) {//@RequestParam("url") String url,
|
||||
// log.info("only office key:" + id);
|
||||
// OnFile onFile = onFileService.getById(id);
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 必要步骤
|
||||
// */
|
||||
// FileUser user = new FileUser();
|
||||
// user.setId(TempUser.getUserId());
|
||||
// user.setName(TempUser.getUserName());
|
||||
// SecurityUtils.setUserSession(user);
|
||||
// /**
|
||||
// * 必要步骤
|
||||
// */
|
||||
// Map<String,Object> map = new HashMap<>();
|
||||
// map.put("fileId",onFile.getFileId());
|
||||
// map.put("fileName",onFile.getFileName());
|
||||
// map.put("fileType",onFile.getFileType());
|
||||
// map.put("fileSize",onFile.getFileSize());
|
||||
// map.put("version",onFile.getVersion());
|
||||
//
|
||||
// Map config = onlyServiceAPI.openDocument(map, mode, false);
|
||||
//
|
||||
// SecurityUtils.removeUserSession();
|
||||
//
|
||||
// String s = JSON.toJSONString(config);
|
||||
// log.info("only office config:" + s);
|
||||
// model.addAllAttributes(config);
|
||||
// return new ModelAndView("onlyOffice");
|
||||
// }
|
||||
|
||||
/**
|
||||
* 文档编辑服务使用JavaScript API通知callbackUrl,向文档存储服务通知文档编辑的状态。
|
||||
* 文档编辑服务使用具有正文中的信息的POST请求。
|
||||
* https://api.onlyoffice.com/editors/callback
|
||||
* 当我们关闭编辑窗口后,十秒钟左右only office会将它存储的我们的编辑后的文件
|
||||
* 0 - 找不到具有密钥标识符的文档
|
||||
* 1 - 正在编辑文档
|
||||
* 2 - 文档已准备好保存
|
||||
* 3 - 发生文档保存错误
|
||||
* 4 - 不作任何更改就关闭文档
|
||||
* 6 - 正在编辑文档,但保存当前文档状态
|
||||
* 7 - 强制保存文档时发生错误
|
||||
*/
|
||||
@RequestMapping("/onlyOffice/save/{fileId}")
|
||||
@ResponseBody
|
||||
public void saveFile(HttpServletRequest request, HttpServletResponse response,@PathVariable(required = false) String fileId) {
|
||||
PrintWriter writer = null;
|
||||
try {
|
||||
writer = response.getWriter();
|
||||
// 获取传输的json数据
|
||||
Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
|
||||
String body = scanner.hasNext() ? scanner.next() : "";
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
if(fileId!=null){
|
||||
jsonObject.put("fileId",fileId);
|
||||
}else{
|
||||
jsonObject.put("fileId","");
|
||||
}
|
||||
log.info("{}", jsonObject);
|
||||
WebsocketResult result = fileService.documentSave(jsonObject);
|
||||
/*
|
||||
* status = 1,我们给onlyOffice的服务返回{"error":"0"}的信息。
|
||||
* 这样onlyOffice会认为回调接口是没问题的,这样就可以在线编辑文档了,否则的话会弹出窗口说明
|
||||
*/
|
||||
FileUser userSession = SecurityUtils.getUserSession();
|
||||
String userId = result.getUserId();
|
||||
if (userSession != null) {
|
||||
userId = userSession.getId();
|
||||
}
|
||||
WebSocketServer.sendInfo(JSON.toJSONString(result.getOnFile()), userId);
|
||||
// if (Objects.nonNull(writer)) {
|
||||
// writer.write("{\"error\":0}");
|
||||
// }
|
||||
writer.write("{\"error\":0}");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.info("报错信息" + e.getMessage());
|
||||
// writer.write("{\"error\":-1}");
|
||||
writer.write("{\"error\":0}");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/save/{id}")
|
||||
@ResponseBody
|
||||
public Object save(@PathVariable(required = false) String id) {
|
||||
OnFile onFile = onFileService.getById(id);
|
||||
if (onFile == null) {
|
||||
return Result.error("文件不存在,保存失败");
|
||||
}
|
||||
/**
|
||||
* 必要步骤
|
||||
*/
|
||||
try {
|
||||
FileUser user = new FileUser();
|
||||
user.setId(Oprator.getUserId());
|
||||
user.setName(Oprator.getUserName());
|
||||
SecurityUtils.setUserSession(user);
|
||||
String key = onlyServiceAPI.getKey(onFile.getFileId());
|
||||
String msg = onlyServiceAPI.save(key, Oprator.getUserId());
|
||||
SecurityUtils.removeUserSession();
|
||||
OnFile fileInfo = new OnFile();
|
||||
fileInfo.setFileId(id);
|
||||
fileInfo.setFileName(onFile.getFileName());
|
||||
fileInfo.setFileType(onFile.getFileType());
|
||||
fileInfo.setFilePath(filepath + "/" + id + "." + onFile.getFileType());
|
||||
return fileInfo;
|
||||
} catch (Exception e) {
|
||||
return Result.error("保存失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/converted")
|
||||
public void converted(String id, String suffix, HttpServletResponse response) {
|
||||
try {
|
||||
OnFile onFile = onFileService.getById(id);
|
||||
String title = onFile.getFileName().replace(onFile.getFileType(), suffix);
|
||||
String path = onlyServiceAPI.converted(onFile.getFileType(), onFile.getFileId(), suffix, title, null);
|
||||
|
||||
FileUtil.downloadAttachment(path, title, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/del")
|
||||
@ResponseBody
|
||||
public Object delFile(String id) {
|
||||
try {
|
||||
onFileService.removeFile(id);
|
||||
return Result.OK("删除成功", "fileTable");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.error("删除失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param isBrowser 用来判断是否是oo服务的回调下载 1.没有值 = oo服务回调下载。2.有值 = 页面手动下载
|
||||
* @param response
|
||||
*/
|
||||
@RequestMapping("/download/{id}")
|
||||
public void download(@PathVariable String id, String isBrowser, HttpServletResponse response) {
|
||||
try {
|
||||
onFileService.download(id, isBrowser, response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.oo.demo.controller;
|
||||
|
||||
import com.oo.demo.service.WebSocketServer;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller("web_Socket_system")
|
||||
@RequestMapping("/socket")
|
||||
public class WebSocketController {
|
||||
//页面请求
|
||||
@GetMapping("/index/{userId}")
|
||||
public ModelAndView socket(@PathVariable String userId) {
|
||||
ModelAndView mav = new ModelAndView("/socket1");
|
||||
mav.addObject("userId", userId);
|
||||
return mav;
|
||||
}
|
||||
//推送数据接口
|
||||
@ResponseBody
|
||||
@RequestMapping("/push/{cid}")
|
||||
public Map pushToWeb(@PathVariable String cid, String message) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
WebSocketServer.sendInfo(message, cid);
|
||||
result.put("code", cid);
|
||||
result.put("msg", message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.oo.demo.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author tonghui
|
||||
* @since 2022-03-10
|
||||
*/
|
||||
@Mapper
|
||||
public interface OnFileMapper extends BaseMapper<OnFile> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.oo.demo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.entity
|
||||
* @CreateTime: 2022-11-14 10:20
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* onlyoffice文件信息表
|
||||
*/
|
||||
@Data
|
||||
@TableName("on_file")
|
||||
public class OnFile {
|
||||
@TableId
|
||||
private String fileId;
|
||||
@TableField("`version`")
|
||||
private String version;
|
||||
private String createdTime;
|
||||
private String userName;
|
||||
private String userId;
|
||||
private String fileName;
|
||||
private String fileType;
|
||||
private String filePath;
|
||||
private String caseId;
|
||||
private Long fileSize;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.oo.demo.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 接口返回数据格式
|
||||
* @author scott
|
||||
* @email jeecgos@163.com
|
||||
* @date 2019年1月19日
|
||||
*/
|
||||
@Data
|
||||
public class Result<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 成功标志
|
||||
*/
|
||||
private boolean success = true;
|
||||
|
||||
/**
|
||||
* 返回处理消息
|
||||
*/
|
||||
private String message = "";
|
||||
|
||||
/**
|
||||
* 返回代码
|
||||
*/
|
||||
private Integer code = 200;
|
||||
|
||||
/**
|
||||
* 返回数据对象 data
|
||||
*/
|
||||
private T result;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private long timestamp = System.currentTimeMillis();
|
||||
|
||||
public Result() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容VUE3版token失效不跳转登录页面
|
||||
* @param code
|
||||
* @param message
|
||||
*/
|
||||
public Result(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Result<T> success(String message) {
|
||||
this.message = message;
|
||||
this.code = 200;
|
||||
this.success = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static<T> Result<T> OK() {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
public static<T> Result<T> OK(String msg) {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setMessage(msg);
|
||||
//Result OK(String msg)方法会造成兼容性问题 issues/I4IP3D
|
||||
r.setResult((T) msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static<T> Result<T> OK(T data) {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static<T> Result<T> OK(String msg, T data) {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(200);
|
||||
r.setMessage(msg);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static<T> Result<T> error(String msg, T data) {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setSuccess(false);
|
||||
r.setCode(500);
|
||||
r.setMessage(msg);
|
||||
r.setResult(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static<T> Result<T> error(String msg) {
|
||||
return error(500, msg);
|
||||
}
|
||||
|
||||
|
||||
public static<T> Result<T> error(int code, String msg) {
|
||||
Result<T> r = new Result<T>();
|
||||
r.setCode(code);
|
||||
r.setMessage(msg);
|
||||
r.setSuccess(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.oo.demo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.entity
|
||||
* @CreateTime: 2022-11-14 10:20
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WebsocketResult {
|
||||
private OnFile onFile;
|
||||
private String userId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.onlyoffice.config.OnlyProperties;
|
||||
import com.oo.onlyoffice.core.SaveFileProcessor;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.tools.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.demo.service
|
||||
* @CreateTime: 2023-08-01 16:00
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class DemoService implements SaveFileProcessor {
|
||||
|
||||
@Autowired
|
||||
private OnlyProperties onlyProperties;
|
||||
@Autowired
|
||||
private OnFileService onFileService;
|
||||
@Value("${filepath}")
|
||||
private String filepath;
|
||||
final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public void saveBeforeInitialization(Map<String, Object> map, byte[] bytes, String fileExtension) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储onlyoffice文件信息
|
||||
* @param map 文件元信息
|
||||
* @param file 文件
|
||||
* @param changes 文件变动信息
|
||||
* @param fileId 文件id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> save(Map<String, Object> map, byte[] file, byte[] changes, String fileId) {
|
||||
try {
|
||||
if(fileId!=null&&fileId!=""){
|
||||
onFileService.updateFileByFileId(file, map.get("fileType").toString(),fileId);
|
||||
}else{
|
||||
fileId = "";
|
||||
fileId = onFileService.saveFile(file, map.get("fileType").toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String version = map.get("version").toString();
|
||||
|
||||
String[] split = version.split("\\.");
|
||||
version = split[0] + "." + split[1] + "." + (Integer.valueOf(split[2]) + 1);
|
||||
|
||||
OnFile onFile = new OnFile();
|
||||
onFile.setFileId(fileId);
|
||||
onFile.setFileName(map.get("fileName").toString());
|
||||
onFile.setVersion(version);
|
||||
onFile.setFileSize((long) file.length);
|
||||
onFile.setFileType(map.get("fileType").toString());
|
||||
if (map.containsKey("caseId")) {
|
||||
onFile.setCaseId(map.get("caseId").toString());
|
||||
}
|
||||
onFile.setFilePath(filepath + "/" + fileId + "." + map.get("fileType").toString());
|
||||
FileUser userSession = SecurityUtils.getUserSession();
|
||||
if (userSession != null) {
|
||||
onFile.setUserId(userSession.getId());
|
||||
onFile.setUserName(userSession.getName());
|
||||
}
|
||||
onFile.setCreatedTime(sdf.format(new Date()));
|
||||
onFileService.save(onFile);
|
||||
|
||||
map.put("version", version);
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAfterInitialization(Map<String, Object> map, byte[] bytes, String fileExtension) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.oo.demo.dao.OnFileMapper;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.demo.entity.WebsocketResult;
|
||||
import com.oo.onlyoffice.api.OnlyServiceAPI;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.tools.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.demo.service
|
||||
* @CreateTime: 2023-08-02 09:57
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileService {
|
||||
|
||||
@Autowired
|
||||
private OnlyServiceAPI onlyServiceAPI;
|
||||
@Autowired
|
||||
private DemoService demoService;
|
||||
@Autowired
|
||||
private OnFileService onFileService;
|
||||
|
||||
/**
|
||||
* 文档服务器 保存文件回调
|
||||
* Defines the status of the document. Can have the following values:
|
||||
* 1 - document is being edited,
|
||||
* 2 - document is ready for saving,
|
||||
* 3 - document saving error has occurred,
|
||||
* 4 - document is closed with no changes,
|
||||
* 6 - document is being edited, but the current document state is saved,
|
||||
* 7 - error has occurred while force saving the document.
|
||||
*
|
||||
* @param jsonObject
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WebsocketResult documentSave(JSONObject jsonObject) {
|
||||
WebsocketResult result = new WebsocketResult();
|
||||
String key = "";
|
||||
String fileId = jsonObject.getString("fileId");
|
||||
try {
|
||||
int status = jsonObject.getIntValue("status");
|
||||
log.info("status[{}]", status);
|
||||
if (6 == status) {
|
||||
log.info("开始保存文件");
|
||||
log.info("dayin:" + JSON.toJSONString(jsonObject));
|
||||
JSONArray jsonArray = jsonObject.getJSONObject("history").getJSONArray("changes");
|
||||
log.info("历史版本:" + JSON.toJSONString(jsonArray));
|
||||
JSONObject object = jsonArray.getJSONObject(0);
|
||||
String userId = object.getJSONObject("user").getString("id");
|
||||
FileUser fileUser = new FileUser();
|
||||
fileUser.setId(userId);
|
||||
SecurityUtils.setUserSession(fileUser);
|
||||
log.info("fileuser:" + JSON.toJSONString(fileUser));
|
||||
key = jsonObject.getString("key");
|
||||
log.info("key:" + JSON.toJSONString(key));
|
||||
//文件id
|
||||
Boolean isexistid = false;
|
||||
if (fileId != null && !"".equals(fileId)) {
|
||||
isexistid = true;
|
||||
}
|
||||
if (!isexistid) {
|
||||
fileId = onlyServiceAPI.getFileId(key);
|
||||
}
|
||||
log.info("fileId:" + JSON.toJSONString(fileId));
|
||||
if (fileId != null && !"".equals(fileId)) {
|
||||
//查询之前FileId对应的文件信息
|
||||
OnFile onfile = onFileService.getFileById(fileId);
|
||||
jsonObject.put("caseId", onfile.getCaseId());
|
||||
}
|
||||
//判断是否是最后一人进行保存
|
||||
int users = onlyServiceAPI.getUserNum(key);
|
||||
// if (users > 1) {
|
||||
// return null;
|
||||
// }
|
||||
//历史版本最大个数 获取当前文件的历史版本数量
|
||||
Integer histNum = onlyServiceAPI.getHistNum();
|
||||
log.info("历史版本最大个数" + histNum);
|
||||
/**
|
||||
* 如果有需要保存历史记录 可以进行相关操作
|
||||
*/
|
||||
if (null != histNum) {
|
||||
|
||||
}
|
||||
//处理文件的保存
|
||||
OnFile file = onlyServiceAPI.handlerStatus(jsonObject);
|
||||
//查询相同案件最新版本的文件信息
|
||||
if (fileId != null && !"".equals(fileId)) {
|
||||
file = getNewFileInofoByFileId(fileId);
|
||||
} else {
|
||||
file = getNewFileInofoByCaseId(file.getCaseId());
|
||||
}
|
||||
result = WebsocketResult.builder().onFile(file).userId(SecurityUtils.getUserSession().getId()).build();
|
||||
log.info("处理文件的保存:" + JSON.toJSONString(jsonObject));
|
||||
log.info("保存文件结束");
|
||||
SecurityUtils.removeUserSession();
|
||||
return result;
|
||||
} else if (0 == status || 2 == status || 4 == status) {
|
||||
onlyServiceAPI.close(jsonObject);
|
||||
log.info("文件关闭====",status);
|
||||
} else if (3 == status || 7 == status) {
|
||||
//保存文档错误
|
||||
onlyServiceAPI.close(jsonObject);
|
||||
log.info("保存文档错误====",status);
|
||||
} else if (1 == status) {
|
||||
log.info("文件正在编辑====",status);
|
||||
//文件服务的回调 获取key判断当前文档有多少人在这使用
|
||||
List<Map> actions = JSONObject.parseArray(jsonObject.getString("actions"), Map.class);
|
||||
if ((Integer) actions.get(0).get("type") == 1) {
|
||||
log.info("当前用户有[{}]", jsonObject.getString("users"));
|
||||
List<String> users = JSONObject.parseArray(jsonObject.getString("users"), String.class);
|
||||
onlyServiceAPI.iskey(jsonObject.getString("key"), users.size());
|
||||
}
|
||||
if ((Integer) actions.get(0).get("type") == 0) {
|
||||
onlyServiceAPI.iskey(jsonObject.getString("key"), null);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
OnFileMapper onFileMapper;
|
||||
|
||||
/**
|
||||
* 查询相同案件最新版本的文件信息
|
||||
*
|
||||
* @param caseId
|
||||
* @return
|
||||
*/
|
||||
private OnFile getNewFileInofoByCaseId(String caseId) {
|
||||
OnFile file = new OnFile();
|
||||
QueryWrapper<OnFile> fileQueryWrapper = new QueryWrapper<>();
|
||||
fileQueryWrapper.eq("case_id", caseId);
|
||||
fileQueryWrapper.orderByDesc("created_time");
|
||||
List<OnFile> onFiles = onFileMapper.selectList(fileQueryWrapper);
|
||||
if (onFiles != null && onFiles.size() > 0) {
|
||||
file = onFiles.get(0);
|
||||
}
|
||||
log.info("caseId:" + caseId + ":fileinfo:" + JSON.toJSONString(file));
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件的fileid查询文件信息
|
||||
*/
|
||||
private OnFile getNewFileInofoByFileId(String fileId) {
|
||||
OnFile file = onFileMapper.selectById(fileId);
|
||||
if (file != null) {
|
||||
log.info("caseId:" + file.getCaseId() + ":fileinfo:" + JSON.toJSONString(file));
|
||||
} else {
|
||||
log.info("根据文件id未查询到文件信息");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
public interface OnFileService extends IService<OnFile> {
|
||||
/**
|
||||
* 保存onlyoffice文件
|
||||
*
|
||||
* @param bytes
|
||||
* @param fileType
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
String saveFile(byte[] bytes, String fileType) throws Exception;
|
||||
|
||||
/**
|
||||
* 通过文件id更新onlyoffice文件
|
||||
*
|
||||
* @param bytes
|
||||
* @param fileType
|
||||
* @param fileId
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
String updateFileByFileId(byte[] bytes, String fileType, String fileId) throws Exception;
|
||||
|
||||
/**
|
||||
* 删除onlyoffice文件
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void removeFile(String id);
|
||||
|
||||
/**
|
||||
* 下载onlyoffice文件
|
||||
*
|
||||
* @param id
|
||||
* @param isBrowser
|
||||
* @param response
|
||||
*/
|
||||
void download(String id, String isBrowser, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 根据文件id查找文件信息
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
OnFile getFileById(String id);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.oo.demo.dao.OnFileMapper;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.onlyoffice.tools.FileUtil;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @since 2022-03-10
|
||||
*/
|
||||
@Service
|
||||
public class OnFileServiceImpl extends ServiceImpl<OnFileMapper, OnFile> implements OnFileService {
|
||||
@Value("${filepath}")
|
||||
private String path;
|
||||
|
||||
@Override
|
||||
public void download(String id, String isBrowser, HttpServletResponse response) {
|
||||
OnFile byId = baseMapper.selectById(id);
|
||||
|
||||
//判断是否有值
|
||||
if (StrUtil.isNotEmpty(isBrowser)) {
|
||||
FileUtil.downloadAttachment(path + "/" + id + "." + byId.getFileType(), byId.getFileName(), response);
|
||||
} else {
|
||||
FileUtil.downloadInline(path + "/" + id + "." + byId.getFileType(), byId.getFileName(), response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnFile getFileById(String id) {
|
||||
OnFile file = baseMapper.selectById(id);
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(String id) {
|
||||
OnFile byId = baseMapper.selectById(id);
|
||||
System.out.println(path);
|
||||
File file = new File(path + "/" + id + "." + byId.getFileType());
|
||||
System.out.println("删除文件");
|
||||
FileUtils.deleteQuietly(file);
|
||||
|
||||
removeById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增文件信息到数据库
|
||||
*
|
||||
* @param bytes
|
||||
* @param fileType
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String saveFile(byte[] bytes, String fileType) throws Exception {
|
||||
|
||||
String fileId = IdUtil.simpleUUID();
|
||||
File file = new File(path + "/" + fileId + "." + fileType);
|
||||
File parentFile = file.getParentFile();
|
||||
if (!parentFile.exists()) {
|
||||
parentFile.mkdirs();
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(path + "/" + fileId + "." + fileType)) {
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
}
|
||||
return fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件信息到数据库
|
||||
*
|
||||
* @param bytes
|
||||
* @param fileType
|
||||
* @param fileId
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String updateFileByFileId(byte[] bytes, String fileType, String fileId) throws Exception {
|
||||
Boolean ishaveid = false;
|
||||
if (fileId != null && fileId != "") {
|
||||
ishaveid = true;
|
||||
}
|
||||
if (!ishaveid) {
|
||||
fileId = IdUtil.simpleUUID();
|
||||
}
|
||||
File file = new File(path + "/" + fileId + "." + fileType);
|
||||
File parentFile = file.getParentFile();
|
||||
if (!parentFile.exists()) {
|
||||
parentFile.mkdirs();
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(path + "/" + fileId + "." + fileType)) {
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
}
|
||||
return fileId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.demo.service
|
||||
* @CreateTime: 2023-08-05 17:14
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class Oprator {
|
||||
private static Logger logger = LoggerFactory.getLogger(Oprator.class);
|
||||
private static List<Map<String, String>> cache1 = new ArrayList<>();
|
||||
private static Integer index;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 1; i++) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
// map.put("userId", IdUtil.simpleUUID().substring(0,6));
|
||||
// map.put("userName","TongHui"+map.get("userId"));
|
||||
map.put("userId", "0");
|
||||
map.put("userName", "OnlyOfficeUser1");
|
||||
cache1.add(map);
|
||||
}
|
||||
logger.info("用户初始完毕");
|
||||
// Random random = new Random();
|
||||
// index = random.nextInt(10);
|
||||
index = 0;
|
||||
logger.info("获取用户完毕" + index);
|
||||
}
|
||||
|
||||
public static String getUserName() {
|
||||
return cache1.get(index).get("userName");
|
||||
}
|
||||
|
||||
public static String getUserId() {
|
||||
return cache1.get(index).get("userId");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.oo.demo.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* @ Description:
|
||||
* @ ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
|
||||
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
|
||||
* @author ym
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@Service
|
||||
@ServerEndpoint("/api/websocket/{userid}")
|
||||
public class WebSocketServer {
|
||||
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
|
||||
private static int onlineCount = 0;
|
||||
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
|
||||
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
|
||||
|
||||
//与某个客户端的连接会话,需要通过它来给客户端发送数据
|
||||
private Session session;
|
||||
|
||||
//接收userid
|
||||
private String userid = "";
|
||||
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("userid") String userid) {
|
||||
this.session = session;
|
||||
webSocketSet.add(this); //加入set中
|
||||
this.userid = userid;
|
||||
addOnlineCount(); //在线数加1
|
||||
try {
|
||||
sendMessage("conn_success");
|
||||
log.info("有新窗口开始监听:" + userid + ",当前在线人数为:" + getOnlineCount());
|
||||
} catch (IOException e) {
|
||||
log.error("websocket IO Exception");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose() {
|
||||
//从set中删除
|
||||
webSocketSet.remove(this);
|
||||
//在线数减1
|
||||
subOnlineCount();
|
||||
//断开连接情况下,更新主板占用情况为释放
|
||||
log.info("释放的userid为:" + userid);
|
||||
//这里写你 释放的时候,要处理的业务
|
||||
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
*
|
||||
* @ Param message 客户端发送过来的消息
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
log.info("收到来自窗口" + userid + "的信息:" + message);
|
||||
//群发消息
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
item.sendMessage(message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ Param session
|
||||
* @ Param error
|
||||
*/
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
log.error("发生错误");
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现服务器主动推送
|
||||
*/
|
||||
public void sendMessage(String message) throws IOException {
|
||||
this.session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发自定义消息
|
||||
*/
|
||||
public static void sendInfo(String message, @PathParam("userid") String userid) throws IOException {
|
||||
log.info("推送消息到窗口" + userid + ",推送内容:" + message);
|
||||
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
//这里可以设定只推送给这个userid的,为null则全部推送
|
||||
if (userid == null) {
|
||||
// item.sendMessage(message);
|
||||
} else if (item.userid.equals(userid)) {
|
||||
item.sendMessage(message);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized int getOnlineCount() {
|
||||
return onlineCount;
|
||||
}
|
||||
|
||||
public static synchronized void addOnlineCount() {
|
||||
WebSocketServer.onlineCount++;
|
||||
}
|
||||
|
||||
public static synchronized void subOnlineCount() {
|
||||
WebSocketServer.onlineCount--;
|
||||
}
|
||||
|
||||
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
|
||||
return webSocketSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.oo.onlyoffice.api;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.onlyoffice.core.context.FileMetadata;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public interface OnlyServiceAPI {
|
||||
/**
|
||||
* 打开only office
|
||||
*
|
||||
* @param map 文件数据信息
|
||||
* @param map{
|
||||
* 必填 fileId
|
||||
* 必填 fileName
|
||||
* 必填 fileType
|
||||
* 必填 fileSize
|
||||
* 可用携带其它值
|
||||
* }
|
||||
* @param mode 打开方式 edit/view
|
||||
* @param collaborativeEditing 是否协同编辑
|
||||
* @return 配置信息
|
||||
*/
|
||||
/**
|
||||
* 打开文件并获取指定的config配置信息
|
||||
* @param map
|
||||
* @param mode
|
||||
* @param collaborativeEditing
|
||||
* @param clientType
|
||||
* @return
|
||||
*/
|
||||
Map openDocument(Map<String, Object> map, String mode, boolean collaborativeEditing,String clientType);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 处理保存结果
|
||||
*
|
||||
* @param jsonObject 信息
|
||||
*/
|
||||
OnFile handlerStatus(JSONObject jsonObject) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 删除临时文件
|
||||
*
|
||||
* @param jsonObject
|
||||
*/
|
||||
void removeTempFile(JSONObject jsonObject);
|
||||
|
||||
/**
|
||||
* 获取文件元数据
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
FileMetadata getTempFile(String key);
|
||||
|
||||
/**
|
||||
* 获取历史数量上限
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Integer getHistNum();
|
||||
|
||||
/**
|
||||
* 获取打开文档时的唯一key
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
String getKey(String id);
|
||||
|
||||
/**
|
||||
* 当文件没有人使用时,清空文件信息
|
||||
*/
|
||||
void close(JSONObject jsonObject);
|
||||
|
||||
/**
|
||||
* redis中存放文件使用人数
|
||||
*
|
||||
* @param key
|
||||
* @param users
|
||||
*/
|
||||
int iskey(String key, Integer users);
|
||||
|
||||
/**
|
||||
* 获取文档是使用人数
|
||||
* @return
|
||||
*/
|
||||
int getUserNum(String key);
|
||||
|
||||
/**
|
||||
* 通过key获取文件id
|
||||
* @return
|
||||
*/
|
||||
String getFileId(String key);
|
||||
|
||||
String getCommandServiceUrl();
|
||||
|
||||
Integer getTimeout();
|
||||
|
||||
String downloadFileRequestPath();
|
||||
|
||||
/**
|
||||
* 文件保存
|
||||
*/
|
||||
String save(String key, String userId);
|
||||
|
||||
/**
|
||||
* 文件转换
|
||||
* @param filetype 文件类型
|
||||
* @param fileId 文件id
|
||||
* @param outputtype 转换类型
|
||||
* @param title 转换后的名称
|
||||
* @param password 文档密码
|
||||
* @return 转换后的文件下载地址
|
||||
*/
|
||||
String converted(String filetype, String fileId, String outputtype, String title,String password);
|
||||
}
|
||||
@@ -0,0 +1,600 @@
|
||||
package com.oo.onlyoffice.api.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.oo.demo.entity.OnFile;
|
||||
import com.oo.demo.service.OnFileService;
|
||||
import com.oo.onlyoffice.api.OnlyServiceAPI;
|
||||
import com.oo.onlyoffice.config.OnlyProperties;
|
||||
import com.oo.onlyoffice.core.Cache;
|
||||
import com.oo.onlyoffice.core.FileHandler;
|
||||
import com.oo.onlyoffice.core.OnlyOfficeConfigFactory;
|
||||
import com.oo.onlyoffice.core.SaveFileProcessor;
|
||||
import com.oo.onlyoffice.core.context.FileContext;
|
||||
import com.oo.onlyoffice.core.context.FileMetadata;
|
||||
import com.oo.onlyoffice.dto.convert.ConvertBody;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.tools.DocumentKey;
|
||||
import com.oo.onlyoffice.tools.FileUtil;
|
||||
import com.oo.onlyoffice.tools.JWTUtil;
|
||||
import com.oo.onlyoffice.tools.SecurityUtils;
|
||||
import com.oo.onlyoffice.vo.FileConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* only office 实现类
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OnlyServiceAPIImpl implements OnlyServiceAPI {
|
||||
@Autowired
|
||||
OnFileService onFileService;
|
||||
@Autowired
|
||||
private OnlyOfficeConfigFactory onlyOfficeConfigFactory;
|
||||
@Autowired
|
||||
private SaveFileProcessor saveFileProcessor;
|
||||
@Autowired
|
||||
private OnlyProperties onlyProperties;
|
||||
@Autowired
|
||||
private FileContext tempFileContext;
|
||||
@Autowired
|
||||
private FileHandler fileHandler;
|
||||
@Autowired
|
||||
private Cache cache;
|
||||
|
||||
private String EDIT = "edit";
|
||||
private String VIEW = "view";
|
||||
|
||||
|
||||
/**
|
||||
* @param map 文件信息
|
||||
* @param map{ 必填 fileId
|
||||
* 必填 fileName
|
||||
* 必填 fileType
|
||||
* 必填 fileSize
|
||||
* 可用携带其它信息
|
||||
* }
|
||||
* @param mode 打开方式 edit/view
|
||||
* @param collaborativeEditing 是否协同编辑
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map openDocument(Map<String, Object> map, String mode, boolean collaborativeEditing, String clientType) {
|
||||
long fileSize = (long) map.get("fileSize");
|
||||
|
||||
if (fileSize > onlyProperties.getMaxSize()) {
|
||||
// 添加操作日志
|
||||
throw new RuntimeException("文件超过【" + onlyProperties.getMaxSize() / 1024 / 1024 + "MB】无法打开");
|
||||
}
|
||||
|
||||
if (EDIT.equals(mode)) {
|
||||
return documentEdit(map, collaborativeEditing, clientType);
|
||||
}
|
||||
if (VIEW.equals(mode)) {
|
||||
return documentView(map, collaborativeEditing, clientType);
|
||||
}
|
||||
// if (VIEW.equals(mode)) {
|
||||
// return documentView(map, clientType);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map documentEdit(Map<String, Object> map, boolean collaborativeEditing, String clientType) {
|
||||
FileConfig fileConfigDTO = openEditConfig(map, "edit", collaborativeEditing, clientType);
|
||||
String json = JSON.toJSONString(fileConfigDTO);
|
||||
Map<String, Object> config = JSON.parseObject(json, Map.class);
|
||||
config.put("type", clientType);
|
||||
return config;
|
||||
}
|
||||
|
||||
private Map documentView(Map<String, Object> map, boolean collaborativeEditing, String clientType) {
|
||||
FileConfig fileConfigDTO = openEditConfig(map, "view", collaborativeEditing, clientType);
|
||||
String json = JSON.toJSONString(fileConfigDTO);
|
||||
Map<String, Object> config = JSON.parseObject(json, Map.class);
|
||||
config.put("type", clientType);
|
||||
return config;
|
||||
}
|
||||
|
||||
private Map documentView(Map<String, Object> map, String clientType) {
|
||||
FileConfig fileConfigDTO = openEditConfig(map, "view", false, clientType);
|
||||
String json = JSON.toJSONString(fileConfigDTO);
|
||||
Map<String, Object> config = JSON.parseObject(json, Map.class);
|
||||
config.put("type", clientType);
|
||||
return config;
|
||||
}
|
||||
|
||||
private FileConfig openEditConfig(Map<String, Object> map, String mode, boolean collaborativeEditing, String clientType) {
|
||||
try {
|
||||
map.put("mode", mode);
|
||||
log.info("开始生成文件信息");
|
||||
//在编辑模式 生成临时文件,保存原文件信息
|
||||
FileMetadata tempFileInfo = fileHandler.handlerFile(map, collaborativeEditing);
|
||||
//生成配置文件 TODO: 控制文件权限
|
||||
log.info("开始生成编辑器配置信息");
|
||||
FileConfig fileConfigDTO = onlyOfficeConfigFactory.buildInitConfig(tempFileInfo.getUrl(), mode, tempFileInfo.getKey(), tempFileInfo.getOldName(), clientType);
|
||||
log.info("生成编辑器配置信息结束");
|
||||
// TODO: 添加更多详细的自定义信息
|
||||
return fileConfigDTO;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取规定历史文件数量
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Integer getHistNum() {
|
||||
return onlyProperties.getHistNum();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存文件地址
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getCommandServiceUrl() {
|
||||
return onlyProperties.getDocService() + onlyProperties.SAVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return onlyProperties.getTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String downloadFileRequestPath() {
|
||||
if (onlyProperties.getDownloadFile().endsWith("/")) {
|
||||
return onlyProperties.getDownloadFile();
|
||||
}
|
||||
return onlyProperties.getDownloadFile() + "/";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OnFile handlerStatus(JSONObject jsonObject) throws Exception {
|
||||
OnFile file = new OnFile();
|
||||
String fileId = jsonObject.getString("fileId");
|
||||
log.info("开始下载编辑器文件");
|
||||
int status = jsonObject.getIntValue("status");
|
||||
log.info("status[{}]:{}", status, jsonObject);
|
||||
String key = (String) jsonObject.get("key");
|
||||
String caseId = jsonObject.getString("caseId");
|
||||
|
||||
FileHandler tempFileHandler = tempFileContext.getHandlerByKey(key);
|
||||
if (Objects.nonNull(tempFileHandler)) {
|
||||
String url = jsonObject.getString("url");
|
||||
String changesurl = jsonObject.getString("changesurl");
|
||||
log.info("编辑后的文档下载路径url:" + url);
|
||||
log.info("文件变动信息文件url:" + changesurl);
|
||||
// 下载修改后文件
|
||||
byte[] fileByte = FileUtil.getFileByte(url);
|
||||
// 下载前一个文化和修改后文件的区别
|
||||
byte[] changes = FileUtil.getFileByte(changesurl);
|
||||
log.info("下载编辑器文件成功");
|
||||
|
||||
log.info("保存文件前置处理");
|
||||
try {
|
||||
String fileExtension = FileUtil.getFileExtension(url);
|
||||
|
||||
Optional<FileMetadata> tempFile = tempFileHandler.getTempFile(key);
|
||||
|
||||
if (!tempFile.isPresent()) {
|
||||
throw new RuntimeException("文件元信息不存在");
|
||||
}
|
||||
Map<String, Object> fileInfoMap = tempFile.get().getFileInfo();
|
||||
if (caseId != null) {
|
||||
fileInfoMap.put("caseId", caseId);
|
||||
}
|
||||
//保存文件前进行自定义处理(该方法暂时没有实现业务逻辑)
|
||||
//saveFileProcessor.saveBeforeInitialization(tempFile.get().getFileInfo(), fileByte, fileExtension);
|
||||
|
||||
// 保存文件
|
||||
Map<String, Object> map = saveFileProcessor.save(tempFile.get().getFileInfo(), fileByte, changes, fileId);
|
||||
log.info("文件信息1:" + JSON.toJSONString(tempFile.get().getFileInfo()));
|
||||
log.info("文件信息2:" + JSON.toJSONString(map));
|
||||
saveFileProcessor.saveAfterInitialization(tempFile.get().getFileInfo(), fileByte, fileExtension);
|
||||
//更新内存文件信息
|
||||
tempFileContext.updateCacheFileInfo(key, map);
|
||||
//构建文件信息
|
||||
fileId = map.get("fileId").toString();
|
||||
//将map转化为OnFile对象
|
||||
// file = mapToEntity(map);
|
||||
if (fileId != null) {
|
||||
//查询文件信息
|
||||
file = onFileService.getFileById(fileId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将map转化成对象
|
||||
*
|
||||
* @param map
|
||||
* @return
|
||||
* @throws NoSuchFieldException
|
||||
* @throws IllegalAccessException
|
||||
*/
|
||||
public OnFile mapToEntity(Map<String, Object> map) throws NoSuchFieldException, IllegalAccessException {
|
||||
OnFile entity = new OnFile();
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
Field field = OnFile.class.getDeclaredField(entry.getKey());
|
||||
field.setAccessible(true);
|
||||
field.set(entity, entry.getValue());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void removeTempFile(JSONObject jsonObject) {
|
||||
String key = (String) jsonObject.get("key");
|
||||
FileHandler tempFileHandler = tempFileContext.getHandlerByKey(key);
|
||||
if (tempFileHandler != null) {
|
||||
log.info("删除临时文件信息缓存" + key);
|
||||
tempFileHandler.removeTempFile(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时文件信息
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public FileMetadata getTempFile(String key) {
|
||||
FileMetadata tempFileInfo = tempFileContext.getFileInfo(key);
|
||||
if (tempFileInfo != null) {
|
||||
return tempFileInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打开文档时的唯一key
|
||||
*
|
||||
* @param id 文件id
|
||||
* @return
|
||||
*/
|
||||
public String getKey(String id) {
|
||||
FileUser user = SecurityUtils.getUserSession();
|
||||
|
||||
if (cache.hasKey(user.getId() + "_" + id)) {
|
||||
return (String) cache.get(user.getId() + "_" + id);
|
||||
}
|
||||
|
||||
return (String) cache.get("collaborativeEditing_" + id);
|
||||
}
|
||||
|
||||
public void close(JSONObject jsonObject) {
|
||||
// 判断临时信息是否存在
|
||||
FileMetadata tempFile = getTempFile(jsonObject.getString("key"));
|
||||
if (tempFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//判断 删除时间 是否大于 文件打开时间
|
||||
//如果 删除时间 小于 文件打开时间 不执行删除
|
||||
log.info("打开时间:" + tempFile.getOpenTime() + ",回调时间:" + new Date().getTime());
|
||||
if (new Date().getTime() < tempFile.getOpenTime()) {
|
||||
return;
|
||||
}
|
||||
// 减少文档的使用人数
|
||||
int i = iskey(jsonObject.getString("key"), null);
|
||||
//如果没有人使用当前文档,清空临时信息
|
||||
if (i <= 0) {
|
||||
//清空之前保存临时文件
|
||||
String key = jsonObject.getString("key");
|
||||
FileHandler tempFileHandler = tempFileContext.getHandlerByKey(key);
|
||||
if (Objects.nonNull(tempFileHandler)) {
|
||||
String url = jsonObject.getString("url");
|
||||
String changesurl = jsonObject.getString("changesurl");
|
||||
log.info("编辑后的文档下载路径url:" + url);
|
||||
log.info("文件变动信息文件url:" + changesurl);
|
||||
// 下载修改后文件
|
||||
byte[] fileByte = FileUtil.getFileByte(url);
|
||||
saveFileProcessor.save(tempFile.getFileInfo(), fileByte, null, jsonObject.getString("fileId"));
|
||||
log.info("zouzhele==================");
|
||||
}
|
||||
removeTempFile(jsonObject);
|
||||
String id = (String) cache.get("getID_" + jsonObject.getString("key"));
|
||||
cache.remove("getID_" + id);
|
||||
cache.remove("collaborativeEditing_" + id);
|
||||
cache.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* redis中存放文件使用人数
|
||||
*
|
||||
* @param key
|
||||
* @param users
|
||||
*/
|
||||
public int iskey(String key, Integer users) {
|
||||
int i = 0;
|
||||
if (users != null) {
|
||||
cache.set(key, users);
|
||||
i = users;
|
||||
} else {
|
||||
i = ((int) cache.get(key)) - 1;
|
||||
cache.set(key, (i >= 0 ? i : 0));
|
||||
}
|
||||
log.info("[" + key + "]文档使用人数:" + i);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUserNum(String key) {
|
||||
return (int) (cache.get(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileId(String key) {
|
||||
return (String) cache.get("getID_" + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://documentserver/coauthoring/CommandService.ashx
|
||||
* {
|
||||
* "c": "forcesave",
|
||||
* "key": "Khirz6zTPdfd7",
|
||||
* "userdata": "sample userdata"
|
||||
* }
|
||||
*/
|
||||
public String save(String key, String userId) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("c", "forcesave");
|
||||
map.put("key", key);
|
||||
map.put("userdata", userId);
|
||||
if (null != onlyProperties.getSecret()) {
|
||||
String token = JWTUtil.createToken(map, onlyProperties.getSecret());
|
||||
map.put("token", token);
|
||||
}
|
||||
String bodyString = JSON.toJSONString(map);
|
||||
log.info("forcesave:" + bodyString);
|
||||
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
|
||||
try {
|
||||
URL url = new URL(onlyProperties.getDocService() + onlyProperties.SAVE);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setFixedLengthStreamingMode(bodyByte.length);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setConnectTimeout(onlyProperties.getTimeout());
|
||||
|
||||
connection.connect();
|
||||
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(bodyByte);
|
||||
|
||||
InputStream stream = connection.getInputStream();
|
||||
|
||||
if (stream == null) {
|
||||
throw new Exception("Could not get an answer");
|
||||
}
|
||||
|
||||
/**将流转为字符串*/
|
||||
String jsonString = FileUtil.ConvertStreamToString(stream);
|
||||
connection.disconnect();
|
||||
JSONObject jsonObj = JSONObject.parseObject(jsonString);
|
||||
log.debug(jsonObj.toJSONString());
|
||||
Object error = jsonObj.get("error");
|
||||
String msg = "";
|
||||
if (error != null) {
|
||||
switch ((Integer) error) {
|
||||
case 1:
|
||||
msg = "缺少文档密钥或找不到具有此类密钥的文档";
|
||||
break;
|
||||
case 2:
|
||||
msg = "回调网址不正确";
|
||||
break;
|
||||
case 3:
|
||||
msg = "内部服务器错误";
|
||||
break;
|
||||
case 4:
|
||||
msg = "在收到强制保存命令之前,未对文档应用任何更改";
|
||||
break;
|
||||
case 5:
|
||||
msg = "命令不正确";
|
||||
break;
|
||||
case 6:
|
||||
msg = "令牌无效";
|
||||
break;
|
||||
default:
|
||||
msg = "保存成功";
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
/**
|
||||
* 文件转化 #简单请求参数示例:
|
||||
* @param filetype 文件类型
|
||||
* @param key 文件key
|
||||
* @param outputtype 输出类型
|
||||
* @param fileUrl 文件路径
|
||||
* @param title 输出文件名称
|
||||
* @param password 加密文档的密码
|
||||
* @return 文件路径
|
||||
*/
|
||||
/**
|
||||
* //#请求参数示例 https://www.songbin.top/post_27457.html
|
||||
* {
|
||||
* "filetype": "xlsx",
|
||||
* "key": "Khirz6zTPdfd7",
|
||||
* "outputtype": "pdf",
|
||||
* "region": "en-US",
|
||||
* "spreadsheetLayout": {
|
||||
* "ignorePrintArea": true,
|
||||
* "orientation": "portrait",
|
||||
* "fitToWidth": 0,
|
||||
* "fitToHeight": 0,
|
||||
* "scale": 100,
|
||||
* "headings": false,
|
||||
* "gridLines": false,
|
||||
* "pageSize": {
|
||||
* "width": "210mm",
|
||||
* "height": "297mm"
|
||||
* },
|
||||
* "margins": {
|
||||
* "left": "17.8mm",
|
||||
* "right": "17.8mm",
|
||||
* "top": "19.1mm",
|
||||
* "bottom": "19.1mm"
|
||||
* }
|
||||
* },
|
||||
* "title": "Example Document Title.pdf",
|
||||
* "url": "https://example.com/url-to-example-spreadsheet.xlsx"
|
||||
* }
|
||||
*/
|
||||
@Override
|
||||
public String converted(String filetype, String key, String outputtype, String title, String password) {
|
||||
log.debug("文件开始转化{}->{}", filetype, outputtype);
|
||||
|
||||
String fileUrl = onlyProperties.getDownloadFile() + key;
|
||||
|
||||
ConvertBody body = new ConvertBody(filetype, DocumentKey.SnowflakeId(), outputtype, fileUrl, title, password);
|
||||
String bodyString = JSON.toJSONString(body);
|
||||
|
||||
if (null != onlyProperties.getSecret()) {
|
||||
String token = JWTUtil.createToken(JSON.parseObject(bodyString, Map.class), onlyProperties.getSecret());
|
||||
body.setToken(token);
|
||||
bodyString = JSON.toJSONString(body);
|
||||
}
|
||||
|
||||
log.debug(bodyString);
|
||||
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
|
||||
try {
|
||||
URL url = new URL(onlyProperties.getDocService() + onlyProperties.CONVERTER);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
connection.setFixedLengthStreamingMode(bodyByte.length);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setConnectTimeout(onlyProperties.getTimeout());
|
||||
|
||||
connection.connect();
|
||||
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(bodyByte);
|
||||
|
||||
InputStream stream = connection.getInputStream();
|
||||
|
||||
if (stream == null) {
|
||||
throw new Exception("Could not get an answer");
|
||||
}
|
||||
|
||||
/**将流转为字符串*/
|
||||
String jsonString = FileUtil.ConvertStreamToString(stream);
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
JSONObject jsonObj = JSONObject.parseObject(jsonString);
|
||||
log.debug(jsonObj.toJSONString());
|
||||
/**
|
||||
* {
|
||||
* "endConvert":true,//转换是否完成
|
||||
* "fileUrl":“ https://documentserver/ResourceService.ashx?filename=output.doc”,//转换后的文件地址
|
||||
* "percent":100//转换完成百分比 仅参数设置为异步时
|
||||
* }
|
||||
*/
|
||||
Object error = jsonObj.get("error");
|
||||
if (error != null) {
|
||||
ProcessConvertServiceResponceError((Integer) error);
|
||||
}
|
||||
|
||||
/**检查转换是否完成,并将结果保存到一个变量中*/
|
||||
Boolean isEndConvert = (Boolean) jsonObj.get("endConvert");
|
||||
Long resultPercent = 0L;
|
||||
String responseUri = null;
|
||||
|
||||
if (isEndConvert) {
|
||||
resultPercent = 100L;
|
||||
responseUri = (String) jsonObj.get("fileUrl");
|
||||
log.debug("文件转化完成{}->{}", filetype, outputtype);
|
||||
} else {
|
||||
resultPercent = (Long) jsonObj.get("percent");
|
||||
resultPercent = resultPercent >= 100l ? 99l : resultPercent;
|
||||
}
|
||||
|
||||
return resultPercent >= 100L ? responseUri : "";
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误代码 描述
|
||||
* -1 未知错误。
|
||||
* -2 转换超时错误。
|
||||
* -3 转换错误。
|
||||
* -4 下载要转换的文档文件时出错。
|
||||
* -5 密码不正确。
|
||||
* -6 访问转换结果数据库时出错。
|
||||
* -7 输入错误。
|
||||
* -8 令牌无效。
|
||||
*/
|
||||
private void ProcessConvertServiceResponceError(int errorCode) throws Exception {
|
||||
String errorMessage = "";
|
||||
String errorMessageTemplate = "Error occurred in the ConvertService: ";
|
||||
switch (errorCode) {
|
||||
case -8:
|
||||
errorMessage = errorMessageTemplate + "令牌无效";
|
||||
break;
|
||||
case -7:
|
||||
errorMessage = errorMessageTemplate + "输入错误";
|
||||
break;
|
||||
case -6:
|
||||
errorMessage = errorMessageTemplate + "访问转换结果数据库时出错";
|
||||
break;
|
||||
case -5:
|
||||
errorMessage = errorMessageTemplate + "密码不正确";
|
||||
break;
|
||||
case -4:
|
||||
errorMessage = errorMessageTemplate + "下载要转换的文档文件时出错";
|
||||
break;
|
||||
case -3:
|
||||
errorMessage = errorMessageTemplate + "转换错误";
|
||||
break;
|
||||
case -2:
|
||||
errorMessage = errorMessageTemplate + "转换超时错误";
|
||||
break;
|
||||
case -1:
|
||||
errorMessage = errorMessageTemplate + "未知错误";
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
errorMessage = "ErrorCode = " + errorCode;
|
||||
break;
|
||||
}
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.oo.onlyoffice.config;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.oo.onlyoffice.core.Cache;
|
||||
import com.oo.onlyoffice.core.cache.InsideCache;
|
||||
import com.oo.onlyoffice.core.cache.RedisCache;
|
||||
import com.oo.onlyoffice.tools.LoadConfigUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.config
|
||||
* @CreateTime: 2023-08-01 16:17
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class CreateBean {
|
||||
@Value("${serverhost}")
|
||||
private String serverhost;
|
||||
|
||||
@Bean
|
||||
public OnlyProperties getOnlyProperties() {
|
||||
OnlyProperties onlyProperties = new OnlyProperties();
|
||||
JSONObject map = LoadConfigUtil.getMap();
|
||||
onlyProperties.setCallBackUrl(map.getStr("call-back-url"));
|
||||
onlyProperties.setDocService(map.getStr("doc-service"));
|
||||
onlyProperties.setDownloadFile(serverhost + map.getStr("download-file"));
|
||||
onlyProperties.setHistNum(map.getInt("hist-num"));
|
||||
onlyProperties.setSecret(map.getStr("secret"));
|
||||
onlyProperties.setTimeout(map.getInt("timeout"));
|
||||
onlyProperties.setLocalhostAddress(serverhost + map.getStr("localhost-address"));
|
||||
onlyProperties.setMaxSize(map.getLong("max-size"));
|
||||
log.info(JSON.toJSONString(onlyProperties));
|
||||
return onlyProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Cache getCache(RedisTemplate<String, Object> redisTemplate) {
|
||||
JSONObject map = LoadConfigUtil.getMap();
|
||||
String c = map.getStr("cache");
|
||||
if (null != c && c.equals("redis")) {
|
||||
return new RedisCache(redisTemplate);
|
||||
}
|
||||
|
||||
return new InsideCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* RedisTemplate配置
|
||||
*
|
||||
* @param lettuceConnectionFactory
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
|
||||
log.info(" --- redis config init --- ");
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jacksonSerializer();
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
|
||||
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
|
||||
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
|
||||
|
||||
// key序列化
|
||||
redisTemplate.setKeySerializer(stringSerializer);
|
||||
// value序列化
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
// Hash key序列化
|
||||
redisTemplate.setHashKeySerializer(stringSerializer);
|
||||
// Hash value序列化
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
private Jackson2JsonRedisSerializer jacksonSerializer() {
|
||||
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
return jackson2JsonRedisSerializer;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.oo.onlyoffice.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
*/
|
||||
@Data
|
||||
public class OnlyProperties {
|
||||
|
||||
|
||||
private String localhostAddress;
|
||||
|
||||
/**
|
||||
* 回调地址 不包含http表示本机地址
|
||||
*/
|
||||
|
||||
private String callBackUrl ;
|
||||
|
||||
/**
|
||||
* only office服务路径
|
||||
* 必须存在
|
||||
*/
|
||||
|
||||
private String docService ;
|
||||
/**
|
||||
* 下载文件请求接口
|
||||
* */
|
||||
|
||||
private String downloadFile;
|
||||
|
||||
/**超时时间*/
|
||||
|
||||
private Integer timeout ;
|
||||
|
||||
|
||||
/**
|
||||
* 历史文件数量
|
||||
*/
|
||||
|
||||
private Integer histNum ;
|
||||
|
||||
/**
|
||||
* JWT令牌
|
||||
*/
|
||||
|
||||
private String secret ;
|
||||
|
||||
|
||||
/**
|
||||
* 打开文件最大MB
|
||||
* */
|
||||
private Long maxSize;
|
||||
|
||||
|
||||
public final String DOC_API_URL = "/web-apps/apps/api/documents/api.js";
|
||||
public final String CONVERTER = "/ConvertService.ashx";
|
||||
public final String SAVE = "/coauthoring/CommandService.ashx";
|
||||
|
||||
|
||||
public void setMaxSize(Long maxSize) {
|
||||
if (null == maxSize){
|
||||
this.maxSize = Long.valueOf(20*1024*1024);
|
||||
}else {
|
||||
this.maxSize = maxSize*1024*1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.oo.onlyoffice.core;
|
||||
|
||||
public interface Cache {
|
||||
|
||||
Object get(String key);
|
||||
void set(String key,Object value,long time);
|
||||
void set(String key,Object value);
|
||||
boolean hasKey(String key);
|
||||
void remove(String key);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.oo.onlyoffice.core;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.oo.onlyoffice.config.OnlyProperties;
|
||||
import com.oo.onlyoffice.dto.DocumentConfig;
|
||||
import com.oo.onlyoffice.dto.EditorConfig;
|
||||
import com.oo.onlyoffice.dto.Plugins;
|
||||
import com.oo.onlyoffice.dto.document.DocumentInfo;
|
||||
import com.oo.onlyoffice.dto.document.DocumentPermission;
|
||||
import com.oo.onlyoffice.dto.document.SharingSettings;
|
||||
import com.oo.onlyoffice.dto.edit.FileCustomization;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.tools.*;
|
||||
import com.oo.onlyoffice.vo.FileConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto
|
||||
* @CreateTime: 2022-11-16 17:00
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class FileConfigFactory implements OnlyOfficeConfigFactory {
|
||||
|
||||
@Autowired
|
||||
private OnlyProperties onlyProperties;
|
||||
|
||||
/**
|
||||
* 初始化 only office 最基础的信息必要数据
|
||||
*
|
||||
* @param fileUrl 可访问的url路径
|
||||
* @param mode 打开方式
|
||||
* @param key 唯一标示符 20个字符以内
|
||||
* @param fileName 文件名称
|
||||
* @return 配置信息
|
||||
*/
|
||||
@Override
|
||||
public FileConfig buildInitConfig(String fileUrl, String mode, String key, String fileName, String clientType) {
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
FileConfig fileConfigDTO = new FileConfig();
|
||||
// 1、文档类型
|
||||
fileConfigDTO.setDocumentType(OnlyOfficeUtil.getDocumentType(fileName));
|
||||
map.put("documentType", fileConfigDTO.getDocumentType());
|
||||
map.put("type", fileConfigDTO.getType());
|
||||
// 2、onlyoffice的 api位置
|
||||
fileConfigDTO.setDocServiceApiUrl(onlyProperties.getDocService() + onlyProperties.getDOC_API_URL());
|
||||
|
||||
// ==========用户============
|
||||
FileUser user = getUser();
|
||||
// ========文档类型=============
|
||||
String typePart = FileUtil.getFileExtension(fileName);
|
||||
DocumentConfig fileDocument = DocumentConfig.builder()
|
||||
// 文件名
|
||||
.title(fileName)
|
||||
// 扩展名
|
||||
.fileType(typePart)
|
||||
// 可访问的url
|
||||
.url(fileUrl)
|
||||
// 唯一有标示符
|
||||
.key(key).info(getDocumentInfo(user)).permissions(buildPermission(mode)).build();
|
||||
fileConfigDTO.setDocument(fileDocument);
|
||||
map.put("document", fileDocument);
|
||||
// ==========编辑配置===============
|
||||
String callBackUrl = onlyProperties.getLocalhostAddress() + onlyProperties.getCallBackUrl();
|
||||
|
||||
EditorConfig editorConfig = new EditorConfig(callBackUrl, mode);
|
||||
editorConfig.setFileCustomization(getFileCustomization(mode, clientType));
|
||||
editorConfig.setFileUser(user);
|
||||
editorConfig.setPlugins(getPlugins());
|
||||
//共同编辑"coEditing"配置:
|
||||
// "coEditing": { "mode": "fast","change": true}
|
||||
JSONObject coEditing = new JSONObject();
|
||||
coEditing.put("mode", "fast");
|
||||
coEditing.put("change", "true");
|
||||
editorConfig.setCoEditing(coEditing);
|
||||
fileConfigDTO.setEditorConfig(editorConfig);
|
||||
map.put("editorConfig", editorConfig);
|
||||
|
||||
|
||||
if (null != onlyProperties.getSecret()) {
|
||||
String token = JWTUtil.createToken(map, onlyProperties.getSecret());
|
||||
fileConfigDTO.setToken(token);
|
||||
}
|
||||
|
||||
return fileConfigDTO;
|
||||
}
|
||||
|
||||
|
||||
private DocumentInfo getDocumentInfo(FileUser user) {
|
||||
SharingSettings sharingSettings = new SharingSettings();
|
||||
sharingSettings.setPermissions(new String[]{"Full Access"});
|
||||
sharingSettings.setUser(user.getName());
|
||||
sharingSettings.setIsLink(true);
|
||||
DocumentInfo info = DocumentInfo.builder().created(DateUtil.formatDateTime(new Date())).sharingSettings(Collections.singletonList(sharingSettings)).build();
|
||||
return info;
|
||||
}
|
||||
|
||||
private DocumentPermission buildPermission(String mode) {
|
||||
if (mode.equals("view")) {
|
||||
return LoadConfigUtil.getViewPermission();
|
||||
}
|
||||
return LoadConfigUtil.getEditPermission();
|
||||
}
|
||||
|
||||
private FileCustomization getFileCustomization() {
|
||||
return LoadConfigUtil.getCustomization();
|
||||
}
|
||||
|
||||
private FileCustomization getFileCustomization(String mode, String clientType) {
|
||||
FileCustomization customization = LoadConfigUtil.getCustomization();
|
||||
if (mode != null && !(mode.trim()).equals("") && mode.equals("edit")) {
|
||||
customization.setAutosave(true);
|
||||
}
|
||||
customization.setMobileForceView(false);
|
||||
if (clientType != null && clientType != "" && "mobile".equals(clientType)) {
|
||||
customization.setMobileForceView(true);
|
||||
}
|
||||
return customization;
|
||||
}
|
||||
|
||||
private Plugins getPlugins() {
|
||||
return LoadConfigUtil.getPlugins();
|
||||
}
|
||||
|
||||
|
||||
private FileUser getUser() {
|
||||
FileUser fileUser = SecurityUtils.getUserSession();
|
||||
return fileUser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.oo.onlyoffice.core;
|
||||
|
||||
|
||||
|
||||
import com.oo.onlyoffice.core.context.FileMetadata;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public interface FileHandler {
|
||||
/**
|
||||
* 处理名称
|
||||
*
|
||||
* @return 名称
|
||||
*/
|
||||
String getHandlerName();
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map{
|
||||
* 必填 fileId
|
||||
* 必填 fileName
|
||||
* 必填 fileType
|
||||
* 必填 fileSize
|
||||
* 可用携带其它值
|
||||
* }
|
||||
* @param collaborativeEditing
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
FileMetadata handlerFile(Map<String, Object> map, boolean collaborativeEditing) throws Exception;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 移除临时文件信息
|
||||
*
|
||||
* @param key key
|
||||
*/
|
||||
void removeTempFile(String key);
|
||||
|
||||
/**
|
||||
* 获取临时文件信息
|
||||
*
|
||||
* @param key key
|
||||
*/
|
||||
Optional<FileMetadata> getTempFile(String key);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.oo.onlyoffice.core;
|
||||
|
||||
|
||||
import com.oo.onlyoffice.vo.FileConfig;
|
||||
|
||||
public interface OnlyOfficeConfigFactory {
|
||||
|
||||
|
||||
/**
|
||||
* 文件初始化onlyOffice必须信息
|
||||
*
|
||||
* @param fileUrl 文件地址
|
||||
* @param key 文件唯一标识
|
||||
* @param fileName 文件名称
|
||||
* @return onlyOffice必须信息
|
||||
*/
|
||||
FileConfig buildInitConfig(String fileUrl, String mode, String key, String fileName,String clientType);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.oo.onlyoffice.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 保存文件处理执行的方法
|
||||
*/
|
||||
public interface SaveFileProcessor {
|
||||
/**
|
||||
* 保存文件前进行自定义处理
|
||||
* @param bytes
|
||||
* @param fileExtension 文件后缀
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
void saveBeforeInitialization(Map<String, Object> map,byte[] bytes,String fileExtension) throws Exception;
|
||||
|
||||
/**
|
||||
* 存储onlyoffice文件信息
|
||||
* @param map 文件元信息
|
||||
* @param file 文件
|
||||
* @param changes 文件变动信息
|
||||
* @param fileId 文件id
|
||||
* @return
|
||||
*/
|
||||
Map<String, Object> save(Map<String, Object> map,byte[] file, byte[] changes,String fileId);
|
||||
|
||||
/**
|
||||
* 保存文件后进行自定义处理
|
||||
* @param bytes
|
||||
* @param fileExtension 文件后缀
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
void saveAfterInitialization(Map<String, Object> map,byte[] bytes,String fileExtension) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.oo.onlyoffice.core.cache;
|
||||
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import com.oo.onlyoffice.core.Cache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.tools
|
||||
*
|
||||
* @CreateTime: 2023-07-30 17:11
|
||||
* @Description: 内部缓存
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class InsideCache implements Cache {
|
||||
|
||||
private long timeout = 60;
|
||||
|
||||
//时间单位 秒
|
||||
private long timeUnit = 1000;
|
||||
|
||||
//创建缓存,默认 1分钟 过期
|
||||
private TimedCache<String, Object> cache = CacheUtil.newTimedCache(timeout*timeUnit);
|
||||
|
||||
|
||||
public InsideCache(){
|
||||
cache.schedulePrune(timeout*timeUnit);
|
||||
}
|
||||
|
||||
public Object get(String key){
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
public boolean hasKey(String key){
|
||||
return cache.get(key) == null ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param time 时间 单位是秒
|
||||
*/
|
||||
public void set(String key,Object value,long time){
|
||||
if (time < timeUnit){
|
||||
time = timeout;
|
||||
}
|
||||
log.info("key:{},value:{},size:{}",key,value,cache.size());
|
||||
cache.put(key, value, time*timeUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, Object value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
public void remove(String key){
|
||||
cache.remove(key);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.oo.onlyoffice.core.cache;
|
||||
|
||||
import com.oo.onlyoffice.core.Cache;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.core.cache
|
||||
*
|
||||
* @CreateTime: 2023-08-01 18:06
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
|
||||
public class RedisCache implements Cache {
|
||||
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public RedisCache(RedisTemplate<String, Object> redisTemplate){
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.oo.onlyoffice.core.context;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.oo.onlyoffice.core.FileHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 存储文件信息
|
||||
*/
|
||||
@Component
|
||||
public class FileContext {
|
||||
|
||||
public final Map<String, FileHandler> tempMaps = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
|
||||
public static Map<String, FileMetadata> keyUrlInfo = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
public FileContext(Map<String, FileHandler> tempMap) {
|
||||
this.tempMaps.clear();
|
||||
tempMap.forEach((k, v) -> this.tempMaps.put(v.getHandlerName(), v));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的执行
|
||||
*
|
||||
* @param handler
|
||||
* @return 结果
|
||||
*/
|
||||
public FileHandler getHandler(String handler) {
|
||||
return tempMaps.get(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的 处理方式
|
||||
*
|
||||
* @param key key
|
||||
* @return 结果
|
||||
*/
|
||||
public FileHandler getHandlerByKey(String key) {
|
||||
for (FileHandler tempFileHandler : tempMaps.values()) {
|
||||
FileMetadata tempFileInfo = keyUrlInfo.get(tempFileHandler.getHandlerName() + key);
|
||||
if (Objects.nonNull(tempFileInfo)) {
|
||||
return tempFileHandler;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public FileMetadata getFileInfo(String key) {
|
||||
for (FileHandler fileHandler : tempMaps.values()) {
|
||||
FileMetadata fileInfo = keyUrlInfo.get(fileHandler.getHandlerName() + key);
|
||||
if (Objects.nonNull(fileInfo)) {
|
||||
return fileInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件信息
|
||||
* @param key
|
||||
* @param map
|
||||
*/
|
||||
public void updateCacheFileInfo(String key,Map<String, Object> map) {
|
||||
FileHandler fileInfo = getHandlerByKey(key);
|
||||
if (fileInfo != null){
|
||||
System.out.println("更新内存文件信息:"+ JSON.toJSONString(map));
|
||||
FileMetadata fileMetadata = keyUrlInfo.get(fileInfo.getHandlerName() + key);
|
||||
|
||||
fileMetadata.setFileInfo(map);
|
||||
keyUrlInfo.put(fileInfo.getHandlerName() + key, fileMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.oo.onlyoffice.core.context;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 文件元数据信息
|
||||
*/
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
public class FileMetadata {
|
||||
/**
|
||||
* 文件可访问的url
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 文件标示符 最大长度为10位
|
||||
*/
|
||||
private String key;
|
||||
/**
|
||||
* 文件名称 源文件名
|
||||
*/
|
||||
private String oldName;
|
||||
|
||||
private String fileType;
|
||||
|
||||
|
||||
/**
|
||||
* 历史版本路径
|
||||
*/
|
||||
private String histVerPath;
|
||||
|
||||
|
||||
/**
|
||||
* 文件信息
|
||||
*/
|
||||
private Map<String,Object> fileInfo;
|
||||
|
||||
/**
|
||||
* 打开时间
|
||||
*/
|
||||
|
||||
private long openTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.oo.onlyoffice.core.enums;
|
||||
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
public enum DocumentTypeEnum {
|
||||
Word,
|
||||
Cell,
|
||||
Slide
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.oo.onlyoffice.core.handler;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.oo.onlyoffice.config.OnlyProperties;
|
||||
import com.oo.onlyoffice.core.Cache;
|
||||
import com.oo.onlyoffice.core.context.FileContext;
|
||||
import com.oo.onlyoffice.core.context.FileMetadata;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import com.oo.onlyoffice.core.FileHandler;
|
||||
import com.oo.onlyoffice.tools.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 文件处理方式
|
||||
*
|
||||
* getID_+key 存储的文件id
|
||||
* collaborativeEditing_+文件id 存储的 key 协同编辑使用同一个 key
|
||||
* userID+文件id 存储的 key
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FileHandlerImpl implements FileHandler {
|
||||
|
||||
|
||||
@Autowired
|
||||
private OnlyProperties onlyProperties;
|
||||
@Autowired
|
||||
private Cache cache;
|
||||
|
||||
private int time = 60*30;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getHandlerName() {
|
||||
return "onlyOffice-";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param map
|
||||
* @param collaborativeEditing
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public FileMetadata handlerFile(Map<String, Object> map, boolean collaborativeEditing) throws Exception {
|
||||
|
||||
try {
|
||||
String id = (String) map.get("fileId");
|
||||
|
||||
log.info("源文件存储的ID" + id);
|
||||
// 唯一标示符
|
||||
/**
|
||||
* 协同编辑时用的同一个key,判断是否协同,是:查找缓存中有无key,否:新生成key
|
||||
* */
|
||||
String key = "";
|
||||
String mode = (String) map.get("mode");
|
||||
if (mode.equals("edit")) { //编辑模式
|
||||
if (collaborativeEditing) {
|
||||
if (cache.get("collaborativeEditing_" + id) != null) {
|
||||
key = (String) cache.get("collaborativeEditing_" + id);
|
||||
} else {
|
||||
key = IdUtil.simpleUUID();
|
||||
cache.set("collaborativeEditing_" + id, key);
|
||||
cache.set("getID_" + key, id);
|
||||
}
|
||||
} else {
|
||||
key = IdUtil.simpleUUID();
|
||||
FileUser user = SecurityUtils.getUserSession();
|
||||
cache.set(user.getId() + "_" + id, key);
|
||||
cache.set("getID_" + key, id);
|
||||
}
|
||||
} else {
|
||||
//查看模式
|
||||
if (collaborativeEditing) {
|
||||
if (cache.get("collaborativeEditing_" + id) != null) {
|
||||
key = (String) cache.get("collaborativeEditing_" + id);
|
||||
} else {
|
||||
key = IdUtil.simpleUUID();
|
||||
cache.set("collaborativeEditing_" + id, key);
|
||||
cache.set("getID_" + key, id);
|
||||
}
|
||||
} else {
|
||||
key = IdUtil.simpleUUID();
|
||||
FileUser user = SecurityUtils.getUserSession();
|
||||
cache.set(user.getId() + "_" + id, key);
|
||||
cache.set("getID_" + key, id);
|
||||
}
|
||||
// key = id;
|
||||
}
|
||||
|
||||
|
||||
Optional<FileMetadata> tempFileInfoOptional = this.getTempFile(key);
|
||||
if (tempFileInfoOptional.isPresent()) {
|
||||
return tempFileInfoOptional.get();
|
||||
}
|
||||
|
||||
// 生成临时可访问文件的url
|
||||
String tempUrl = getFileUri(id);
|
||||
|
||||
FileMetadata tempFileInfo = FileMetadata.builder()
|
||||
// 可访问路径
|
||||
.url(tempUrl)
|
||||
// 原来的文件名
|
||||
.oldName((String) map.get("fileName"))
|
||||
.fileType((String) map.get("fileType"))
|
||||
.fileInfo(map)
|
||||
// 唯一标识
|
||||
.key(key)
|
||||
.openTime(new Date().getTime())
|
||||
.build();
|
||||
if (mode.equals("edit")) {
|
||||
FileContext.keyUrlInfo.put(getHandlerName() + key, tempFileInfo);
|
||||
}
|
||||
return tempFileInfo;
|
||||
} catch (Exception e) {
|
||||
log.error("生成临时文件失败", e);
|
||||
throw new Exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeTempFile(String key) {
|
||||
Optional<FileMetadata> tempFileInfo = this.getTempFile(key);
|
||||
if (tempFileInfo.isPresent()) {
|
||||
FileContext.keyUrlInfo.remove(getHandlerName() + key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否存在临时文件信息
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public Optional<FileMetadata> getTempFile(String key) {
|
||||
FileMetadata tempFileInfo = FileContext.keyUrlInfo.get(getHandlerName() + key);
|
||||
return Optional.ofNullable(tempFileInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件可访问的地址
|
||||
*
|
||||
* @param id
|
||||
* @return 地址
|
||||
*/
|
||||
private String getFileUri(String id) {
|
||||
if (onlyProperties.getDownloadFile().endsWith("/")) {
|
||||
return onlyProperties.getDownloadFile() + id ;
|
||||
}
|
||||
return onlyProperties.getDownloadFile() + "/"+ id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.oo.onlyoffice.dto;
|
||||
|
||||
import com.oo.onlyoffice.dto.document.DocumentInfo;
|
||||
import com.oo.onlyoffice.dto.document.DocumentPermission;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* file文档部分
|
||||
*/
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
public class DocumentConfig implements Serializable {
|
||||
/**
|
||||
* 文件类型 如 docx
|
||||
* 只需要文件的扩展名
|
||||
*/
|
||||
private String fileType;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 文件访问的url
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 定义用于服务的文档识别的唯一文档标识符。在发送已知密钥的情况下,文档将从高速缓存中取出。
|
||||
* 每次编辑和保存文档时,必须重新生成密钥。
|
||||
* 文档url可以用作键,但是没有特殊字符,长度限制为20个符号。
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 文件作者信息
|
||||
*/
|
||||
private DocumentInfo info;
|
||||
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
private DocumentPermission permissions;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.oo.onlyoffice.dto;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.oo.onlyoffice.dto.edit.FileCustomization;
|
||||
import com.oo.onlyoffice.dto.edit.FileEmbedded;
|
||||
import com.oo.onlyoffice.dto.edit.FileRecent;
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 编辑配置
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class EditorConfig implements Serializable {
|
||||
|
||||
/**
|
||||
* 回调地址
|
||||
* 指定文档存储服务的绝对URL(必须由在自己的服务器上使用ONLYOFFICE Document Server的软件集成器实现)。
|
||||
* 必填*
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
/**
|
||||
* 定义文档创建后的绝对URL,并在创建后可用。如果没有指定,将没有创建按钮
|
||||
*/
|
||||
private String createUrl;
|
||||
|
||||
|
||||
/**
|
||||
* 语言
|
||||
* 定义编辑器接口语言(如果存在除英语之外的其他语言)。
|
||||
* 使用两个字母(DE、RU、IT等)或四个字母(EN美国、FR FR等)来设置语言代码。不填默认值是"EN US"。
|
||||
*/
|
||||
private String lang = "zh-CN";
|
||||
|
||||
|
||||
/**
|
||||
* 定义编辑器打开模式。
|
||||
* 可以是打开用于查看的文档的视图,也可以是在允许对文档数据应用更改的编辑模式下打开文档的编辑。
|
||||
* 默认值是edit
|
||||
* view 视图
|
||||
* edit 编辑
|
||||
*/
|
||||
private String mode;
|
||||
|
||||
/**
|
||||
* 最近打开历史
|
||||
*/
|
||||
private List<FileRecent> recent;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
private FileUser user;
|
||||
|
||||
/**
|
||||
* 自定义信息
|
||||
*/
|
||||
@JSONField(name = "customization")
|
||||
private FileCustomization customization;
|
||||
|
||||
/**
|
||||
*共同编辑
|
||||
*/
|
||||
private Object coEditing;
|
||||
|
||||
@JSONField(name = "embedded")
|
||||
private FileEmbedded embedded;
|
||||
|
||||
/**
|
||||
* 请查看官方文档
|
||||
* 自定义插件
|
||||
* https://api.onlyoffice.com/editors/config/editor/plugins
|
||||
*/
|
||||
private Plugins plugins;
|
||||
|
||||
public EditorConfig(String callbackUrl) {
|
||||
this.callbackUrl = callbackUrl;
|
||||
}
|
||||
public EditorConfig(String callbackUrl,String mode) {
|
||||
this.callbackUrl = callbackUrl;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public void setFileCustomization(FileCustomization customization){
|
||||
this.customization = customization;
|
||||
}
|
||||
|
||||
|
||||
public void setFileUser(FileUser user){
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.oo.onlyoffice.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @BelongsProject: self-study
|
||||
* @BelongsPackage: com.project.dto
|
||||
*
|
||||
* @CreateTime: 2022-12-23 16:23
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
public class Plugins {
|
||||
|
||||
/** 插件的 guid asc.{4FF5B2DB-BDDA-CC2A-5A36-0087719EB455} */
|
||||
private String[] autostart;
|
||||
/** 插件地址 服务器地址+guid+/config.json 这的guid没有前缀 {4FF5B2DB-BDDA-CC2A-5A36-0087719EB455}*/
|
||||
private String[] pluginsData;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.oo.onlyoffice.dto.convert;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.oo.onlyoffice.dto.convert.document.DocumentLayout;
|
||||
import com.oo.onlyoffice.dto.convert.document.DocumentRenderer;
|
||||
import com.oo.onlyoffice.dto.convert.sheet.SpreadsheetLayout;
|
||||
import com.oo.onlyoffice.dto.convert.thumbnail.Thumbnail;
|
||||
import com.oo.onlyoffice.tools.LoadConfigUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:41
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class ConvertBody {
|
||||
/**
|
||||
* 定义转换请求类型:异步或非异步。
|
||||
* 默认值为false。
|
||||
*/
|
||||
private Boolean async;
|
||||
/**
|
||||
* 定义从csv或txt格式转换时的文件编码。
|
||||
* 支持的主要值:
|
||||
* 932- 日语 (移位 JIS),
|
||||
* 950-繁体中文(大5),
|
||||
* 1250- 中欧 (视窗),
|
||||
* 1251-西里尔文(视窗),
|
||||
* 65001- 统一码 (UTF-8)。
|
||||
*/
|
||||
private Integer codePage;
|
||||
/**
|
||||
* 定义从csv格式转换时用于分隔值的分隔符。
|
||||
* 0- 无分隔符,
|
||||
* 1-标签,
|
||||
* 2-分号,
|
||||
* 3-冒号,
|
||||
* 4-逗号,
|
||||
* 5-空间。
|
||||
*/
|
||||
private Integer delimiter;
|
||||
|
||||
/** 必填 文件类型*/
|
||||
private String filetype;
|
||||
/** 必填 文件key*/
|
||||
private String key;
|
||||
/** 必填 输出类型*/
|
||||
private String outputtype;
|
||||
/**密码*/
|
||||
private String password;
|
||||
/**地区 默认值为en-US*/
|
||||
private String region;
|
||||
|
||||
/**定义转换后的文件名。*/
|
||||
private String title;
|
||||
|
||||
/**必填 定义要转换的文档的绝对 URL。*/
|
||||
private String url;
|
||||
|
||||
/**token*/
|
||||
private String token;
|
||||
|
||||
/**文档布局*/
|
||||
private DocumentLayout documentLayout;
|
||||
/**文档渲染器*/
|
||||
private DocumentRenderer documentRenderer;
|
||||
/**表格布局*/
|
||||
private SpreadsheetLayout spreadsheetLayout;
|
||||
|
||||
private Thumbnail thumbnail;
|
||||
|
||||
public ConvertBody(String filetype,String key,String outputtype,String url,String title,String password){
|
||||
this.filetype =filetype;
|
||||
this.key =key;
|
||||
this.outputtype = outputtype;
|
||||
this.password = password;
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
this.region = "zh-CN";
|
||||
|
||||
JSONObject convert = LoadConfigUtil.getConvert();
|
||||
setAsync(convert.getBool("async"));
|
||||
setCodePage(convert.getInt("codePage"));
|
||||
setDelimiter(convert.getInt("delimiter"));
|
||||
setRegion(convert.getStr("region"));
|
||||
|
||||
//判断以下属性是否启用
|
||||
JSONObject documentLayout = convert.getJSONObject("documentLayout");
|
||||
if (documentLayout.getBool("enabled")){
|
||||
setDocumentLayout(convert.get("documentLayout", DocumentLayout.class));
|
||||
}
|
||||
|
||||
JSONObject documentRenderer = convert.getJSONObject("documentRenderer");
|
||||
if (documentRenderer.getBool("enabled")){
|
||||
setDocumentRenderer(convert.get("documentRenderer", DocumentRenderer.class));
|
||||
}
|
||||
|
||||
JSONObject spreadsheetLayout = convert.getJSONObject("spreadsheetLayout");
|
||||
if (spreadsheetLayout.getBool("enabled")){
|
||||
setSpreadsheetLayout(convert.get("spreadsheetLayout", SpreadsheetLayout.class));
|
||||
}
|
||||
|
||||
JSONObject thumbnail = convert.getJSONObject("thumbnail");
|
||||
if (thumbnail.getBool("enabled")){
|
||||
setThumbnail(convert.get("thumbnail",Thumbnail.class));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAsync(Boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
public void setCodePage(Integer codePage) {
|
||||
this.codePage = codePage;
|
||||
}
|
||||
|
||||
public void setDelimiter(Integer delimiter) {
|
||||
this.delimiter = delimiter;
|
||||
}
|
||||
|
||||
public void setRegion(String region) {
|
||||
if (null != region){
|
||||
this.region = region;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDocumentLayout(DocumentLayout documentLayout) {
|
||||
this.documentLayout = documentLayout;
|
||||
}
|
||||
|
||||
public void setDocumentRenderer(DocumentRenderer documentRenderer) {
|
||||
this.documentRenderer = documentRenderer;
|
||||
}
|
||||
|
||||
public void setSpreadsheetLayout(SpreadsheetLayout spreadsheetLayout) {
|
||||
this.spreadsheetLayout = spreadsheetLayout;
|
||||
}
|
||||
|
||||
public void setThumbnail(Thumbnail thumbnail) {
|
||||
this.thumbnail = thumbnail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.oo.onlyoffice.dto.convert.document;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:44
|
||||
* @Description: 文档布局
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class DocumentLayout {
|
||||
/**定义是否绘制占位符。*/
|
||||
private Boolean drawPlaceHolders;
|
||||
/**定义是否突出显示表单。*/
|
||||
private Boolean drawFormHighlight;
|
||||
/***
|
||||
* 定义打印模式是打开还是关闭。
|
||||
* 此参数仅用于将docx/docxf转换为pdf。
|
||||
* 如果此参数等于true,则如上所述使用drawPlaceHolder和drawFormHighlight标志。
|
||||
* 如果此参数为false,则drawFormHighlight标志不起作用,
|
||||
* 并且drawPlaceHolder参数允许以pdf格式保存表单。 默认值为false。
|
||||
*/
|
||||
private Boolean isPrint;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.oo.onlyoffice.dto.convert.document;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:46
|
||||
* @Description: 文档渲染器
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class DocumentRenderer {
|
||||
/***
|
||||
* 定义可以具有以下值的呈现模式:
|
||||
* 块字符(blockChar) - 所有文本都由单个字符转换。 每个字符都在自己的框架中(如文本框),
|
||||
* blockLine- 所有文本都由单独的行转换。 每个文本行都位于其自己的框架中。行可以在同一块内组合,
|
||||
* 纯行(plainLine) - 所有文本都转换为纯文本。 但每一行都是一个单独的段落,
|
||||
* 纯段落(plainParagraph ) - 所有文本都转换为纯文本。 行合并为段落。
|
||||
* 默认值为plainLine。
|
||||
*/
|
||||
private String textAssociation;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.oo.onlyoffice.dto.convert.sheet;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert.sheet
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:55
|
||||
* @Description: 边距
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Margins {
|
||||
/**设置输出 PDF 文件的边距 默认 19.1mm */
|
||||
private String bottom;
|
||||
/** 默认 17.8mm */
|
||||
private String left;
|
||||
/** 默认 17.8mm */
|
||||
private String right;
|
||||
/** 默认 19.1mm */
|
||||
private String top;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.oo.onlyoffice.dto.convert.sheet;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert.sheet
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:58
|
||||
* @Description: 页面大小
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class PageSize {
|
||||
/** 设置输出 PDF 文件的页面高度。默认 297mm*/
|
||||
private String height;
|
||||
/** 设置输出 PDF 文件的页面宽度。默认 210mm*/
|
||||
private String width;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.oo.onlyoffice.dto.convert.sheet;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert
|
||||
*
|
||||
* @CreateTime: 2022-11-23 09:50
|
||||
* @Description: 电子表格布局
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class SpreadsheetLayout {
|
||||
/**设置转换区域的高度(以页数为单位)。 默认值为0。*/
|
||||
private Integer fitToHeight;
|
||||
/**设置转换区域的宽度(以页数为单位)。 默认值为0。*/
|
||||
private Integer fitToWidth;
|
||||
/**允许是否在输出PDF文件中包含网格线。 默认值为false。*/
|
||||
private Boolean gridLines;
|
||||
/**允许是否包含输出PDF文件的标题。 默认值为false。*/
|
||||
private Boolean headings;
|
||||
/**确定是否忽略为电子表格文件选择的打印区域。 默认值为true。*/
|
||||
private Boolean ignorePrintArea;
|
||||
|
||||
private Margins margins;
|
||||
/**设置输出 PDF 文件的方向。 可能是landscape, portrait. 默认值为纵向(portrait)。*/
|
||||
private String orientation;
|
||||
|
||||
private PageSize pageSize;
|
||||
/**允许设置输出PDF文件的比例。 默认值为100。*/
|
||||
private Integer scale;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.oo.onlyoffice.dto.convert.thumbnail;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.convert.thumbnail
|
||||
*
|
||||
* @CreateTime: 2022-11-23 10:18
|
||||
* @Description: 缩略图 定义将图像格式(bmp,gif,jpg,png)指定为输出类型时缩略图的设置。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class Thumbnail {
|
||||
/**
|
||||
* 定义使图像适合指定高度和宽度的模式。 支持的值:
|
||||
* 0-拉伸文件以适合高度和宽度,
|
||||
* 1-保留图像的纵横比,
|
||||
* 2-在这种情况下,不使用宽度和高度设置。 取而代之的是,页面的度量大小将转换为具有 96dpi 的像素。 例如,A4(210x297mm)页面将是一张尺寸为794x1123像素的图片。
|
||||
* 默认值为2。
|
||||
*/
|
||||
private Integer aspect;
|
||||
/**
|
||||
* 定义是应仅为第一页生成缩略图,还是应为所有文档页面生成缩略图。
|
||||
* 如果为 false,则将创建包含所有页面缩略图的 zip 存档。
|
||||
* 默认值为true,
|
||||
*/
|
||||
private Boolean first;
|
||||
/**
|
||||
* 定义缩略图高度(以像素为单位)。 默认值为100。
|
||||
*/
|
||||
private Integer height;
|
||||
/**
|
||||
* 定义缩略图宽度(以像素为单位)。 默认值为100。
|
||||
*/
|
||||
private Integer width;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.oo.onlyoffice.dto.document;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* file文档部分
|
||||
*/
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
public class DocumentInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 定义收藏夹图标的突出显示状态。 当用户单击该图标时,将调用onMetaChange事件
|
||||
*/
|
||||
private String favorite;
|
||||
|
||||
/**
|
||||
* 创建时间(格式化后数据)
|
||||
*/
|
||||
private String owner;
|
||||
/**
|
||||
* 创建时间(格式化后数据)
|
||||
*/
|
||||
private String created;
|
||||
|
||||
/**
|
||||
* 存储文件夹可以为空
|
||||
*/
|
||||
private String folder;
|
||||
|
||||
/**
|
||||
* 分享
|
||||
* Defines the settings which will allow to share the document with other users:
|
||||
* permissions - the access rights for the user with the name above. Can be Full Access, Read Only or Deny Access
|
||||
* type: string
|
||||
* example: "Full Access"
|
||||
* user - the name of the user the document will be shared with
|
||||
* type: string
|
||||
* example: "John Smith".
|
||||
*/
|
||||
private List<SharingSettings> sharingSettings;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.oo.onlyoffice.dto.document;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* file 权限
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DocumentPermission implements Serializable {
|
||||
|
||||
/**
|
||||
* 定义是否在文档中启用聊天功能。 如果聊天权限设置为true,将显示聊天菜单按钮。 默认值为true。
|
||||
* */
|
||||
private Boolean chat;
|
||||
|
||||
/**
|
||||
* 定义文档是否可以被注释。
|
||||
* 在注释权限设置为“true”的情况下,文档侧栏将包含“注释”菜单选项;
|
||||
* 如果该模式参数设置为“编辑”,则文档注释仅可用于文档编辑器。
|
||||
* 默认值与编辑参数的值一致。
|
||||
* 默认为true
|
||||
*/
|
||||
private Boolean comment;
|
||||
/***
|
||||
"edit": ["Group2", ""],
|
||||
"remove": [""],
|
||||
"view": "" ,
|
||||
定义用户可以编辑、删除和/或查看其注释的组。 该对象具有以下参数:
|
||||
编辑 - 用户可以编辑其他用户的评论,类型:列表,例如:[“Group2”,“”];
|
||||
删除 - 用户可以删除其他用户的评论,类型:列表,
|
||||
示例:[];
|
||||
查看 - 用户可以查看其他用户的评论,类型:列表,
|
||||
[“”]值表示用户可以编辑/删除/查看不属于这些组的人员所做的评论(例如,如果在第三方编辑器中审阅文档)。
|
||||
如果值为 [],则用户无法编辑/删除/查看任何组所做的注释。
|
||||
如果编辑、删除和查看参数为“”或未指定,则用户可以查看/编辑/删除任何用户所做的评论。
|
||||
*/
|
||||
private Object commentGroups;
|
||||
|
||||
/**
|
||||
* 定义是否可以将内容复制到剪贴板。
|
||||
* 如果参数设置为false,则粘贴内容将仅在当前文档编辑器中可用。 默认值为true。
|
||||
*/
|
||||
private Boolean copy;
|
||||
|
||||
/**
|
||||
* 定义用户是否只能删除其注释。 默认值为false。
|
||||
*/
|
||||
private Boolean deleteCommentAuthorOnly;
|
||||
/**
|
||||
* 是否允许下载 默认为true
|
||||
*/
|
||||
private Boolean download;
|
||||
/**
|
||||
* 是否允许编辑 默认true
|
||||
*/
|
||||
private Boolean edit;
|
||||
|
||||
/**
|
||||
* 定义用户是否只能编辑其注释。 默认值为false。
|
||||
*/
|
||||
private Boolean editCommentAuthorOnly;
|
||||
|
||||
/**
|
||||
* 是否可以填写表单 默认true
|
||||
* 如果编辑设置为“true”或审阅设置为“true”,则不考虑fillForms值,并且可以填写表单。
|
||||
* 如果编辑设置为“false”,审阅设置为“false”,并且fillForms也设置为“true”,则用户只能在文档中填写表单。
|
||||
* 如果编辑设置为“false”并且审阅设置为“false”并且fillForms设置为“true”则不考虑注释值,并且注释不可用。
|
||||
* 仅表单填写模式目前仅适用于文档编辑器。
|
||||
*/
|
||||
private Boolean fillForms;
|
||||
/**
|
||||
* 定义是否可以更改内容控件设置。 仅当mode参数设置为编辑时,内容控件修改才可用于文档编辑器。 默认值为true。
|
||||
*/
|
||||
private Boolean modifyContentControl;
|
||||
/**
|
||||
* 定义筛选器是可以全局应用(true)影响所有其他用户,还是本地应用(false),即仅适用于当前用户。
|
||||
* 仅当模式参数设置为编辑时,过滤器修改才可用于电子表格编辑器。 默认值为true。
|
||||
*/
|
||||
private Boolean modifyFilter;
|
||||
/**
|
||||
* 定义文档是否可以打印。 如果打印权限设置为“false”打印菜单选项将不在“文件”菜单中。 默认值为true。
|
||||
*/
|
||||
private Boolean print;
|
||||
/**
|
||||
* 定义是显示工具栏上的“保护”选项卡和左侧菜单中的“保护”按钮(真)还是隐藏(假)。 默认值为true。
|
||||
*/
|
||||
private Boolean protect;
|
||||
/**
|
||||
* 定义文档是否可以被审核。
|
||||
* 如果审阅权限设置为“true”,则文档状态栏将包含审阅菜单选项;
|
||||
* 如果模式参数设置为编辑,则文档审阅将仅对文档编辑器可用。
|
||||
* 默认值与编辑参数的值一致。
|
||||
* 如果编辑设置为“true”并且审阅也设置为“true”,则用户将能够编辑文档,接受/拒绝所做的更改并自己切换到审阅模式。
|
||||
* 如果编辑设置为“true”并且审阅设置为“false”,则用户将只能进行编辑。 如果编辑设置为“false”并且审阅设置为“true”,则文档将仅在审阅模式下可用。
|
||||
* 默认:true
|
||||
*/
|
||||
private Boolean review;
|
||||
/**
|
||||
* 定义用户可以接受/拒绝其更改的组。 [“”]值表示用户可以审阅不属于这些组的人员所做的更改(例如,如果在第三方编辑器中审阅文档)。
|
||||
* 如果值为 [],则用户无法查看任何组所做的更改。 如果值为“”或未指定,则用户可以查看任何用户所做的更改。
|
||||
*/
|
||||
private String[] reviewGroups;
|
||||
/**
|
||||
* 定义其信息显示在编辑器中的用户组:
|
||||
* 用户名显示在编辑器标题的编辑用户列表中,
|
||||
* 键入文本时,将显示用户光标和工具提示及其名称,
|
||||
* 在严格协同编辑模式下锁定对象时,将显示用户名。
|
||||
* [“组 1”, “”] 表示显示有关组 1 中的用户和不属于任何组的用户的信息。 [] 表示根本不显示任何用户信息。 未定义的或 “” 值表示显示有关所有用户的信息。
|
||||
*/
|
||||
private String[] userInfoGroups;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.oo.onlyoffice.dto.document;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @BelongsProject: leaf-onlyoffice
|
||||
* @BelongsPackage: com.ideayp.leaf.onlyoffice.dto.document
|
||||
*
|
||||
* @CreateTime: 2022-11-09 13:53
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class SharingSettings {
|
||||
|
||||
private Boolean isLink; //将用户图标更改为链接图标
|
||||
private String[] permissions; //完全访问,只读或拒绝访问 Full Access, Read Only , Deny Access
|
||||
private String user; //共享文档的用户的名称
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.oo.onlyoffice.dto.edit;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
*@Author TongHui
|
||||
*@Date 2022/11/16
|
||||
*@ClassName FileCustomer
|
||||
*@Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class FileCustomer implements Serializable {
|
||||
|
||||
/**
|
||||
* 地址
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 介绍信息
|
||||
*/
|
||||
private String info;
|
||||
|
||||
/**
|
||||
* logo地址
|
||||
* 将显示在“关于”页上的图像标志的路径(该文件没有特别推荐,但如果是具有透明背景的.png格式会更好)。
|
||||
* 图像必须具有以下尺寸:432×70
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* 联系邮箱
|
||||
*/
|
||||
private String mail;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 网址
|
||||
*/
|
||||
private String www;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.oo.onlyoffice.dto.edit;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
*@Author TongHui
|
||||
*@Date 2022/11/16
|
||||
*@ClassName FileCustomization
|
||||
*@Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class FileCustomization implements Serializable {
|
||||
|
||||
/**
|
||||
* {
|
||||
* "request": true,
|
||||
* "label": "Guest"
|
||||
* },
|
||||
* 添加对匿名名称的请求:
|
||||
* 请求 - 定义请求是否发送。 默认值为 true,类型:布尔值,
|
||||
* 标签 - 添加到用户名的后缀。 默认值为来宾,类型:字符串,
|
||||
*/
|
||||
private Object anonymous;
|
||||
|
||||
/**
|
||||
* 定义是否启用或禁用“自动保存”菜单选项。
|
||||
* 如果设置为false,则只能选择Strict协同编辑模式,因为Fast在没有自动保存的情况下无法工作。
|
||||
* 请注意,如果您在菜单中更改此选项,它将保存到您的浏览器localStorage。默认值为true
|
||||
*/
|
||||
private Boolean autosave;
|
||||
|
||||
/**
|
||||
定义是显示还是隐藏“注释”菜单按钮。
|
||||
请注意,如果您隐藏了“评论”按钮,则相应的评论功能将仅供查看,添加和编辑评论将不可用。 默认值为true。
|
||||
*/
|
||||
private Boolean comments;
|
||||
/**
|
||||
* 定义其他操作按钮是显示在编辑器窗口标题的上部徽标旁边 (false) 还是显示在工具栏 (true) 中,从而使标题更紧凑。 默认值为false。
|
||||
*/
|
||||
private Boolean compactHeader;
|
||||
/**
|
||||
* 定义显示的顶部工具栏类型是完整 (假) 还是紧凑 (真)。 默认值为false。
|
||||
*/
|
||||
private Boolean compactToolbar;
|
||||
/**
|
||||
* 定义仅与 OOXML 格式兼容的功能的使用。 例如,不要对整个文档使用注释。 默认值为false。
|
||||
*/
|
||||
private Boolean compatibleFeatures;
|
||||
/**
|
||||
* "address": "My City, 123a-45",有权访问编辑或编辑作者的公司或个人的邮政地址
|
||||
* "info": "Some additional information",有关您希望其他人认识的公司或个人的一些其他信息,
|
||||
* "logo": "https://example.com/logo-big.png",图片徽标的路径
|
||||
* "logoDark": "https://example.com/dark-logo-big.png",深色主题的图像徽标的路径
|
||||
* "mail": "john@example.com",有权访问编辑者或编辑者的公司或个人的电子邮件地址
|
||||
* "name": "John Smith and Co.",名称
|
||||
* "phone": "123456789",电话
|
||||
* "www": "example.com"以上公司或个人的家庭网站地址
|
||||
*/
|
||||
private Object customer;
|
||||
/**
|
||||
* {"spellcheck": true}
|
||||
* 定义用户可以禁用或自定义的参数(如果可能):
|
||||
* 拼写检查 - 定义在加载编辑器时是自动打开还是关闭拼写检查器。 如果此参数是布尔值,则将其设置为初始拼写检查器值,并且不会隐藏拼写检查器设置。
|
||||
* 默认值为 true,类型:对象或布尔值,
|
||||
* {"spellcheck": {"mode": true}}
|
||||
* 拼写检查模式 - 定义在加载编辑器时拼写检查器是自动打开还是关闭。
|
||||
* 此参数仅适用于文档编辑器和演示文稿编辑器,类型:布尔值,
|
||||
* 示例:true;
|
||||
*/
|
||||
private Object features;
|
||||
/**
|
||||
* {"url": "https://example.com",
|
||||
* "visible": true}
|
||||
* 定义“反馈和支持”菜单按钮的设置。
|
||||
* 可以是布尔值(仅显示或隐藏“反馈和支持”菜单按钮)或对象。
|
||||
*/
|
||||
private Object feedback;
|
||||
/**在文档编辑服务中保存文档时(例如,单击“保存”按钮等),
|
||||
* 将文件强制保存的请求添加到回调处理程序中。 默认值为false。*/
|
||||
private Boolean forcesave;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "blank": true,
|
||||
* "requestClose": false,
|
||||
* "text": "Open file location",
|
||||
* "url": "https://example.com"
|
||||
* }
|
||||
* 定义“打开文件位置”菜单按钮和右上角按钮的设置。 该对象具有以下参数:
|
||||
* 空白 - 单击“打开文件位置”按钮时,在新的浏览器选项卡/窗口中打开网站(如果值设置为true)或当前选项卡(如果值设置为false)。
|
||||
* 默认值为 true,类型:布尔值,
|
||||
|
||||
* requestClose- 定义如果单击“打开文件位置”按钮,则会调用 events.onRequestClose事件,而不是打开浏览器选项卡或窗口。
|
||||
* 默认值为假,类型:布尔值,
|
||||
*
|
||||
|
||||
* text-将为“打开文件位置”菜单按钮和右上角按钮(即而不是“转到文档”)显示的文本,键入:字符串,
|
||||
|
||||
* url-单击“打开文件位置”菜单按钮时将打开的网站地址的绝对URL,键入:字符串,
|
||||
*
|
||||
*/
|
||||
private Object goback;
|
||||
/**
|
||||
* 定义是显示还是隐藏“帮助”菜单按钮。 默认值为true。
|
||||
*/
|
||||
private Boolean help;
|
||||
/**
|
||||
* 定义在首次加载时是显示还是隐藏注释面板。 默认值为false。此参数仅适用于演示文稿编辑器ppt。
|
||||
*/
|
||||
private Boolean hideNotes;
|
||||
/**
|
||||
* 定义首次加载时是显示还是隐藏右侧菜单。 默认值为false。
|
||||
*/
|
||||
private Boolean hideRightMenu;
|
||||
/**
|
||||
* 定义是显示还是隐藏编辑器标尺。 此参数可用于文档和演示文稿编辑器。文档编辑器的默认值为false,演示文稿的默认值为true。
|
||||
*/
|
||||
private Boolean hideRulers;
|
||||
|
||||
/**
|
||||
* 定义将编辑器嵌入网页的模式。 嵌入值在加载编辑器框架时禁用滚动到编辑器框架,因为未捕获焦点。
|
||||
*/
|
||||
private String integrationMode;
|
||||
|
||||
/**
|
||||
* "image": "https://example.com/logo.png",
|
||||
* "imageDark": "https://example.com/dark-logo.png",
|
||||
* "url": "https://www.onlyoffice.com"
|
||||
* 更改编辑器标题左上角的图像文件。 建议的图像高度为 20 像素。 该对象具有以下参数:
|
||||
* image- 用于在通用工作模式(即所有编辑器的查看和编辑模式下)或嵌入模式下显示的图像文件的路径(请参阅配置部分以了解如何定义嵌入式文档类型)。
|
||||
* 图像必须具有以下大小:172x40,类型:字符串,
|
||||
*
|
||||
* imageDark - 用于深色主题的图像文件的路径。 图像必须具有以下大小:172x40,类型:字符串,
|
||||
*
|
||||
* url - 当有人点击徽标图像时将使用的绝对URL(可用于访问您的网站等)。
|
||||
* 保留为空字符串或null以使徽标不可点击,键入:字符串,
|
||||
*/
|
||||
private Object logo;
|
||||
|
||||
/**
|
||||
* 定义在编辑器打开时是否自动运行文档宏。 默认值为true。false值对用户隐藏宏设置。
|
||||
*/
|
||||
private Boolean macros;
|
||||
/**
|
||||
* disable
|
||||
* enable
|
||||
* warn 默认
|
||||
*/
|
||||
private String macrosMode;
|
||||
/**
|
||||
*定义在注释中提及后描述事件的提示。
|
||||
* 如果为 true,则提示指示用户将收到通知并访问文档。
|
||||
* 如果为 false,则提示指示用户将仅收到提及通知。 默认值为true。
|
||||
* 请注意,只有在设置了onRequestSendNotify事件的情况下,它才可用于注释。
|
||||
*/
|
||||
private Boolean mentionShare;
|
||||
/**
|
||||
* 定义插件是否启动并可用。 默认值为true。
|
||||
*/
|
||||
private Boolean plugins;
|
||||
|
||||
/**
|
||||
* "hideReviewDisplay": false, 定义在“协作”选项卡上显示还是隐藏“显示模式”按钮。 默认值为假,类型:布尔值,
|
||||
* "hoverMode": false 定义审阅显示模式:通过悬停更改在工具提示中显示审阅 (true) 或通过单击更改(假)在气球中。 默认值为false。
|
||||
*/
|
||||
private Object review;
|
||||
|
||||
/**
|
||||
* 定义文档标题是在顶部工具栏上可见 (假) 还是隐藏 (真)。 默认值为false。
|
||||
*/
|
||||
private Boolean toolbarHideFileName;
|
||||
|
||||
/**
|
||||
* 定义顶部工具栏选项卡是清晰显示 (false) 还是仅突出显示以查看选择了哪个选项卡 (true)。 默认值为false。
|
||||
*/
|
||||
private Boolean toolbarNoTabs;
|
||||
|
||||
/**
|
||||
*定义编辑器主题设置。 可以通过两种方式进行设置:
|
||||
* 主题 ID - 用户通过其 ID 设置主题参数(主题-浅色、主题-经典-浅色、主题-深色、主题-对比度-深),
|
||||
* 默认主题 - 将设置默认的深色或浅色主题值(默认深色,默认浅色)。 默认浅色主题为主题经典浅色。
|
||||
* 第一个选项具有更高的优先级。除了可用的编辑器主题外,用户还可以为应用程序界面自定义自己的颜色主题。
|
||||
* 颜色可以以十六进制或 RGBA 格式呈现。
|
||||
*/
|
||||
private String uiTheme;
|
||||
|
||||
/**
|
||||
* 定义标尺和对话框中使用的度量单位。 可以采用以下值:
|
||||
* 厘米,
|
||||
* pt-点,
|
||||
* 英寸 - 英寸。
|
||||
* 默认值为厘米 (cm)。
|
||||
*/
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* 定义以百分比度量的文档显示缩放值。 可以采用大于0 的值。
|
||||
* 对于文本文档和演示文稿,可以将此参数设置为 -1(使文档适合页面选项)或 to-2(使文档页面宽度适合编辑器页面)。
|
||||
* 默认值为100。
|
||||
*/
|
||||
private Integer zoom;
|
||||
private Boolean mobileForceView;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.oo.onlyoffice.dto.edit;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 当type =embedded 生效
|
||||
*/
|
||||
@Data
|
||||
public class FileEmbedded implements Serializable {
|
||||
|
||||
/**
|
||||
* 文件url
|
||||
* "https://example.com/embedded?doc=exampledocument1.docx"
|
||||
*/
|
||||
private String embedUrl="https://example.com/embedded?doc=exampledocument1.docx";
|
||||
|
||||
/**
|
||||
* "https://example.com/embedded?doc=exampledocument1.docx#fullscreen"
|
||||
*/
|
||||
private String fullscreenUrl="https://example.com/embedded?doc=exampledocument1.docx";
|
||||
|
||||
/**
|
||||
* 保存的url
|
||||
* "https://example.com/download?doc=exampledocument1.docx"
|
||||
*/
|
||||
private String saveUrl;
|
||||
|
||||
/**
|
||||
* "https://example.com/view?doc=exampledocument1.docx"
|
||||
*/
|
||||
private String shareUrl;
|
||||
|
||||
/**
|
||||
* 定义嵌入式浏览器工具栏的位置,可以是顶部或底部
|
||||
* 默认top
|
||||
* bottom/top
|
||||
*/
|
||||
private String toolbarDocked;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.oo.onlyoffice.dto.edit;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 最近打开
|
||||
*/
|
||||
@Data
|
||||
public class FileRecent implements Serializable {
|
||||
|
||||
/**
|
||||
* 文件夹
|
||||
*/
|
||||
private String folder;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* url 绝对路径
|
||||
*/
|
||||
private String url;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.oo.onlyoffice.dto.edit;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 使用文件的用户信息
|
||||
*/
|
||||
@Data
|
||||
public class FileUser implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户唯一标识
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 用户 全称
|
||||
*/
|
||||
private String name;
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 组
|
||||
*/
|
||||
private String[] group;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @BelongsProject: office-demo
|
||||
* @BelongsPackage: com.doc.utils
|
||||
*
|
||||
* @CreateTime: 2022-11-04 18:25
|
||||
* @Description: 生成ID
|
||||
* @Version: 1.0
|
||||
*/
|
||||
|
||||
public class DocumentKey {
|
||||
|
||||
private static Snowflake snowflake;
|
||||
|
||||
static {
|
||||
// 0 ~ 31 位,可以采用配置的方式使用
|
||||
long workerId;
|
||||
try {
|
||||
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
|
||||
} catch (Exception e) {
|
||||
workerId = NetUtil.getLocalhostStr().hashCode();
|
||||
}
|
||||
|
||||
workerId = workerId >> 16 & 31;
|
||||
|
||||
long dataCenterId = 1L;
|
||||
snowflake = IdUtil.createSnowflake(workerId,dataCenterId);
|
||||
}
|
||||
|
||||
public static String SnowflakeId() {
|
||||
return String.valueOf(snowflake.nextId());
|
||||
}
|
||||
|
||||
public static String ShortCode() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
int week = calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
int day = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
|
||||
// 打乱排序:2020年为准 + 小时 + 周期 + 日 + 三位随机数
|
||||
StringBuilder idStr = new StringBuilder();
|
||||
idStr.append(year-2020);
|
||||
idStr.append(hour);
|
||||
//(“%04d”, 99) 0099
|
||||
idStr.append(String.format("%02d",week));
|
||||
idStr.append(day);
|
||||
idStr.append(String.format("%03d",new Random().nextInt(1000)));
|
||||
|
||||
return idStr.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.tools
|
||||
*
|
||||
* @CreateTime: 2023-07-30 17:26
|
||||
* @Description: 文件操作
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class FileUtil {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(FileUtil.class);
|
||||
|
||||
static String COMMA = ".";
|
||||
|
||||
/**
|
||||
* 获取文件后缀 不带.
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String getFileExtension(String name){
|
||||
return FileNameUtil.extName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取远程文件
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static byte[] getFileByte(String url){
|
||||
try (InputStream in = new URL(url).openConnection().getInputStream()){
|
||||
return IoUtil.readBytes(in);
|
||||
}catch (IOException e){
|
||||
log.error("读取失败:" + e.getMessage());
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 流 转字符串
|
||||
* @param stream
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String ConvertStreamToString(InputStream stream) throws IOException {
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(stream);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
|
||||
String line = bufferedReader.readLine();
|
||||
|
||||
while (line != null) {
|
||||
stringBuilder.append(line);
|
||||
line = bufferedReader.readLine();
|
||||
}
|
||||
|
||||
String result = stringBuilder.toString();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static InputStream openInputStream(File file){
|
||||
return IoUtil.toStream(file);
|
||||
}
|
||||
|
||||
// 一般oo服务回调下载
|
||||
public static void downloadInline(File file,String name,HttpServletResponse response){
|
||||
try {
|
||||
byte[] buffer = null;
|
||||
// 将文件写入输入流
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
InputStream fis = new BufferedInputStream(fileInputStream);
|
||||
buffer = new byte[fis.available()];
|
||||
fis.read(buffer);
|
||||
fis.close();
|
||||
dowInline(buffer, name, response);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public static void downloadInline(String path,String name,HttpServletResponse response){
|
||||
logger.info("文件下载:"+path);
|
||||
byte[] buffer = null;
|
||||
try {
|
||||
if (path.startsWith("http")){
|
||||
buffer = getFileByte(path);
|
||||
dowInline(buffer,name,response);
|
||||
}else {
|
||||
// path是指想要下载的文件的路径
|
||||
File file = new File(path);
|
||||
|
||||
downloadInline(file,name,response);
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
public static void downloadInline(byte[] bytes,String name,HttpServletResponse response){
|
||||
logger.info("文件下载:"+name);
|
||||
dowInline(bytes,name,response);
|
||||
}
|
||||
|
||||
|
||||
//以附件形式下载 浏览器下载使用
|
||||
public static void downloadAttachment(File file,String name,HttpServletResponse response){
|
||||
try {
|
||||
byte[] buffer = null;
|
||||
// 将文件写入输入流
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
InputStream fis = new BufferedInputStream(fileInputStream);
|
||||
buffer = new byte[fis.available()];
|
||||
fis.read(buffer);
|
||||
fis.close();
|
||||
attachment(buffer, name, response);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public static void downloadAttachment(String path,String name,HttpServletResponse response){
|
||||
logger.info("文件下载:"+path);
|
||||
byte[] buffer = null;
|
||||
try {
|
||||
if (path.startsWith("http")){
|
||||
buffer = getFileByte(path);
|
||||
downloadAttachment(buffer,name,response);
|
||||
}else {
|
||||
// path是指想要下载的文件的路径
|
||||
File file = new File(path);
|
||||
|
||||
downloadAttachment(file,name,response);
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public static void downloadAttachment(byte[] bytes,String name,HttpServletResponse response){
|
||||
attachment(bytes,name,response);
|
||||
}
|
||||
|
||||
private static void attachment(byte[] bytes,String name, HttpServletResponse response){
|
||||
try {
|
||||
// 清空response
|
||||
response.reset();
|
||||
// 设置response的Header
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType(getContentType(name));
|
||||
//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
|
||||
//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
|
||||
// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));
|
||||
// 告知浏览器文件的大小
|
||||
response.addHeader("Content-Length", "" + bytes.length);
|
||||
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
|
||||
outputStream.write(bytes);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
private static void dowInline(byte[] bytes,String name, HttpServletResponse response){
|
||||
try {
|
||||
// 清空response
|
||||
response.reset();
|
||||
// 设置response的Header
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType(getContentType(name));
|
||||
//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
|
||||
//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
|
||||
// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
|
||||
response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(name, "UTF-8"));
|
||||
// 告知浏览器文件的大小
|
||||
response.addHeader("Content-Length", "" + bytes.length);
|
||||
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
|
||||
outputStream.write(bytes);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据“文件名的后缀”获取文件内容类型(而非根据File.getContentType()读取的文件类型)
|
||||
*
|
||||
* @param returnFileName 带验证的文件名
|
||||
* @return 返回文件类型
|
||||
*/
|
||||
public static String getContentType(String returnFileName) {
|
||||
String contentType = "application/octet-stream";
|
||||
if (returnFileName.lastIndexOf(COMMA) < 0) {
|
||||
return contentType;
|
||||
}
|
||||
returnFileName = returnFileName.toLowerCase();
|
||||
returnFileName = returnFileName.substring(returnFileName.lastIndexOf(".") + 1);
|
||||
switch (returnFileName) {
|
||||
case "html":
|
||||
case "htm":
|
||||
case "shtml":
|
||||
contentType = "text/html";
|
||||
break;
|
||||
case "apk":
|
||||
contentType = "application/vnd.android.package-archive";
|
||||
break;
|
||||
case "sis":
|
||||
contentType = "application/vnd.symbian.install";
|
||||
break;
|
||||
case "sisx":
|
||||
contentType = "application/vnd.symbian.install";
|
||||
break;
|
||||
case "exe":
|
||||
contentType = "application/x-msdownload";
|
||||
break;
|
||||
case "msi":
|
||||
contentType = "application/x-msdownload";
|
||||
break;
|
||||
case "css":
|
||||
contentType = "text/css";
|
||||
break;
|
||||
case "xml":
|
||||
contentType = "text/xml";
|
||||
break;
|
||||
case "gif":
|
||||
contentType = "image/gif";
|
||||
break;
|
||||
case "jpeg":
|
||||
case "jpg":
|
||||
contentType = "image/jpeg";
|
||||
break;
|
||||
case "js":
|
||||
contentType = "application/x-javascript";
|
||||
break;
|
||||
case "atom":
|
||||
contentType = "application/atom+xml";
|
||||
break;
|
||||
case "rss":
|
||||
contentType = "application/rss+xml";
|
||||
break;
|
||||
case "mml":
|
||||
contentType = "text/mathml";
|
||||
break;
|
||||
case "txt":
|
||||
contentType = "text/plain";
|
||||
break;
|
||||
case "jad":
|
||||
contentType = "text/vnd.sun.j2me.app-descriptor";
|
||||
break;
|
||||
case "wml":
|
||||
contentType = "text/vnd.wap.wml";
|
||||
break;
|
||||
case "htc":
|
||||
contentType = "text/x-component";
|
||||
break;
|
||||
case "png":
|
||||
contentType = "image/png";
|
||||
break;
|
||||
case "tif":
|
||||
case "tiff":
|
||||
contentType = "image/tiff";
|
||||
break;
|
||||
case "wbmp":
|
||||
contentType = "image/vnd.wap.wbmp";
|
||||
break;
|
||||
case "ico":
|
||||
contentType = "image/x-icon";
|
||||
break;
|
||||
case "jng":
|
||||
contentType = "image/x-jng";
|
||||
break;
|
||||
case "bmp":
|
||||
contentType = "image/x-ms-bmp";
|
||||
break;
|
||||
case "svg":
|
||||
contentType = "image/svg+xml";
|
||||
break;
|
||||
case "jar":
|
||||
case "var":
|
||||
case "ear":
|
||||
contentType = "application/java-archive";
|
||||
break;
|
||||
case "doc":
|
||||
contentType = "application/msword";
|
||||
break;
|
||||
case "pdf":
|
||||
contentType = "application/pdf";
|
||||
break;
|
||||
case "rtf":
|
||||
contentType = "application/rtf";
|
||||
break;
|
||||
case "xls":
|
||||
contentType = "application/vnd.ms-excel";
|
||||
break;
|
||||
case "ppt":
|
||||
contentType = "application/vnd.ms-powerpoint";
|
||||
break;
|
||||
case "7z":
|
||||
contentType = "application/x-7z-compressed";
|
||||
break;
|
||||
case "rar":
|
||||
contentType = "application/x-rar-compressed";
|
||||
break;
|
||||
case "swf":
|
||||
contentType = "application/x-shockwave-flash";
|
||||
break;
|
||||
case "rpm":
|
||||
contentType = "application/x-redhat-package-manager";
|
||||
break;
|
||||
case "der":
|
||||
case "pem":
|
||||
case "crt":
|
||||
contentType = "application/x-x509-ca-cert";
|
||||
break;
|
||||
case "xhtml":
|
||||
contentType = "application/xhtml+xml";
|
||||
break;
|
||||
case "zip":
|
||||
contentType = "application/zip";
|
||||
break;
|
||||
case "mid":
|
||||
case "midi":
|
||||
case "kar":
|
||||
contentType = "audio/midi";
|
||||
break;
|
||||
case "mp3":
|
||||
contentType = "audio/mpeg";
|
||||
break;
|
||||
case "ogg":
|
||||
contentType = "audio/ogg";
|
||||
break;
|
||||
case "m4a":
|
||||
contentType = "audio/x-m4a";
|
||||
break;
|
||||
case "ra":
|
||||
contentType = "audio/x-realaudio";
|
||||
break;
|
||||
case "3gpp":
|
||||
case "3gp":
|
||||
contentType = "video/3gpp";
|
||||
break;
|
||||
case "mp4":
|
||||
contentType = "video/mp4";
|
||||
break;
|
||||
case "mpeg":
|
||||
case "mpg":
|
||||
contentType = "video/mpeg";
|
||||
break;
|
||||
case "mov":
|
||||
contentType = "video/quicktime";
|
||||
break;
|
||||
case "flv":
|
||||
contentType = "video/x-flv";
|
||||
break;
|
||||
case "m4v":
|
||||
contentType = "video/x-m4v";
|
||||
break;
|
||||
case "mng":
|
||||
contentType = "video/x-mng";
|
||||
break;
|
||||
case "asx":
|
||||
case "asf":
|
||||
contentType = "video/x-ms-asf";
|
||||
break;
|
||||
case "wmv":
|
||||
contentType = "video/x-ms-wmv";
|
||||
break;
|
||||
case "avi":
|
||||
contentType = "video/x-msvideo";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
import org.primeframework.jwt.Signer;
|
||||
import org.primeframework.jwt.domain.JWT;
|
||||
import org.primeframework.jwt.hmac.HMACSigner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.tools
|
||||
*
|
||||
* @CreateTime: 2023-07-30 18:39
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class JWTUtil {
|
||||
|
||||
public static String createToken(Map<String,Object> map,String secret){
|
||||
try {
|
||||
Signer signer = HMACSigner.newSHA256Signer(secret);
|
||||
JWT jwt = new JWT();
|
||||
for (String key : map.keySet()) {
|
||||
jwt.addClaim(key, map.get(key));
|
||||
}
|
||||
return JWT.getEncoder().encode(jwt, signer);
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.oo.onlyoffice.dto.Plugins;
|
||||
import com.oo.onlyoffice.dto.document.DocumentPermission;
|
||||
import com.oo.onlyoffice.dto.edit.FileCustomization;
|
||||
import com.oo.onlyoffice.dto.edit.FileEmbedded;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @BelongsProject: onlyoffice-demo
|
||||
* @BelongsPackage: com.oo.onlyoffice.tools
|
||||
*
|
||||
* @CreateTime: 2023-07-30 18:30
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class LoadConfigUtil {
|
||||
private static JSONObject map = new JSONObject();
|
||||
private static DocumentPermission viewPermission = new DocumentPermission();
|
||||
private static DocumentPermission editPermission = new DocumentPermission();
|
||||
private static FileCustomization customization = new FileCustomization();
|
||||
private static FileEmbedded embedded = new FileEmbedded();
|
||||
private static Plugins plugins = new Plugins();
|
||||
|
||||
private static String YML_NAME = "onlyOffice.yml";
|
||||
|
||||
static {
|
||||
loadYml();
|
||||
}
|
||||
|
||||
private static void loadYml(){
|
||||
log.info("--------加载【onlyOffice.yml】配置文件-------");
|
||||
InputStream inputStream = LoadConfigUtil.class.getClassLoader().getResourceAsStream(YML_NAME);
|
||||
//解析配置文件
|
||||
map = new Yaml().loadAs(inputStream, JSONObject.class);
|
||||
JSONObject oo = map.getJSONObject("oo");
|
||||
JSONObject document = oo.getJSONObject("document");
|
||||
if (null != document || null != document.getJSONObject("permissions")){
|
||||
JSONObject permissions = document.getJSONObject("permissions");
|
||||
if (null != permissions.getJSONObject("edit")){
|
||||
editPermission = JSONUtil.toBean(permissions.getJSONObject("edit").toString(),DocumentPermission.class);
|
||||
editPermission.setEdit(true);
|
||||
}
|
||||
if (null != permissions.getJSONObject("view")){
|
||||
viewPermission = JSONUtil.toBean(permissions.getJSONObject("view").toString(),DocumentPermission.class);
|
||||
viewPermission.setEdit(false);
|
||||
}
|
||||
}
|
||||
JSONObject editor = oo.getJSONObject("editor");
|
||||
if (null != editor){
|
||||
customization = JSONUtil.toBean(editor.getJSONObject("customization").toString(),FileCustomization.class);
|
||||
}
|
||||
|
||||
JSONObject embeddedJson = editor.getJSONObject("embedded");
|
||||
if (null != embeddedJson){
|
||||
embedded = JSONUtil.toBean(embeddedJson.toString(),FileEmbedded.class);
|
||||
}
|
||||
|
||||
JSONObject pluginsJson = editor.getJSONObject("plugins");
|
||||
if (null != pluginsJson){
|
||||
plugins = JSONUtil.toBean(pluginsJson.toString(),Plugins.class);
|
||||
}
|
||||
log.info("--------【onlyOffice.yml】配置文件加载完成-------");
|
||||
}
|
||||
|
||||
public static DocumentPermission getEditPermission() {
|
||||
return editPermission;
|
||||
}
|
||||
|
||||
public static DocumentPermission getViewPermission() {
|
||||
return viewPermission;
|
||||
}
|
||||
|
||||
public static FileCustomization getCustomization() {
|
||||
return customization;
|
||||
}
|
||||
|
||||
public static FileEmbedded getEmbedded() {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
public static Plugins getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
public static JSONObject getConvert(){
|
||||
JSONObject oo = map.getJSONObject("oo");
|
||||
JSONObject convert = oo.getJSONObject("convert");
|
||||
return convert;
|
||||
}
|
||||
|
||||
public static JSONObject getMap(){
|
||||
return map.getJSONObject("oo");
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
JSONObject convert = LoadConfigUtil.getConvert();
|
||||
System.out.println(convert.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
|
||||
import com.oo.onlyoffice.core.enums.DocumentTypeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class OnlyOfficeUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 通过文件名获取文件类型
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 结果
|
||||
*/
|
||||
public static String getDocumentType(String fileName) {
|
||||
// 获取文件的扩展名
|
||||
String ext = "." + FileUtil.getFileExtension(fileName);
|
||||
if (ExtsDocument.contains(ext)) {
|
||||
return DocumentTypeEnum.Word.toString().toLowerCase();
|
||||
} else if (ExtsSpreadsheet.contains(ext)) {
|
||||
return DocumentTypeEnum.Cell.toString().toLowerCase();
|
||||
} else if (ExtsPresentation.contains(ext)) {
|
||||
return DocumentTypeEnum.Slide.toString().toLowerCase();
|
||||
}
|
||||
return DocumentTypeEnum.Word.toString().toLowerCase();
|
||||
}
|
||||
|
||||
private static List<String> ExtsDocument = Arrays.asList(
|
||||
".doc", ".docx", ".docm",
|
||||
".dot", ".dotx", ".dotm",
|
||||
".odt", ".fodt", ".ott", ".rtf", ".txt",
|
||||
".html", ".htm", ".mht",
|
||||
".pdf", ".djvu", ".fb2", ".epub", ".xps");
|
||||
|
||||
private static List<String> ExtsSpreadsheet = Arrays.asList(
|
||||
".xls", ".xlsx", ".xlsm",
|
||||
".xlt", ".xltx", ".xltm",
|
||||
".ods", ".fods", ".ots", ".csv");
|
||||
|
||||
private static List<String> ExtsPresentation = Arrays.asList(
|
||||
".pps", ".ppsx", ".ppsm",
|
||||
".ppt", ".pptx", ".pptm",
|
||||
".pot", ".potx", ".potm",
|
||||
".odp", ".fodp", ".otp");
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.oo.onlyoffice.tools;
|
||||
|
||||
import com.oo.onlyoffice.dto.edit.FileUser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @BelongsProject: jeecg-boot-parent
|
||||
* @BelongsPackage: com.waysoft.tools
|
||||
*
|
||||
* @CreateTime: 2023-02-06 09:12
|
||||
* @Description: 存储当前登录的用户信息
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class SecurityUtils implements Serializable {
|
||||
|
||||
private static ThreadLocal<Object> loginEntityThreadLocal=new ThreadLocal<>();
|
||||
/**
|
||||
* 获取当前线程绑定的用户登录对象
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static FileUser getUserSession() {
|
||||
log.info(Thread.currentThread().getName()+"获取登录用户信息");
|
||||
return (FileUser)loginEntityThreadLocal.get();
|
||||
}
|
||||
|
||||
|
||||
public static Object getObjectSession() {
|
||||
return loginEntityThreadLocal.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将用户登录对象绑定到当前线程
|
||||
*
|
||||
* @param loginEntity
|
||||
*/
|
||||
public static void setUserSession(Object loginEntity) {
|
||||
log.info(Thread.currentThread().getName()+"存入登录用户信息");
|
||||
loginEntityThreadLocal.set(loginEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将用户登录对象从当前线程销毁
|
||||
*/
|
||||
public static void removeUserSession() {
|
||||
log.info(Thread.currentThread().getName()+"清除用户信息");
|
||||
loginEntityThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.oo.onlyoffice.vo;
|
||||
|
||||
import com.oo.onlyoffice.dto.DocumentConfig;
|
||||
import com.oo.onlyoffice.dto.EditorConfig;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* only office 配置信息
|
||||
* 以下参数必须填写
|
||||
* 1、docServiceApiUrl
|
||||
* 2、fileType
|
||||
* 3、key
|
||||
* 4、title
|
||||
* 5、url
|
||||
* 6、callbackUrl
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
public class FileConfig implements Serializable {
|
||||
/**
|
||||
* 类型 embedded/desktop
|
||||
* 默认为desktop
|
||||
*/
|
||||
private String type = "desktop";
|
||||
|
||||
|
||||
/**
|
||||
* 文档类型 word/cell/slide
|
||||
* open a word document (.doc, .docm, .docx, .dot, .dotm, .dotx, .epub, .fodt, .htm, .html, .mht, .odt, .ott, .pdf, .rtf, .txt, .djvu, .xps)
|
||||
* open a cell (.csv, .fods, .ods, .ots, .xls, .xlsm, .xlsx, .xlt, .xltm, .xltx)
|
||||
* open a slide (.fodp, .odp, .otp, .pot, .potm, .potx, .pps, .ppsm, .ppsx, .ppt, .pptm, .pptx)
|
||||
*
|
||||
*/
|
||||
private String documentType;
|
||||
|
||||
/**
|
||||
* 自定义签名
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 文档配置信息
|
||||
*/
|
||||
private DocumentConfig document;
|
||||
|
||||
/**
|
||||
* 编辑配置
|
||||
*/
|
||||
private EditorConfig editorConfig;
|
||||
|
||||
/**
|
||||
* 访问api 路径
|
||||
*/
|
||||
private String docServiceApiUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
server:
|
||||
port: 9090
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 1024MB
|
||||
thymeleaf:
|
||||
cache: false
|
||||
prefix: classpath:/templates/
|
||||
suffix: .html
|
||||
encoding: UTF-8
|
||||
content-type: text/html
|
||||
mode: HTML5
|
||||
#配置静态资源
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
resource:
|
||||
static-locations: classpath:/static/
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://121.40.189.20:3306/onlyoffice_test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
username: root
|
||||
password: YMzc157#
|
||||
redis:
|
||||
host: 121.40.189.20
|
||||
port: 6389
|
||||
database: 1
|
||||
|
||||
mybatis-plus:
|
||||
# global-config:
|
||||
# db-config:
|
||||
# table-prefix: t_
|
||||
mapper-locations: classpath:mappers/*.xml
|
||||
|
||||
logging:
|
||||
level:
|
||||
com: debug
|
||||
---
|
||||
#开发环境属性配置
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://121.40.189.20:3306/onlyoffice_test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
username: root
|
||||
password: YMzc157#
|
||||
filepath: /home/ruoyi/uploadPath/onlyoffice/data/files
|
||||
serverhost: http://121.40.189.20
|
||||
---
|
||||
#生产环境属性配置
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
redis:
|
||||
host: 121.40.189.20
|
||||
port: 6389
|
||||
database: 0
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://121.40.189.20:3306/onlyoffice?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
username: root
|
||||
password: YMzc157#
|
||||
filepath: /home/ruoyi/uploadPath/onlyoffice/data/files
|
||||
serverhost: http://121.40.189.20
|
||||
@@ -0,0 +1,15 @@
|
||||
DROP TABLE IF EXISTS `on_file`;
|
||||
CREATE TABLE `on_file` (
|
||||
`file_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
|
||||
`version` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本',
|
||||
`created_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '时间',
|
||||
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户',
|
||||
`user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户id',
|
||||
`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件名称',
|
||||
`file_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件类型',
|
||||
`file_size` bigint NULL DEFAULT NULL COMMENT '文件大小',
|
||||
`file_path` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件路径',
|
||||
PRIMARY KEY (`file_id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@@ -0,0 +1,125 @@
|
||||
oo:
|
||||
secret: #yunmeionlyofficeOK #onlyoffice服务 开启了jwt校验 填写
|
||||
timeout: 300000
|
||||
doc-service: http://121.40.189.20:8899 #onlyoffice服务的地址
|
||||
call-back-url: /onlyOffice/save # oo回调
|
||||
#正式系统地址
|
||||
download-file: :9090/download/ #http://ip:prot(域名)/xxxx/download/{id},{id}在程序中动态拼接上的
|
||||
localhost-address: :9090 #本应用的地址
|
||||
#测试系统地址
|
||||
# download-file: http://172.16.0.254:9090/download/ #http://ip:prot(域名)/xxxx/download/{id},{id}在程序中动态拼接上的
|
||||
# localhost-address: http://172.16.0.254:9090 #本应用的地址
|
||||
hist-num: #历史文件数量超出 则进行删除 有需要则填写
|
||||
max-size: #单位 MB 限制单个文件打开时的大小 默认20MB
|
||||
cache: #不写默认使用内部缓存 可填redis
|
||||
# ===========================================以下配置不是必须有的=====================================================
|
||||
document:
|
||||
permissions: #https://api.onlyoffice.com/editors/config/document/permissions 在查看和编辑时可以定义不同的功能
|
||||
edit:
|
||||
chat: false #定义是否在文档中启用聊天功能。 如果聊天权限设置为true,将显示聊天菜单按钮。 默认值为true。
|
||||
comment: #定义文档是否可以被注释。默认为true
|
||||
copy: #定义是否可以将内容复制到剪贴板。
|
||||
deleteCommentAuthorOnly: #定义用户是否只能删除其注释。 默认值为false。
|
||||
download: #是否允许下载 默认为true
|
||||
editCommentAuthorOnly: #定义用户是否只能编辑其注释。 默认值为false。
|
||||
fillForms: #是否可以填写表单 默认true
|
||||
modifyContentControl: # 定义是否可以更改内容控件设置。 仅当mode参数设置为编辑时,内容控件修改才可用于文档编辑器。 默认值为true。
|
||||
modifyFilter: #定义筛选器是可以全局应用(true)影响所有其他用户,还是本地应用(false),即仅适用于当前用户。默认值为true。
|
||||
print: #定义文档是否可以打印。 如果打印权限设置为“false”打印菜单选项将不在“文件”菜单中。 默认值为true。
|
||||
protect: #定义是显示工具栏上的“保护”选项卡和左侧菜单中的“保护”按钮(真)还是隐藏(假)。 默认值为true。
|
||||
review: false #定义文档是否可以被审核。默认:true
|
||||
view:
|
||||
chat: false #定义是否在文档中启用聊天功能。 如果聊天权限设置为true,将显示聊天菜单按钮。 默认值为true。
|
||||
comment: #定义文档是否可以被注释。默认为true
|
||||
copy: #定义是否可以将内容复制到剪贴板。
|
||||
deleteCommentAuthorOnly: #定义用户是否只能删除其注释。 默认值为false。
|
||||
download: #是否允许下载 默认为true
|
||||
editCommentAuthorOnly: #定义用户是否只能编辑其注释。 默认值为false。
|
||||
fillForms: #是否可以填写表单 默认true
|
||||
modifyContentControl: # 定义是否可以更改内容控件设置。 仅当mode参数设置为编辑时,内容控件修改才可用于文档编辑器。 默认值为true。
|
||||
modifyFilter: #定义筛选器是可以全局应用(true)影响所有其他用户,还是本地应用(false),即仅适用于当前用户。默认值为true。
|
||||
print: #定义文档是否可以打印。 如果打印权限设置为“false”打印菜单选项将不在“文件”菜单中。 默认值为true。
|
||||
protect: #定义是显示工具栏上的“保护”选项卡和左侧菜单中的“保护”按钮(真)还是隐藏(假)。 默认值为true。
|
||||
review: false #定义文档是否可以被审核。默认:true
|
||||
editor:
|
||||
customization: #https://api.onlyoffice.com/editors/config/editor/customization
|
||||
anonymous: #添加对匿名名称的请求
|
||||
request: false #定义请求是否发送。 默认值为 true
|
||||
label: #添加到用户名的后缀。默认值为 Guest
|
||||
goback: #定义“打开文件位置”菜单按钮和右上角按钮的设置。
|
||||
blank: false #在新的浏览器选项卡/窗口中打开网站(如果值设置为true)或当前选项卡(如果值设置为false) 默认值为 true
|
||||
requestClose: #定义如果单击“打开文件位置”按钮,则会调用 events.onRequestClose事件,而不是打开浏览器选项卡或窗口。默认值 false
|
||||
text: #提示信息 默认 转到文档
|
||||
url: #单击“打开文件位置”菜单按钮时将打开的网站地址的绝对URL
|
||||
logo: #onlyoffice付费用户生效
|
||||
image: #图像文件的路径
|
||||
imageDark: #深色主题的图像文件的路径
|
||||
url: #点击徽标图像时将使用的绝对URL
|
||||
review:
|
||||
hideReviewDisplay: #定义在“协作”选项卡上显示还是隐藏“显示模式”按钮。 默认值为false
|
||||
hoverMode: #定义审阅显示模式:通过悬停更改在工具提示中显示审阅 (true) 或通过单击更改(假)在气球中。 默认值为false。
|
||||
feedback: #定义“反馈和支持”菜单按钮的设置。默认值为 true
|
||||
visible: false
|
||||
url:
|
||||
autosave: false #定义是否启用或禁用“自动保存”菜单选项。默认值为true 如果设置为false,则只能选择Strict协同编辑模式,因为Fast在没有自动保存的情况下无法工作。默认值为true
|
||||
forcesave: true #在文档编辑服务中保存文档时(例如,单击“保存”按钮等), 将文件强制保存的请求添加到回调处理程序中。 默认值为false
|
||||
comments: false #定义是显示还是隐藏“注释”菜单按钮。如果您隐藏了“评论”按钮,则相应的评论功能将仅供查看,添加和编辑评论将不可用。 默认值为true。
|
||||
compactHeader: # 定义其他操作按钮是显示在编辑器窗口标题的上部徽标旁边 (false) 还是显示在工具栏 (true) 中,从而使标题更紧凑。 默认值为false。
|
||||
compactToolbar: # 定义显示的顶部工具栏类型是完整 (假) 还是紧凑 (真)。 默认值为false。
|
||||
compatibleFeatures: #定义仅与 OOXML 格式兼容的功能的使用。 例如,不要对整个文档使用注释。 默认值为false。
|
||||
features: #拼写检查 - 定义在加载编辑器时是自动打开还是关闭拼写检查器。 如果此参数是布尔值,则将其设置为初始拼写检查器值,并且不会隐藏拼写检查器设置。默认值为 true
|
||||
help: false #定义是显示还是隐藏“帮助”菜单按钮。 默认值为true。
|
||||
hideNotes: true #定义在首次加载时是显示还是隐藏注释面板。 默认值为false
|
||||
hideRightMenu: true #定义首次加载时是显示还是隐藏右侧菜单。 默认值为false。
|
||||
hideRulers: # 定义是显示还是隐藏编辑器标尺。 此参数可用于文档和演示文稿编辑器。文档编辑器的默认值为false,演示文稿的默认值为true。
|
||||
macros: false #定义在编辑器打开时是否自动运行文档宏。 默认值为true。false值对用户隐藏宏设置。
|
||||
macrosMode: #宏提示 warn 默认 警告宏并请求运行它们的权限 / enable 自动运行所有宏/ disable不运行宏
|
||||
mentionShare: #定义在注释中提及后描述事件的提示。true,则提示指示用户将收到通知并访问文档。 false,则提示指示用户将仅收到提及通知。 默认值为true。只有在设置了onRequestSendNotify事件的情况下,它才可用于注释。
|
||||
plugins: #定义插件是否启动并可用。 默认值为true。
|
||||
toolbarHideFileName: #定义文档标题是在顶部工具栏上可见 (假) 还是隐藏 (真)。 默认值为false。
|
||||
toolbarNoTabs: #定义顶部工具栏选项卡是清晰显示 (false) 还是仅突出显示以查看选择了哪个选项卡 (true)。 默认值为false。
|
||||
uiTheme: #定义编辑器主题设置。 theme-light, theme-classic-light, theme-dark, theme-contrast-dark 默认 theme-dark
|
||||
unit: #定义标尺和对话框中使用的度量单位。 可以采用以下值:cm - 厘米 /pt - 像素点/inch - 英寸. 默认值为厘米 (cm)。
|
||||
zoom: # 定义以百分比度量的文档显示缩放值。 可以采用大于0 的值。默认值为100。对于文本文档和演示文稿,可以将此参数设置为 -1(使文档适合页面选项)或 to-2(使文档页面宽度适合编辑器页面)。
|
||||
plugins: #https://api.onlyoffice.com/editors/config/editor/plugins 插件配置
|
||||
autostart: #数组 asc.{FFE1F462-1EA2-4391-990D-4CC84940B754}
|
||||
-
|
||||
pluginsData: #数组
|
||||
-
|
||||
|
||||
convert: #https://api.onlyoffice.com/editors/conversionapi
|
||||
async: #定义转换请求类型:异步或非异步。默认值为false。
|
||||
codePage: #定义从csv或txt格式转换时的文件编码。
|
||||
delimiter: #定义从csv格式转换时用于分隔值的分隔符。
|
||||
region: #地区 oo默认值为en-US 项目中默认值zh-CN
|
||||
documentLayout:
|
||||
enabled: false
|
||||
drawPlaceHolders:
|
||||
drawFormHighlight:
|
||||
isPrint:
|
||||
documentRenderer:
|
||||
enabled: false
|
||||
textAssociation:
|
||||
spreadsheetLayout:
|
||||
enabled: false
|
||||
fitToHeight: #设置转换区域的高度(以页数为单位)。 默认值为0。
|
||||
fitToWidth: #设置转换区域的宽度(以页数为单位)。 默认值为0
|
||||
gridLines: #允许是否在输出PDF文件中包含网格线。 默认值为false。
|
||||
headings: #允许是否包含输出PDF文件的标题。 默认值为false。
|
||||
ignorePrintArea: #确定是否忽略为电子表格文件选择的打印区域。 默认值为true。
|
||||
orientation: #设置输出 PDF 文件的方向。 可能是landscape, portrait. 默认值为纵向(portrait)
|
||||
scale:
|
||||
margins: #设置输出 PDF 文件的边距 默认 19.1mm 默认 17.8mm 默认 17.8mm 默认 19.1mm
|
||||
bottom:
|
||||
left:
|
||||
right:
|
||||
top:
|
||||
pageSize: #设置输出 PDF 文件的页面高度。默认 297mm 页面宽度。默认 210mm
|
||||
height:
|
||||
width:
|
||||
thumbnail: # 缩略图 定义将图像格式(bmp,gif,jpg,png)指定为输出类型时缩略图的设置。
|
||||
enabled: false
|
||||
aspect: #默认值为2。
|
||||
first: #默认值为true,
|
||||
height: #缩略图高度(以像素为单位)。 默认值为100。
|
||||
width: #缩略图宽度(以像素为单位)。 默认值为100。
|
||||
@@ -0,0 +1,160 @@
|
||||
|
||||
|
||||
|
||||
function onprint(){
|
||||
layer.msg('正在加载中...<i class="layui-icon layui-icon-loading"></i>',{time: 100000});
|
||||
onPrintUrl('/print/'+id)
|
||||
}
|
||||
function dow(){
|
||||
download(id)
|
||||
}
|
||||
|
||||
function onPrintUrl(t) {
|
||||
if (this.iframePrint && (this.iframePrint.parentNode.removeChild(this.iframePrint),
|
||||
this.iframePrint = null),
|
||||
!this.iframePrint) {
|
||||
var e = this;
|
||||
this.iframePrint = document.createElement("iframe"),
|
||||
this.iframePrint.id = "id-print-frame",
|
||||
this.iframePrint.style.display = "none",
|
||||
this.iframePrint.style.visibility = "hidden",
|
||||
this.iframePrint.style.position = "fixed",
|
||||
this.iframePrint.style.right = "0",
|
||||
this.iframePrint.style.bottom = "0",
|
||||
document.body.appendChild(this.iframePrint),
|
||||
this.iframePrint.onload = function() {
|
||||
try {
|
||||
layer.closeAll();
|
||||
e.iframePrint.contentWindow.focus(),
|
||||
e.iframePrint.contentWindow.print(),
|
||||
e.iframePrint.contentWindow.blur(),
|
||||
window.focus()
|
||||
} catch (t) {
|
||||
console.log("打印出错")
|
||||
}
|
||||
}
|
||||
}
|
||||
t && (this.iframePrint.src = t)
|
||||
}
|
||||
|
||||
|
||||
const innerAlert = function (message) {
|
||||
if (console && console.log){
|
||||
console.log(message);
|
||||
// docEditor.showMessage("文件加载完成....");
|
||||
}
|
||||
};
|
||||
const onReady = function () {
|
||||
innerAlert("文件加载完成....");
|
||||
};
|
||||
/**
|
||||
* 文档改变后的回调 onDocumentStateChange:{"target":{"frameOrigin":"http://192.168.31.201:9001"},"data":true}
|
||||
* @param event
|
||||
*/
|
||||
const onDocumentStateChange = function (event) {
|
||||
console.log("onDocumentStateChange:"+JSON.stringify(event));
|
||||
const title = document.title.replace(/\*$/g, "");
|
||||
console.log("onDocumentStateChange:"+JSON.stringify(title));
|
||||
document.title = title + (event.data ? "*" : "");
|
||||
};
|
||||
/**
|
||||
* 用户正在尝试通过单击“编辑文档”按钮将文档从查看模式切换到编辑模式。
|
||||
*/
|
||||
const onRequestEditRights = function () {
|
||||
location.href = location.href.replace(RegExp("action=view\&?", "i"), "");
|
||||
};
|
||||
|
||||
/**
|
||||
* 发生错误或其他一些特定事件。
|
||||
* @param event
|
||||
*/
|
||||
const onError = function (event) {
|
||||
if (event) innerAlert(event.data);
|
||||
};
|
||||
/**
|
||||
* 显示错误后调用的函数,当使用旧文档打开文档进行编辑时.key值,该值用于编辑以前的文档版本并已成功保存。
|
||||
* 调用此事件时,必须使用新文档重新初始化编辑器.key。
|
||||
* @param event
|
||||
*/
|
||||
const onOutdatedVersion = function (event) {
|
||||
location.reload(true);
|
||||
};
|
||||
/**
|
||||
* 当用户尝试通过单击“版本历史记录”按钮显示文档版本历史记录时调用的函数。
|
||||
* 若要显示文档版本历史记录,必须调用refreshHistory方法。
|
||||
* 如果未声明该方法和onRequestHistoryData方法,则不会显示“版本历史记录”按钮。
|
||||
*/
|
||||
const onRequestHistory = function (){
|
||||
docEditor.refreshHistory();
|
||||
}
|
||||
/**
|
||||
* 当用户尝试通过单击“关闭历史记录”按钮从查看文档版本历史记录返回到文档时调用的函数。
|
||||
* 调用函数时,必须在编辑模式下再次初始化编辑器。
|
||||
* 如果未声明该方法,则不会显示“关闭历史记录”按钮。
|
||||
*/
|
||||
const onRequestHistoryClose = function () {
|
||||
document.location.reload();
|
||||
};
|
||||
/**
|
||||
* 当用户尝试单击文档版本历史记录中的特定文档版本时调用的函数。
|
||||
* 若要显示与特定文档版本对应的更改,必须调用setHistoryData方法。
|
||||
* 文档版本号在数据参数中发送。 如果未声明该方法和onRequestHistory方法,则不会显示“版本历史记录”按钮。
|
||||
*/
|
||||
const onRequestHistoryData = function (event) {
|
||||
var version = event.data;
|
||||
docEditor.setHistoryData()
|
||||
};
|
||||
/**
|
||||
* 当用户尝试通过单击“存储中的图像”按钮插入图像时调用的函数。 图像插入的类型在参数data.c 中指定。
|
||||
* 若要将图像插入到文件中,必须使用指定的命令调用insertImage方法。 如果未声明该方法,则不会显示“存储中的图像”按钮。
|
||||
* add, change, fill, watermark, slide.
|
||||
*/
|
||||
const onRequestInsertImage = function (event) {
|
||||
docEditor.insertImage({
|
||||
"c": "watermark",
|
||||
"images": [
|
||||
{
|
||||
"fileType": "jpg",
|
||||
"url": "http://192.168.49.1:8080/images/logo.jpg"
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 当用户尝试通过单击“将副本另存为”来保存文件时调用的函数...按钮。
|
||||
* 文档的标题、类型和要下载的文档的绝对 URL 在data参数中发送。
|
||||
* 如果未将该方法声明为“将副本另存为...按钮将不会显示。
|
||||
* @param event
|
||||
*/
|
||||
const onRequestSaveAs = function (event) {
|
||||
var title = event.data.title;
|
||||
var url = event.data.url;
|
||||
var data = {
|
||||
title: title,
|
||||
url: url
|
||||
};
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "IndexServlet?type=saveas");
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify(data));
|
||||
xhr.onload = function () {
|
||||
innerAlert(xhr.responseText);
|
||||
innerAlert(JSON.parse(xhr.responseText).file, true);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 通过meta命令更改文档的元信息时调用的函数。
|
||||
* 文档的名称在data.title参数中发送。
|
||||
* 收藏夹图标突出显示状态在data.favorite参数中发送。
|
||||
* 当用户单击收藏夹图标时,将调用setFavorite方法来更新有关收藏夹图标突出显示状态的信息。 如果未声明该方法,则不会更改“收藏夹”图标。
|
||||
* @param event
|
||||
*/
|
||||
const onMetaChange = function (event) {
|
||||
if (event.data.favorite) {
|
||||
var favorite = !!event.data.favorite;
|
||||
var title = document.title.replace(/^\☆/g, "");
|
||||
document.title = (favorite ? "☆" : "") + title;
|
||||
docEditor.setFavorite(favorite); // change the Favorite icon state
|
||||
}
|
||||
innerAlert("onMetaChange: " + JSON.stringify(event.data));
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
function ajax(url,data,type){
|
||||
return new Promise(function(resolve, reject) {
|
||||
$.ajax({
|
||||
type: type,
|
||||
url: url,
|
||||
data: data,
|
||||
synch:true,
|
||||
dataType:'json',
|
||||
success:function(res){
|
||||
resolve(res)
|
||||
},
|
||||
error: function(res) {
|
||||
console.log(res)
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function download(href){
|
||||
var a = document.createElement('a');
|
||||
a.setAttribute('href', href);
|
||||
a.setAttribute('id', 'startTelMedicine');
|
||||
|
||||
// 防止反复添加
|
||||
if (document.getElementById('startTelMedicine')) {
|
||||
document.body.removeChild(document.getElementById('startTelMedicine'));
|
||||
}
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
|
||||
var fileTable;
|
||||
var element;
|
||||
var laydate;
|
||||
var upload;
|
||||
var layer;
|
||||
var table;
|
||||
var form;
|
||||
|
||||
let pdf = ['doc','docx','xls','xlsx','ppt','pptx','txt'];
|
||||
|
||||
layui.use(['element', 'layer', 'util', 'carousel', 'form', 'table', 'upload', 'laydate'], function () {
|
||||
laydate = layui.laydate;
|
||||
element = layui.element;
|
||||
upload = layui.upload;
|
||||
layer = layui.layer;
|
||||
table = layui.table;
|
||||
form = layui.form;
|
||||
|
||||
|
||||
fileTable = table.render({
|
||||
elem: '#fileTable'
|
||||
, url: '/file/all'
|
||||
, toolbar: '#toolFile' //开启头部工具栏,并为其绑定左侧模板
|
||||
, defaultToolbar: []
|
||||
, height: 'full-170'
|
||||
, title: '文件列表'
|
||||
, cols: [[
|
||||
{title: '编号', type: 'numbers', align: 'center',width:50}
|
||||
, {field: 'fileName', title: '文件名称', align: 'center'}
|
||||
, {field: 'fileType', title: '文件类型', align: 'center'}
|
||||
, {field: 'fileSize', title: '大小', align: 'center'}
|
||||
, {field: 'version', title: '版本', align: 'center'}
|
||||
, {fixed: 'right', title: '操作', align: 'center',templet:function (row){
|
||||
var html ='';
|
||||
var className = 'layui-bg-orange'
|
||||
if (!pdf.includes(row.fileType)) {
|
||||
className = 'layui-btn-disabled'
|
||||
}
|
||||
|
||||
html +=' <button class="layui-btn layui-btn-sm '+className+'" lay-event="converted">PDF</button>' +
|
||||
' <button class="layui-btn layui-bg-blue layui-btn-sm" lay-event="edit">编辑</button>' +
|
||||
' <button class="layui-btn layui-bg-blue layui-btn-sm" lay-event="view">查看</button>' +
|
||||
' <button class="layui-btn layui-btn-sm" lay-event="download">下载</button>' +
|
||||
' <button class="layui-btn layui-btn-danger layui-btn-sm" lay-event="del" >删除</button>';
|
||||
return html;
|
||||
}}
|
||||
]],
|
||||
skin: 'line',
|
||||
size: 'lg',
|
||||
page: true,
|
||||
done: function () {
|
||||
$(".layui-table-header tr").css("background-color", "#b0b0b0");
|
||||
}
|
||||
});
|
||||
|
||||
//监听行工具事件
|
||||
table.on('tool(fileTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event == 'del') {
|
||||
layer.confirm('你确定要删除【' + data.fileName + '】这个文件吗?', {icon: 3, title: '提示'}, function (index) {
|
||||
ajax('/del', {id: data.fileId}, 'post').then(function (res) {
|
||||
layer.msg(res.message)
|
||||
table.reload("fileTable");
|
||||
})
|
||||
});
|
||||
} else if (obj.event == 'download') {
|
||||
download("/download/" + data.fileId+"?isBrowser=true")
|
||||
} else if(obj.event == 'converted'){
|
||||
download( `/converted?id=${data.fileId}&suffix=pdf`)
|
||||
} else if(obj.event == 'edit'){
|
||||
// window.open('/onlyOffice/edit/'+data.id);
|
||||
openDocument(data.fileId,'edit','在线编辑')
|
||||
}else if (obj.event == 'view'){
|
||||
openDocument(data.fileId,'view','在线查看')
|
||||
}
|
||||
});
|
||||
//清空表单
|
||||
$(".clean").on('click', function () {
|
||||
$("form")[0].reset();
|
||||
|
||||
$(".xm-select-parent .xm-select").attr("title", '')
|
||||
$("div[xm-select-skin=default] .xm-select-title div.xm-select-label>span").remove()
|
||||
$(".xm-select-parent .xm-select--suffix input").attr("placeholder", "请选择");
|
||||
$(".xm-select-parent .xm-form-select dl dd").removeClass("xm-select-this")
|
||||
|
||||
})
|
||||
|
||||
/**提交form表单*/
|
||||
form.on('submit(formDemo)', function (data) {
|
||||
var obj = data.field
|
||||
console.log(obj)
|
||||
ajax(data.form.action, obj, data.form.method).then(function (res) {
|
||||
layer.msg(res.msg, {time: 1000}, function () {
|
||||
layer.closeAll();
|
||||
table.reload(res.data);
|
||||
});
|
||||
})
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function openDocument(id,mode,txt){
|
||||
var index = layer.open({
|
||||
type: 2, // page 层类型
|
||||
offset: 'lb',
|
||||
area: ['150px', '50px'],
|
||||
title: txt,
|
||||
shade: 0, // 遮罩透明度
|
||||
shadeClose: true, // 点击遮罩区域,关闭弹层
|
||||
maxmin: true, // 允许全屏最小化
|
||||
anim: 0, // 0-6 的动画形式,-1 不开启
|
||||
content: `/onlyOffice/${mode}/${id}`,
|
||||
btn: ['保存(autosave/forcesave是默认值时生效)'],
|
||||
btnAlign: 'c',
|
||||
btn1: function(index, layero, that){
|
||||
ajax('/save',{id:id},"get").then(function (res) {
|
||||
layer.msg(res.message)
|
||||
})
|
||||
return false
|
||||
},
|
||||
|
||||
success: function(layero, index){
|
||||
layer.full(index); // 最大化
|
||||
},
|
||||
cancel: function(index, layero){
|
||||
// 获取 iframe 中 body 元素的 jQuery 对象
|
||||
console.log(index,layero)
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**格式化时间*/
|
||||
function dateFormatter(date) {
|
||||
//Object对象转为日期格式
|
||||
var date = new Date(date);
|
||||
var strDate = date.getFullYear() + "-";
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
//格式化日期,月日时分秒保持两位
|
||||
strDate = strDate + (month > 9 ? month : "0" + month) + "-"
|
||||
+ (day > 9 ? day : "0" + day) + " "
|
||||
return strDate;
|
||||
}
|
||||
|
||||
/**关闭弹窗*/
|
||||
function closeEditWin(){
|
||||
layui.use('layer',function(){
|
||||
var layer = layui.layer ;
|
||||
layer.closeAll();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 701 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 309 KiB |