Compare commits

...

43 Commits

Author SHA1 Message Date
asiawu 31c7b2dfb8 重构了EncodingDetectors#getJavaEncode(String filePath)方法,并附带部分测试数据
重构了EncodingDetectors#getJavaEncode(String filePath)方法,并附带部分测试数据
Co-authored-by: asiawu <asiawu3@qq.com>
Co-committed-by: asiawu <asiawu3@qq.com>
2023-07-24 17:15:07 +08:00
陈精华 d2a8ca2cdd
!186 新增xbrl格式
Merge pull request !186 from 高雄/xbrl
2023-07-24 03:30:59 +00:00
陈精华 16fca7ec61
!185 修复PDF解密加密文件 转换成功后台报错问题
Merge pull request !185 from 高雄/pdf2
2023-07-24 03:30:26 +00:00
陈精华 39d8d38ee9
!184 修复office转换加密文档 PDF不生成密码问题
Merge pull request !184 from 高雄/pdf
2023-07-24 03:30:09 +00:00
陈精华 99982f07f7
!183 调整 验证码 样式 为弹窗显示
Merge pull request !183 from 高雄/N/A
2023-07-24 03:29:33 +00:00
gaoxiongzaq 6382453327 新增xbrl格式 2023-07-24 09:47:04 +08:00
gaoxiongzaq 4ebee74f70 修复PDF解密加密文件 转换成功后台报错问题 2023-07-24 09:41:00 +08:00
gaoxiongzaq 54750f4e06 修复转换加密文档 PDF不生成密码问题 2023-07-24 09:39:20 +08:00
高雄 1225362c90
调整 验证码 样式 为弹窗显示
调整 验证码 样式 为弹窗显示

Signed-off-by: 高雄 <admin@cxcp.com>
2023-07-24 01:10:29 +00:00
陈精华 fe5ad49008
!175 验证码方法 代码优化
Merge pull request !175 from 高雄/code1
2023-07-22 06:35:37 +00:00
陈精华 586561ec5a
fix some typo 2023-07-22 14:33:02 +08:00
陈精华 cad2d58f44
CAD默认预览模式调整为svg 2023-07-22 14:31:22 +08:00
陈精华 4f86a56f59
!180 优化 CAD转换功能 新增CAD线程控制和CAD超时限制
Merge pull request !180 from 陈精华/cad
2023-07-22 06:26:13 +00:00
gaoxiongzaq c86ca0d8cf 优化 CAD转换功能 新增CAD线程控制和CAD超时限制 2023-07-22 14:22:31 +08:00
陈精华 ec633cc0e1
!179 验证码方法 代码优化
Merge pull request !179 from 陈精华/captcha
2023-07-22 06:14:33 +00:00
陈精华 fa2a2b4342
!178 office 功能调整 支持批注 转换页码限制 生成水印等等
Merge pull request !178 from 陈精华/office1
2023-07-22 06:14:24 +00:00
gaoxiongzaq 2b456c9934 验证码方法 代码优化
(cherry picked from commit da5dac73ab)
2023-07-22 14:01:56 +08:00
陈精华 7965d52f29 office 功能调整 支持批注 转换页码限制 生成水印等等 2023-07-22 13:42:29 +08:00
陈精华 ad322c2e10
!173 升级 CAD转换组件
Merge pull request !173 from 高雄/cad1
2023-07-22 04:27:36 +00:00
gaoxiongzaq da5dac73ab 验证码方法 代码优化 2023-07-22 08:53:50 +08:00
gaoxiongzaq b5e711bf87 office 功能调整 支持批注 转换页码限制 生成水印等等 2023-07-22 08:51:23 +08:00
gaoxiongzaq 535d2baf0b 升级 CAD转换组件 2023-07-22 08:45:21 +08:00
高雄 294dcb1994 !170 删除功能 新增验证码方法
删除功能 新增验证码方法
2023-07-21 09:52:27 +00:00
陈精华 c54a5e9f1a
!166 CAD格式新增支持 转换成svg tif 格式 CAD 转换新增 超时结束方法
Merge pull request !166 from 高雄/cad
2023-07-21 09:50:49 +00:00
陈精华 3571f2b502
!165 启用 GZIP压缩
Merge pull request !165 from 高雄/gzip
2023-07-21 09:50:05 +00:00
gaoxiongzaq 6f8416365f CAD格式新增支持 转换成svg tif 格式
CAD 转换新增 超时结束方法
2023-07-20 10:54:47 +08:00
gaoxiongzaq 778a381b5b 启用 GZIP压缩 2023-07-20 09:12:30 +08:00
gaoxiongzaq 770769ead5 启用 GZIP压缩 2023-07-20 09:06:50 +08:00
陈精华 8d49abb797
!163 更新说明文档
Merge pull request !163 from 高雄/master
2023-07-14 07:48:21 +00:00
高雄 d0568c53dc
更新说明文档
Merge pull request !1 from 陈精华/N/A
2023-07-13 06:30:06 +00:00
陈精华 276ef9d704
update README.cn.md.
Signed-off-by: 陈精华 <842761733@qq.com>
2023-07-12 07:16:58 +00:00
高雄 dd75f718aa
更新说明文档
更新说明文档

Signed-off-by: 高雄 <admin@cxcp.com>
2023-07-10 09:26:15 +00:00
陈精华 0ece6ccb51
!161 修复 forceUpdatedCache 属性设置,但是本地缓存文件不更新缺陷
Merge pull request !161 from lujiaming/N/A
2023-07-10 07:51:51 +00:00
lujiaming bbd7530f77
修复 forceUpdatedCache 属性设置,但是本地缓存文件不更新缺陷
Signed-off-by: lujiaming <1451771613@qq.com>
2023-07-10 07:43:23 +00:00
陈精华 2cfd692171
update officeweb.ftl 2023-07-10 13:59:56 +08:00
陈精华 77f794831f
!154 PdfFilePreviewImpl 中无效代码去除
Merge pull request !154 from lujiaming/N/A
2023-07-10 03:38:48 +00:00
陈精华 4ee8926d5f
!155 更新xlsx前端解析组件
Merge pull request !155 from 高雄/master
2023-07-10 03:35:54 +00:00
陈精华 a850e405ed
!156 ofd修复部分已知问题.
Merge pull request !156 from 高雄/ofd
2023-07-10 03:34:49 +00:00
陈精华 cac68f88df
!157 v4.4.0版本迭代开启
Merge pull request !157 from 高雄/xlsx
2023-07-10 03:34:12 +00:00
gaoxiongzaq 3734a66549 更新xlsx前端解析组件 2023-07-10 11:25:17 +08:00
gaoxiongzaq 2331545369 ofd修复部分已知问题. 2023-07-10 11:19:54 +08:00
gaoxiongzaq 0ff1f2c22b v4.4.0-SNAPSHOT版本 迭代开启 2023-07-10 11:18:12 +08:00
lujiaming 61f1d6ac8b
PdfFilePreviewImpl 中无效代码去除
Signed-off-by: lujiaming <1451771613@qq.com>
2023-07-05 16:18:11 +00:00
67 changed files with 189406 additions and 43239 deletions

View File

@ -1,5 +1,5 @@
FROM keking/kkfileview-jdk:latest FROM keking/kkfileview-jdk:latest
MAINTAINER chenjh "842761733@qq.com" MAINTAINER chenjh "842761733@qq.com"
ADD server/target/kkFileView-*.tar.gz /opt/ ADD server/target/kkFileView-*.tar.gz /opt/
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.3.0/bin ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.4.0-SNAPSHOT/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.3.0/config/application.properties","-jar","/opt/kkFileView-4.3.0/bin/kkFileView-4.3.0.jar"] ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.4.0-SNAPSHOT/config/application.properties","-jar","/opt/kkFileView-4.4.0-SNAPSHOT/bin/kkFileView-4.4.0-SNAPSHOT.jar"]

View File

@ -42,9 +42,7 @@
地址[https://file.kkview.cn](https://file.kkview.cn) 地址[https://file.kkview.cn](https://file.kkview.cn)
### 项目文档Project documentation ### 项目文档Project documentation
1. 详细wiki文档https://gitee.com/kekingcn/file-online-preview/wikis/pages 1. 详细使用文档https://kkview.cn/zh-cn/docs/home.html
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://gitee.com/kekingcn/file-online-preview/blob/master/README.en.md
### 联系我们加入组织 ### 联系我们加入组织
> 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少 Google baidu 珍爱生命远离无效的交流沟通 > 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少 Google baidu 珍爱生命远离无效的交流沟通
@ -110,12 +108,33 @@ pdf预览模式预览效果如下
![cad文档预览2](https://kkview.cn/img/preview/preview-cad-pdf.png) ![cad文档预览2](https://kkview.cn/img/preview/preview-cad-pdf.png)
考虑说明篇幅原因就不贴其他格式文件的预览效果了感兴趣的可以参考下面的实例搭建下 考虑说明篇幅原因就不贴其他格式文件的预览效果了感兴趣的可以参考下面的实例搭建下
#### 10. Excel文件纯前端渲染效果
![Excel文件纯前端渲染效果](https://kkview.cn/img/preview/preview-xlsx-web.png)
#### 11. 流程图bpmn文件预览效果
![流程图bpmn文件预览效果](https://kkview.cn/img/preview/preview-bpmn.png)
#### 12. 3D模型文件预览效果
![3D模型文件预览效果](https://kkview.cn/img/preview/preview-3ds.png)
#### 13. dcm医疗数位影像文件预览效果
![dcm医疗数位影像文件预览效果](https://kkview.cn/img/preview/preview-dcm.png)
#### 14. drawio流程图预览效果
![dcdrawio流程图预览效果](https://kkview.cn/img/preview/preview-drawio.png)
### 快速开始 ### 快速开始
> 项目使用技术 > 项目使用技术
- spring boot [spring boot开发参考指南](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot) - spring boot [spring boot开发参考指南](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- freemarker - freemarker
- redisson - redisson
- jodconverter - jodconverter
> 依赖外部环境 > 依赖外部环境
- redis (可选默认不用) - redis (可选默认不用)
- OpenOffice 或者 LibreOffice( Windows 下已内置Linux 脚本启动模式会自动安装Mac OS 下需要手动安装) - OpenOffice 或者 LibreOffice( Windows 下已内置Linux 脚本启动模式会自动安装Mac OS 下需要手动安装)
@ -129,7 +148,82 @@ pdf预览模式预览效果如下
### 历史更新记录 ### 历史更新记录
> 2022年12月14日v4.1.0 版本发布 #### > 2023年07月05日v4.3 版本发布
#### 新增功能:
1. 新增dcm等医疗数位影像预
2. 新增drawio绘图预览
3. 新增开启缓存的情况下重新生成的命令 &forceUpdatedCache=true
4. 新增dwg CAD文件预览
5. 新增PDF文件支持密码功能
6. 新增PDF文件生成图片的dpi自定义配置
7. 新增删除转换后OFFICECADTIFF压缩包源文件配置 默认开启 节约磁盘空间
8. 新增前端解析xlsx方法
9. 新增pages,eps, iges , igs, dwt, dng, ifc, dwfx, stl, cf2, plt等格式支持
#### 优化:
1. 调整生成的PDF文件 文件名称添加文件后缀 防止生成同名文件
2. 调整SQL文件预览方式
3. 优化OFD预览兼容性
4. 美化TXT文本 分页框的显示
5. 升级LinuxDocker版内置office为LibreOffice-7.5.3版本
6. 升级Windows版内置office为LibreOffice-7.5.3 Portable版本
7. 其他功能优化
#### 修复:
1. 修复反代情况下压缩包获取路径错误
2. 修复预览图片的url中如果包含&会导致.click报错
3. 修复OFD预览部分已知问题
4. 修复预览压缩包时如果点击的是文件目录树节点页面会报错
5. 其他已知问题修复
#### > 2023年04月18日v4.2.1 版本发布
#### 更新日志:
1. 修复 dwg 文件预览报空指针的 bug
#### > 2023年04月13日v4.2.0 版本发布
#### 新增功能:
1. 新增 SVG 格式文件预览支持
2. 新增加密的 Office 文件预览支持
3. 新增加密的 ziprar 等压缩包文件预览支持
4. 新增 xmind 软件模型文件预览支持
5. 新增 bpmn 工作流模型文件预览支持
6. 新增 eml 邮件文件预览支持
7. 新增 epub 电子书文件预览支持
8. 新增 dotm,ett,xlt,xltm,wpt,dot,xlam,xla,dotx 等格式的办公文档预览支持
9. 新增 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 3D 模型文件预览支持
10. 新增可配置限制高风险文件上传的功能比如 exe 文件
11. 新增可配置站点的备案信息
12. 新增演示站点删除文件需要密码的功能
#### 优化:
1. 文本文档预览加入缓存
2. 美化 404500 报错页
3. 优化发票等 ofd 文件预览的印证渲染兼容性
4. 移除 office-plugin 模块, 使用新版 jodconverter组件
5. 优化 Excel 文件的预览效果
6. 优化 CAD 文件的预览效果
7. 更新 xstream junrarpdfbox 等依赖的版本
8. 更新 TIF 文件转换 PDF 的插件添加转换缓存
9. 优化演示页 UI 部署
10. 压缩包文件预览支持目录
#### 修复:
1. 修复部分接口 XSS 问题
2. 修复控制台打印的演示地址不跟着 content-path 配置走的问题
3. 修复 ofd 文件预览跨域问题
4. 修复内部自签证书 https 协议 url 文件无法下载的问题
5. 修复特殊符号的文件无法删除的问题
6. 修复 PDF 转图片,内存无法回收导致的 OOM
7. 修复 xlsx7.4 以上版本文件预览乱码的问题
8. 修复 TrustHostFilter 未拦截跨域接口的问题这是一个安全问题有使用到 TrustHost 功能的务必升级
9. 修复压缩包文件预览在 Linux 系统下文件名乱码的问题
10. 修复 ofd 文件预览页码只能显示10页的问题
#### > 2022年12月14日v4.1.0 版本发布
1. 全新首页视觉 @wsd7747 1. 全新首页视觉 @wsd7747
2. tif图片预览兼容多页tif的pdf转换jpg转换以及jpg在线多页预览功能 @zhangzhen1979 2. tif图片预览兼容多页tif的pdf转换jpg转换以及jpg在线多页预览功能 @zhangzhen1979
@ -142,7 +236,7 @@ pdf预览模式预览效果如下
感谢 @yl-yue @wsd7747 @zhangzhen1979 @tomhusky @shenghuadun @kischn.sun 的代码贡献 感谢 @yl-yue @wsd7747 @zhangzhen1979 @tomhusky @shenghuadun @kischn.sun 的代码贡献
> 2021年7月6日v4.0.0 版本发布 #### > 2021年7月6日v4.0.0 版本发布
1. 底层集成OpenOffice替换为LibreOfficeOffice文件兼容性增强预览效果提升 1. 底层集成OpenOffice替换为LibreOfficeOffice文件兼容性增强预览效果提升
2. 修复压缩文件目录穿越漏洞 2. 修复压缩文件目录穿越漏洞
@ -153,7 +247,7 @@ pdf预览模式预览效果如下
7. 优化Windows环境下查找Office组件逻辑(内置的LibreOffice优先) 7. 优化Windows环境下查找Office组件逻辑(内置的LibreOffice优先)
8. 优化启动Office进程改同步执行 8. 优化启动Office进程改同步执行
> 2021年6月17日v3.6.0 版本发布 #### > 2021年6月17日v3.6.0 版本发布
ofd 类型文件支持版本本次版本重要功能均由社区开发贡献感谢 @gaoxingzaq@zhangxiaoxiao9527 的代码贡献 ofd 类型文件支持版本本次版本重要功能均由社区开发贡献感谢 @gaoxingzaq@zhangxiaoxiao9527 的代码贡献
1. 新增 ofd 类型文件预览支持ofd 是国产的类似 pdf 格式的文件 1. 新增 ofd 类型文件预览支持ofd 是国产的类似 pdf 格式的文件
@ -161,7 +255,7 @@ ofd 类型文件支持版本,本次版本重要功能均由社区开发贡献
3. 美化了 pptpptx 类型文件预览效果比之前版本好看太多 3. 美化了 pptpptx 类型文件预览效果比之前版本好看太多
4. 更新了 pdfboxxstreamcommon-io 等依赖的版本 4. 更新了 pdfboxxstreamcommon-io 等依赖的版本
> 2021年1月28日 #### > 2021年1月28日
2020农历年最后一个版本发布主要包含了部分 UI 改进和解决了 QQ 群友 Issue 里反馈的 Bug 修复最最重要的是发个新版过个好年 2020农历年最后一个版本发布主要包含了部分 UI 改进和解决了 QQ 群友 Issue 里反馈的 Bug 修复最最重要的是发个新版过个好年
@ -184,7 +278,7 @@ ofd 类型文件支持版本,本次版本重要功能均由社区开发贡献
17. escaping of dangerous characters to prevent reflected xss 17. escaping of dangerous characters to prevent reflected xss
18. 修复重复编码导致文档转图片预览失败的问题&编码规范 18. 修复重复编码导致文档转图片预览失败的问题&编码规范
> 2020年12月27日 #### > 2020年12月27日
2020年年终大版本更新架构全面设计代码全面重构代码质量全面提升二次开发更便捷欢迎拉源码品鉴提issuepr共同建设 2020年年终大版本更新架构全面设计代码全面重构代码质量全面提升二次开发更便捷欢迎拉源码品鉴提issuepr共同建设
@ -204,7 +298,7 @@ ofd 类型文件支持版本,本次版本重要功能均由社区开发贡献
14. 修复压缩包里文件再次预览失败的bug 14. 修复压缩包里文件再次预览失败的bug
15. 修复图片预览的bug 15. 修复图片预览的bug
> 2020年05月20日 #### > 2020年05月20日
1. 新增支持全局水印并支持通过参数动态改变水印内容 1. 新增支持全局水印并支持通过参数动态改变水印内容
2. 新增支持CAD文件预览 2. 新增支持CAD文件预览
3. 新增base.url配置支持使用nginx反向代理和使用context-path 3. 新增base.url配置支持使用nginx反向代理和使用context-path
@ -222,35 +316,35 @@ ofd 类型文件支持版本,本次版本重要功能均由社区开发贡献
15. 官网建设[https://kkview.cn](https://kkview.cn/) 15. 官网建设[https://kkview.cn](https://kkview.cn/)
16. 官方Docker镜像仓库建设[https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview) 16. 官方Docker镜像仓库建设[https://hub.docker.com/r/keking/kkfileview](https://hub.docker.com/r/keking/kkfileview)
> 2019年06月18日 #### > 2019年06月18日
1. 支持自动清理缓存及预览文件 1. 支持自动清理缓存及预览文件
2. 支持http/https下载流url文件预览 2. 支持http/https下载流url文件预览
3. 支持FTP url文件预览 3. 支持FTP url文件预览
4. 加入Docker构建 4. 加入Docker构建
> 2019年04月08日 #### > 2019年04月08日
1. 缓存及队列实现抽象提供JDK和REDIS两种实现(REDIS成为可选依赖) 1. 缓存及队列实现抽象提供JDK和REDIS两种实现(REDIS成为可选依赖)
2. 打包方式提供zip和tar.gz包并提供一键启动脚本 2. 打包方式提供zip和tar.gz包并提供一键启动脚本
> 2018年01月19日 #### > 2018年01月19日
1. 大文件入队提前处理 1. 大文件入队提前处理
1. 新增addTask文件转换入队接口 1. 新增addTask文件转换入队接口
1. 采用redis队列支持kkFIleView接口和异构系统入队两种方式 1. 采用redis队列支持kkFIleView接口和异构系统入队两种方式
> 2018年01月17日 #### > 2018年01月17日
1. 优化项目结构抽象文件预览接口更方便的加入更多的文件类型预览支持方便二次开发 1. 优化项目结构抽象文件预览接口更方便的加入更多的文件类型预览支持方便二次开发
1. 新增英文文档说明@幻幻Fate@汝辉贡献 1. 新增英文文档说明@幻幻Fate@汝辉贡献
1. 新增图片预览文件支持类型 1. 新增图片预览文件支持类型
1. 修复压缩包内轮播图片总是从第一张开始的问题 1. 修复压缩包内轮播图片总是从第一张开始的问题
> 2018年01月12日 #### > 2018年01月12日
1. 新增多图片同时预览 1. 新增多图片同时预览
1. 支持压缩包内图片轮番预览 1. 支持压缩包内图片轮番预览
> 2018年01月02日 #### > 2018年01月02日
1. 修复txt等文本编码问题导致预览乱码 1. 修复txt等文本编码问题导致预览乱码
1. 修复项目模块依赖引入不到的问题 1. 修复项目模块依赖引入不到的问题
@ -265,14 +359,15 @@ xmind 引用于 [ xmind-embed-viewer](https://github.com/xmindltd/xmind-embed-v
epub 引用于 [ epub.js](https://github.com/futurepress/epub.js) 开源协议 BSD许可证 epub 引用于 [ epub.js](https://github.com/futurepress/epub.js) 开源协议 BSD许可证
压缩包 引用于 [sevenzipjbinding](https://github.com/borisbrodski/sevenzipjbinding )开源协议LGPL 压缩包 引用于 [sevenzipjbinding](https://github.com/borisbrodski/sevenzipjbinding )开源协议LGPL
3D 引用于 [Online3DViewer](https://github.com/kovacsv/Online3DViewer )开源协议MIT 3D 引用于 [Online3DViewer](https://github.com/kovacsv/Online3DViewer )开源协议MIT
drawio 引用于 [drawio](https://github.com/jgraph/drawio )开源协议 Apache-2.0
bpmn流程图 引用于 [bpmn-js](https://github.com/bpmn-io/bpmn-js ) 自定义协议 保留水印 具体自行查看
dcm医疗数位影像 引用于 [dcmjs](https://github.com/dcmjs-org/dcmjs )开源协议MIT
### 使用登记 ### 使用登记
如果这个项目解决了你的实际问题可在 https://gitee.com/kekingcn/file-online-preview/issues/IGSBV 如果这个项目解决了你的实际问题可在 https://gitee.com/kekingcn/file-online-preview/issues/IGSBV
登记下如果节省了你的三方预览服务费用也愿意支持下的话可点击下方捐助请作者喝杯咖啡也是非常感谢 登记下如果节省了你的三方预览服务费用也愿意支持下的话可点击下方捐助请作者喝杯咖啡也是非常感谢
### Stars 趋势图 ### Stars
#### Gitee
[![Stargazers over time](https://whnb.wang/img/kekingcn/file-online-preview)](https://whnb.wang/kekingcn/file-online-preview?e=86400)
#### GitHub #### GitHub

View File

@ -6,7 +6,7 @@
<groupId>cn.keking</groupId> <groupId>cn.keking</groupId>
<artifactId>kkFileView-parent</artifactId> <artifactId>kkFileView-parent</artifactId>
<version>4.3.0</version> <version>4.4.0-SNAPSHOT</version>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
@ -32,8 +32,9 @@
<ffmpeg.version>4.2.1-1.5.2</ffmpeg.version> <ffmpeg.version>4.2.1-1.5.2</ffmpeg.version>
<itextpdf.version>5.5.13.3</itextpdf.version> <itextpdf.version>5.5.13.3</itextpdf.version>
<httpclient.version>3.1</httpclient.version> <httpclient.version>3.1</httpclient.version>
<aspose-cad.version>23.1</aspose-cad.version> <aspose-cad.version>23.3</aspose-cad.version>
<bcprov-jdk15on.version>1.70</bcprov-jdk15on.version> <bcprov-jdk15on.version>1.70</bcprov-jdk15on.version>
<juniversalchardet.version>1.0.3</juniversalchardet.version>
<commons-cli.version>1.2</commons-cli.version> <commons-cli.version>1.2</commons-cli.version>
<commons-net.version>3.6</commons-net.version> <commons-net.version>3.6</commons-net.version>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>kkFileView-parent</artifactId> <artifactId>kkFileView-parent</artifactId>
<groupId>cn.keking</groupId> <groupId>cn.keking</groupId>
<version>4.3.0</version> <version>4.4.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>kkFileView</artifactId> <artifactId>kkFileView</artifactId>
@ -122,6 +122,14 @@
<artifactId>redisson</artifactId> <artifactId>redisson</artifactId>
<version>${redisson.version}</version> <version>${redisson.version}</version>
</dependency> </dependency>
<!-- 编码检测-JUniversalCharDet-->
<dependency>
<groupId>com.googlecode.juniversalchardet</groupId>
<artifactId>juniversalchardet</artifactId>
<version>${juniversalchardet.version}</version>
</dependency>
<!-- 解压(rar)--> <!-- 解压(rar)-->
<dependency> <dependency>
<groupId>com.github.junrar</groupId> <groupId>com.github.junrar</groupId>

View File

@ -7,4 +7,4 @@ echo Please check log file in ../log/kkFileView.log for more information
echo You can get help in our official home site: https://kkview.cn echo You can get help in our official home site: https://kkview.cn
echo If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ echo If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ
echo If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers echo If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers
java -Dspring.config.location=..\config\application.properties -jar kkFileView-4.3.0.jar -> ..\log\kkFileView.log java -Dspring.config.location=..\config\application.properties -jar kkFileView-4.4.0-SNAPSHOT.jar -> ..\log\kkFileView.log

View File

@ -51,7 +51,7 @@ else
## 启动kkFileView ## 启动kkFileView
echo "Starting kkFileView..." echo "Starting kkFileView..."
nohup java -Dfile.encoding=UTF-8 -Dspring.config.location=../config/application.properties -jar kkFileView-4.3.0.jar > ../log/kkFileView.log 2>&1 & nohup java -Dfile.encoding=UTF-8 -Dspring.config.location=../config/application.properties -jar kkFileView-4.4.0-SNAPSHOT.jar > ../log/kkFileView.log 2>&1 &
echo "Please execute ./showlog.sh to check log for more information" echo "Please execute ./showlog.sh to check log for more information"
echo "You can get help in our official home site: https://kkview.cn" echo "You can get help in our official home site: https://kkview.cn"
echo "If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ" echo "If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ"

View File

@ -2,7 +2,13 @@
server.port = ${KK_SERVER_PORT:8012} server.port = ${KK_SERVER_PORT:8012}
server.servlet.context-path= ${KK_CONTEXT_PATH:/} server.servlet.context-path= ${KK_CONTEXT_PATH:/}
server.servlet.encoding.charset = utf-8 server.servlet.encoding.charset = utf-8
#文件上传限制前端 #启用GZIP压缩功能
server.compression.enable= true
#允许压缩的响应缓冲区最小字节数默认2048
server.compression.min-response-size = 2048
#压缩格式
server.compression.mime-types=application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain,font/woff,application/font-woff,font/eot,image/svg+xml,image/x-icon
# 文件上传限制前端
spring.servlet.multipart.max-file-size=500MB spring.servlet.multipart.max-file-size=500MB
#文件上传限制 #文件上传限制
spring.servlet.multipart.max-request-size=500MB spring.servlet.multipart.max-request-size=500MB
@ -124,6 +130,8 @@ tif.preview.type = ${KK_TIF_PREVIEW_TYPE:tif}
beian = ${KK_BEIAN:default} beian = ${KK_BEIAN:default}
#禁止上传类型 #禁止上传类型
prohibit = ${KK_PROHIBIT:exe,dll,dat} prohibit = ${KK_PROHIBIT:exe,dll,dat}
#启用验证码删除文件 默认关闭
delete.captcha= ${KK_DELETE_CAPTCHA:false}
#删除密码 #删除密码
delete.password = ${KK_DELETE_PASSWORD:123456} delete.password = ${KK_DELETE_PASSWORD:123456}
#删除 转换后OFFICECADTIFF压缩包源文件 默认开启 节约磁盘空间 #删除 转换后OFFICECADTIFF压缩包源文件 默认开启 节约磁盘空间
@ -131,4 +139,26 @@ delete.source.file = ${KK_DELETE_SOURCE_FILE:true}
#配置PDF文件生成图片的像素大小dpi 越高图片质量越清晰同时也会消耗更多的计算资源 #配置PDF文件生成图片的像素大小dpi 越高图片质量越清晰同时也会消耗更多的计算资源
pdf2jpg.dpi = ${KK_PDF2JPG_DPI:144} pdf2jpg.dpi = ${KK_PDF2JPG_DPI:144}
#xlsx格式前端解析 #xlsx格式前端解析
office.type.web = ${KK_OFFICE_TYPE_WEB:web} office.type.web = ${KK_OFFICE_TYPE_WEB:web}
#Cad类型图片浏览模式tif利用前端js插件浏览svg转换为svg显示pdf转换为pdf后显示便于打印
cad.preview.type = ${KK_CAD_PREVIEW_TYPE:svg}
#Cad转换超时设置
cad.timeout =${KK_CAD_TIMEOUT:90}
#Cad转换线程设置
cad.thread =${KK_CAD_THREAD:5}
#OFFICE转换模块设置
#生成限制 默认不限制 使用方法 (1-5)
office.pagerange = ${KK_OFFICE_PAGERANGE:false}
#生成水印 默认不启用 使用方法 (kkFileView)
office.watermark = ${KK_OFFICE_WATERMARK:false}
#OFFICE JPEG图片压缩
office.quality = ${KK_OFFICE_QUALITY:80}
#图像分辨率限制
office.maximageresolution = ${KK_OFFICE_MAXIMAGERESOLUTION:150}
#导出书签
office.exportbookmarks = ${KK_OFFICE_EXPORTBOOKMARKS:true}
#批注作为PDF的注释
office.exportnotes = ${KK_OFFICE_EXPORTNOTES:true}
#加密文档 生成的PDF文档 添加密码(密码为加密文档的密码)
office.documentopenpasswords = ${KK_OFFICE_DOCUMENTOPENPASSWORD:true}

View File

@ -48,10 +48,21 @@ public class ConfigConstants {
private static String password; private static String password;
private static int pdf2JpgDpi; private static int pdf2JpgDpi;
private static String officeTypeWeb; private static String officeTypeWeb;
private static String cadPreviewType;
private static Boolean deleteSourceFile; private static Boolean deleteSourceFile;
private static Boolean deleteCaptcha;
private static String officePageRange;
private static String officeWatermark;
private static String officeQuality;
private static String officeMaxImageResolution;
private static Boolean officeExportBookmarks;
private static Boolean officeExportNotes;
private static Boolean officeDocumentOpenPasswords;
private static String cadTimeout;
private static int cadThread;
public static final String DEFAULT_CACHE_ENABLED = "true"; public static final String DEFAULT_CACHE_ENABLED = "true";
public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd"; public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd,xbrl";
public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv"; public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv";
public static final String DEFAULT_OFFICE_PREVIEW_TYPE = "image"; public static final String DEFAULT_OFFICE_PREVIEW_TYPE = "image";
public static final String DEFAULT_OFFICE_PREVIEW_SWITCH_DISABLED = "false"; public static final String DEFAULT_OFFICE_PREVIEW_SWITCH_DISABLED = "false";
@ -69,6 +80,7 @@ public class ConfigConstants {
public static final String DEFAULT_PDF_BOOKMARK_DISABLE = "true"; public static final String DEFAULT_PDF_BOOKMARK_DISABLE = "true";
public static final String DEFAULT_FILE_UPLOAD_DISABLE = "false"; public static final String DEFAULT_FILE_UPLOAD_DISABLE = "false";
public static final String DEFAULT_TIF_PREVIEW_TYPE = "tif"; public static final String DEFAULT_TIF_PREVIEW_TYPE = "tif";
public static final String DEFAULT_CAD_PREVIEW_TYPE = "pdf";
public static final String DEFAULT_BEIAN = ""; public static final String DEFAULT_BEIAN = "";
public static final String DEFAULT_SIZE = "500MB"; public static final String DEFAULT_SIZE = "500MB";
public static final String DEFAULT_PROHIBIT = "exe,dll"; public static final String DEFAULT_PROHIBIT = "exe,dll";
@ -76,6 +88,19 @@ public class ConfigConstants {
public static final String DEFAULT_PDF2_JPG_DPI = "105"; public static final String DEFAULT_PDF2_JPG_DPI = "105";
public static final String DEFAULT_OFFICE_TYPE_WEB = "web"; public static final String DEFAULT_OFFICE_TYPE_WEB = "web";
public static final String DEFAULT_DELETE_SOURCE_FILE = "true"; public static final String DEFAULT_DELETE_SOURCE_FILE = "true";
public static final String DEFAULT_DELETE_CAPTCHA = "false";
public static final String DEFAULT_CAD_TIMEOUT = "90";
public static final String DEFAULT_CAD_THREAD = "5";
public static final String DEFAULT_OFFICE_PAQERANQE = "false";
public static final String DEFAULT_OFFICE_WATERMARK = "false";
public static final String DEFAULT_OFFICE_QUALITY = "80";
public static final String DEFAULT_OFFICE_MAXIMAQERESOLUTION = "150";
public static final String DEFAULT_OFFICE_EXPORTBOOKMARKS = "true";
public static final String DEFAULT_OFFICE_EXPORTNOTES = "true";
public static final String DEFAULT_OFFICE_EOCUMENTOPENPASSWORDS = "true";
public static Boolean isCacheEnabled() { public static Boolean isCacheEnabled() {
return cacheEnabled; return cacheEnabled;
@ -94,7 +119,7 @@ public class ConfigConstants {
return simTexts; return simTexts;
} }
@Value("${simText:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}") @Value("${simText:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd,xbrl}")
public void setSimText(String simText) { public void setSimText(String simText) {
String[] simTextArr = simText.split(","); String[] simTextArr = simText.split(",");
setSimTextValue(simTextArr); setSimTextValue(simTextArr);
@ -449,4 +474,143 @@ public class ConfigConstants {
ConfigConstants.deleteSourceFile = deleteSourceFile; ConfigConstants.deleteSourceFile = deleteSourceFile;
} }
public static Boolean getDeleteCaptcha() {
return deleteCaptcha;
}
@Value("${delete.captcha:false}")
public void setDeleteCaptcha(Boolean deleteCaptcha) {
setDeleteCaptchaValue(deleteCaptcha);
}
public static void setDeleteCaptchaValue(Boolean deleteCaptcha) {
ConfigConstants.deleteCaptcha = deleteCaptcha;
}
/**
* 以下为cad转换模块设置
*/
public static String getCadPreviewType() {
return cadPreviewType;
}
@Value("${cad.preview.type:svg}")
public void setCadPreviewType(String cadPreviewType) {
setCadPreviewTypeValue(cadPreviewType);
}
public static void setCadPreviewTypeValue(String cadPreviewType) {
ConfigConstants.cadPreviewType = cadPreviewType;
}
public static String getCadTimeout() {
return cadTimeout;
}
@Value("${cad.timeout:90}")
public void setCadTimeout(String cadTimeout) {
setCadTimeoutValue(cadTimeout);
}
public static void setCadTimeoutValue(String cadTimeout) {
ConfigConstants.cadTimeout = cadTimeout;
}
public static int getCadThread() {
return cadThread;
}
@Value("${cad.thread:5}")
public void setCadThread(int cadThread) {
setCadThreadValue(cadThread);
}
public static void setCadThreadValue(int cadThread) {
ConfigConstants.cadThread = cadThread;
}
/**
* 以下为OFFICE转换模块设置
*/
public static String getOfficePageRange() {
return officePageRange;
}
@Value("${office.pagerange:false}")
public void setOfficePageRange(String officePageRange) {
setOfficePageRangeValue(officePageRange);
}
public static void setOfficePageRangeValue(String officePageRange) {
ConfigConstants.officePageRange = officePageRange;
}
public static String getOfficeWatermark() {
return officeWatermark;
}
@Value("${office.watermark:false}")
public void setOfficeWatermark(String officeWatermark) {
setOfficeWatermarkValue(officeWatermark);
}
public static void setOfficeWatermarkValue(String officeWatermark) {
ConfigConstants.officeWatermark = officeWatermark;
}
public static String getOfficeQuality() {
return officeQuality;
}
@Value("${office.quality:80}")
public void setOfficeQuality(String officeQuality) {
setOfficeQualityValue(officeQuality);
}
public static void setOfficeQualityValue(String officeQuality) {
ConfigConstants.officeQuality = officeQuality;
}
public static String getOfficeMaxImageResolution() {
return officeMaxImageResolution;
}
@Value("${office.maximageresolution:150}")
public void setOfficeMaxImageResolution(String officeMaxImageResolution) {
setOfficeMaxImageResolutionValue(officeMaxImageResolution);
}
public static void setOfficeMaxImageResolutionValue(String officeMaxImageResolution) {
ConfigConstants.officeMaxImageResolution = officeMaxImageResolution;
}
public static Boolean getOfficeExportBookmarks() {
return officeExportBookmarks;
}
@Value("${office.exportbookmarks:true}")
public void setOfficeExportBookmarks(Boolean officeExportBookmarks) {
setOfficeExportBookmarksValue(officeExportBookmarks);
}
public static void setOfficeExportBookmarksValue(Boolean officeExportBookmarks) {
ConfigConstants.officeExportBookmarks = officeExportBookmarks;
}
public static Boolean getOfficeExportNotes() {
return officeExportNotes;
}
@Value("${office.exportnotes:true}")
public void setExportNotes(Boolean officeExportNotes) {
setOfficeExportNotesValue(officeExportNotes);
}
public static void setOfficeExportNotesValue(Boolean officeExportNotes) {
ConfigConstants.officeExportNotes = officeExportNotes;
}
public static Boolean getOfficeDocumentOpenPasswords() {
return officeDocumentOpenPasswords;
}
@Value("${office.documentopenpasswords:true}")
public void setDocumentOpenPasswords(Boolean officeDocumentOpenPasswords) {
setOfficeDocumentOpenPasswordsValue(officeDocumentOpenPasswords);
}
public static void setOfficeDocumentOpenPasswordsValue(Boolean officeDocumentOpenPasswords) {
ConfigConstants.officeDocumentOpenPasswords = officeDocumentOpenPasswords;
}
} }

View File

@ -60,7 +60,18 @@ public class ConfigRefreshComponent {
String password; String password;
int pdf2JpgDpi; int pdf2JpgDpi;
String officeTypeWeb; String officeTypeWeb;
String cadPreviewType;
boolean deleteSourceFile; boolean deleteSourceFile;
boolean deleteCaptcha;
String officPageRange;
String officWatermark;
String officQuality;
String officMaxImageResolution;
boolean officExportBookmarks;
boolean officeExportNotes;
boolean officeDocumentOpenPasswords;
String cadTimeout;
int cadThread;
while (true) { while (true) {
FileReader fileReader = new FileReader(configFilePath); FileReader fileReader = new FileReader(configFilePath);
BufferedReader bufferedReader = new BufferedReader(fileReader); BufferedReader bufferedReader = new BufferedReader(fileReader);
@ -85,6 +96,7 @@ public class ConfigRefreshComponent {
pdfBookmarkDisable = properties.getProperty("pdf.bookmark.disable", ConfigConstants.DEFAULT_PDF_BOOKMARK_DISABLE); pdfBookmarkDisable = properties.getProperty("pdf.bookmark.disable", ConfigConstants.DEFAULT_PDF_BOOKMARK_DISABLE);
fileUploadDisable = Boolean.parseBoolean(properties.getProperty("file.upload.disable", ConfigConstants.DEFAULT_FILE_UPLOAD_DISABLE)); fileUploadDisable = Boolean.parseBoolean(properties.getProperty("file.upload.disable", ConfigConstants.DEFAULT_FILE_UPLOAD_DISABLE));
tifPreviewType = properties.getProperty("tif.preview.type", ConfigConstants.DEFAULT_TIF_PREVIEW_TYPE); tifPreviewType = properties.getProperty("tif.preview.type", ConfigConstants.DEFAULT_TIF_PREVIEW_TYPE);
cadPreviewType = properties.getProperty("cad.preview.type", ConfigConstants.DEFAULT_CAD_PREVIEW_TYPE);
size = properties.getProperty("spring.servlet.multipart.max-file-size", ConfigConstants.DEFAULT_SIZE); size = properties.getProperty("spring.servlet.multipart.max-file-size", ConfigConstants.DEFAULT_SIZE);
beian = properties.getProperty("beian", ConfigConstants.DEFAULT_BEIAN); beian = properties.getProperty("beian", ConfigConstants.DEFAULT_BEIAN);
prohibit = properties.getProperty("prohibit", ConfigConstants.DEFAULT_PROHIBIT); prohibit = properties.getProperty("prohibit", ConfigConstants.DEFAULT_PROHIBIT);
@ -92,6 +104,16 @@ public class ConfigRefreshComponent {
pdf2JpgDpi = Integer.parseInt(properties.getProperty("pdf2jpg.dpi", ConfigConstants.DEFAULT_PDF2_JPG_DPI)); pdf2JpgDpi = Integer.parseInt(properties.getProperty("pdf2jpg.dpi", ConfigConstants.DEFAULT_PDF2_JPG_DPI));
officeTypeWeb = properties.getProperty("office.type.web", ConfigConstants.DEFAULT_OFFICE_TYPE_WEB); officeTypeWeb = properties.getProperty("office.type.web", ConfigConstants.DEFAULT_OFFICE_TYPE_WEB);
deleteSourceFile = Boolean.parseBoolean(properties.getProperty("delete.source.file", ConfigConstants.DEFAULT_DELETE_SOURCE_FILE)); deleteSourceFile = Boolean.parseBoolean(properties.getProperty("delete.source.file", ConfigConstants.DEFAULT_DELETE_SOURCE_FILE));
deleteCaptcha = Boolean.parseBoolean(properties.getProperty("delete.captcha", ConfigConstants.DEFAULT_DELETE_CAPTCHA));
officPageRange = properties.getProperty("office.pagerange", ConfigConstants.DEFAULT_OFFICE_PAQERANQE);
officWatermark = properties.getProperty("office.watermark", ConfigConstants.DEFAULT_OFFICE_WATERMARK);
officQuality = properties.getProperty("office.quality", ConfigConstants.DEFAULT_OFFICE_QUALITY);
officMaxImageResolution = properties.getProperty("office.maximageresolution", ConfigConstants.DEFAULT_OFFICE_MAXIMAQERESOLUTION);
officExportBookmarks = Boolean.parseBoolean(properties.getProperty("office.exportbookmarks", ConfigConstants.DEFAULT_OFFICE_EXPORTBOOKMARKS));
officeExportNotes = Boolean.parseBoolean(properties.getProperty("office.exportnotes", ConfigConstants.DEFAULT_OFFICE_EXPORTNOTES));
officeDocumentOpenPasswords = Boolean.parseBoolean(properties.getProperty("office.documentopenpasswords", ConfigConstants.DEFAULT_OFFICE_EOCUMENTOPENPASSWORDS));
cadTimeout = properties.getProperty("cad.timeout", ConfigConstants.DEFAULT_CAD_TIMEOUT);
cadThread = Integer.parseInt(properties.getProperty("cad.thread", ConfigConstants.DEFAULT_CAD_THREAD));
prohibitArray = prohibit.split(","); prohibitArray = prohibit.split(",");
ConfigConstants.setCacheEnabledValueValue(cacheEnabled); ConfigConstants.setCacheEnabledValueValue(cacheEnabled);
@ -111,13 +133,24 @@ public class ConfigRefreshComponent {
ConfigConstants.setPdfBookmarkDisableValue(pdfBookmarkDisable); ConfigConstants.setPdfBookmarkDisableValue(pdfBookmarkDisable);
ConfigConstants.setFileUploadDisableValue(fileUploadDisable); ConfigConstants.setFileUploadDisableValue(fileUploadDisable);
ConfigConstants.setTifPreviewTypeValue(tifPreviewType); ConfigConstants.setTifPreviewTypeValue(tifPreviewType);
ConfigConstants.setCadPreviewTypeValue(cadPreviewType);
ConfigConstants.setBeianValue(beian); ConfigConstants.setBeianValue(beian);
ConfigConstants.setSizeValue(size); ConfigConstants.setSizeValue(size);
ConfigConstants.setProhibitValue(prohibitArray); ConfigConstants.setProhibitValue(prohibitArray);
ConfigConstants.setPasswordValue(password); ConfigConstants.setPasswordValue(password);
ConfigConstants.setPdf2JpgDpiValue(pdf2JpgDpi); ConfigConstants.setPdf2JpgDpiValue(pdf2JpgDpi);
ConfigConstants.setOfficeTypeWebValue(officeTypeWeb); ConfigConstants.setOfficeTypeWebValue(officeTypeWeb);
ConfigConstants.setOfficePageRangeValue(officPageRange);
ConfigConstants.setOfficeWatermarkValue(officWatermark);
ConfigConstants.setOfficeQualityValue(officQuality);
ConfigConstants.setOfficeMaxImageResolutionValue(officMaxImageResolution);
ConfigConstants.setOfficeExportBookmarksValue(officExportBookmarks);
ConfigConstants.setOfficeExportNotesValue(officeExportNotes);
ConfigConstants.setOfficeDocumentOpenPasswordsValue(officeDocumentOpenPasswords);
ConfigConstants.setDeleteSourceFileValue(deleteSourceFile); ConfigConstants.setDeleteSourceFileValue(deleteSourceFile);
ConfigConstants.setDeleteCaptchaValue(deleteCaptcha);
ConfigConstants.setCadTimeoutValue(cadTimeout);
ConfigConstants.setCadThreadValue(cadThread);
setWatermarkConfig(properties); setWatermarkConfig(properties);
bufferedReader.close(); bufferedReader.close();
fileReader.close(); fileReader.close();

View File

@ -43,6 +43,7 @@ public enum FileType {
private static final String[] EPUB_TYPES = {"epub"}; private static final String[] EPUB_TYPES = {"epub"};
private static final String[] DCM_TYPES = {"dcm"}; private static final String[] DCM_TYPES = {"dcm"};
private static final String[] DRAWIO_TYPES = {"drawio"}; private static final String[] DRAWIO_TYPES = {"drawio"};
private static final String[] XML_TYPES = {"xml","xbrl"};
private static final String[] TIFF_TYPES = {"tif", "tiff"}; private static final String[] TIFF_TYPES = {"tif", "tiff"};
private static final String[] OFD_TYPES = {"ofd"}; private static final String[] OFD_TYPES = {"ofd"};
private static final String[] SVG_TYPES = {"svg"}; private static final String[] SVG_TYPES = {"svg"};
@ -105,8 +106,10 @@ public enum FileType {
for (String drawio : DRAWIO_TYPES) { for (String drawio : DRAWIO_TYPES) {
FILE_TYPE_MAPPER.put(drawio, FileType.DRAWIO); FILE_TYPE_MAPPER.put(drawio, FileType.DRAWIO);
} }
for (String xml : XML_TYPES) {
FILE_TYPE_MAPPER.put(xml, FileType.XML);
}
FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN); FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN);
FILE_TYPE_MAPPER.put("xml", FileType.XML);
FILE_TYPE_MAPPER.put("pdf", FileType.PDF); FILE_TYPE_MAPPER.put("pdf", FileType.PDF);
FILE_TYPE_MAPPER.put("flv", FileType.FLV); FILE_TYPE_MAPPER.put("flv", FileType.FLV);
FILE_TYPE_MAPPER.put("bpmn", FileType.BPMN); FILE_TYPE_MAPPER.put("bpmn", FileType.BPMN);

View File

@ -9,12 +9,13 @@ import cn.keking.utils.EncodingDetects;
import cn.keking.utils.KkFileUtils; import cn.keking.utils.KkFileUtils;
import cn.keking.utils.WebUtils; import cn.keking.utils.WebUtils;
import cn.keking.web.filter.BaseUrlFilter; import cn.keking.web.filter.BaseUrlFilter;
import com.aspose.cad.CodePages; import com.aspose.cad.*;
import com.aspose.cad.Color; import com.aspose.cad.fileformats.tiff.enums.TiffExpectedFormat;
import com.aspose.cad.Image;
import com.aspose.cad.LoadOptions;
import com.aspose.cad.imageoptions.CadRasterizationOptions; import com.aspose.cad.imageoptions.CadRasterizationOptions;
import com.aspose.cad.imageoptions.PdfOptions; import com.aspose.cad.imageoptions.PdfOptions;
import com.aspose.cad.imageoptions.SvgOptions;
import com.aspose.cad.imageoptions.TiffOptions;
import com.aspose.cad.internal.Exceptions.TimeoutException;
import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfReader;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
@ -38,6 +39,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.*;
import java.util.stream.IntStream; import java.util.stream.IntStream;
/** /**
@ -52,7 +54,6 @@ public class FileHandlerService {
private final Logger logger = LoggerFactory.getLogger(FileHandlerService.class); private final Logger logger = LoggerFactory.getLogger(FileHandlerService.class);
private final String fileDir = ConfigConstants.getFileDir(); private final String fileDir = ConfigConstants.getFileDir();
private final CacheService cacheService; private final CacheService cacheService;
@Value("${server.tomcat.uri-encoding:UTF-8}") @Value("${server.tomcat.uri-encoding:UTF-8}")
private String uriEncoding; private String uriEncoding;
@ -143,6 +144,10 @@ public class FileHandlerService {
cacheService.putImgCache(fileKey, imgs); cacheService.putImgCache(fileKey, imgs);
} }
/**
cad定义线程池
*/
private static final ExecutorService pool = Executors.newFixedThreadPool(ConfigConstants.getCadThread());
/** /**
* 对转换后的文件进行操作(改变编码方式) * 对转换后的文件进行操作(改变编码方式)
* *
@ -259,7 +264,7 @@ public class FileHandlerService {
imageUrls.add(imageUrl); imageUrls.add(imageUrl);
} }
try { try {
pdfReader = new PdfReader(pdfFilePath); //读取PDF文件 pdfReader = new PdfReader(pdfFilePath,filePassword.getBytes()); //读取PDF文件
} catch (Exception e) { //获取异常方法 判断是否有加密字符串 } catch (Exception e) { //获取异常方法 判断是否有加密字符串
Throwable[] throwableArray = ExceptionUtils.getThrowables(e); Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
for (Throwable throwable : throwableArray) { for (Throwable throwable : throwableArray) {
@ -297,34 +302,79 @@ public class FileHandlerService {
* @param outputFilePath pdf输出文件路径 * @param outputFilePath pdf输出文件路径
* @return 转换是否成功 * @return 转换是否成功
*/ */
public String cadToPdf(String inputFilePath, String outputFilePath) throws Exception { public String cadToPdf(String inputFilePath, String outputFilePath ,String cadPreviewType) throws Exception {
File outputFile = new File(outputFilePath); final InterruptionTokenSource source = new InterruptionTokenSource();//CAD延时
LoadOptions opts = new LoadOptions(); Callable<String> call = () -> {
opts.setSpecifiedEncoding(CodePages.SimpChinese); File outputFile = new File(outputFilePath);
com.aspose.cad.Image cadImage = Image.load(inputFilePath, opts); LoadOptions opts = new LoadOptions();
CadRasterizationOptions cadRasterizationOptions = new CadRasterizationOptions(); opts.setSpecifiedEncoding(CodePages.SimpChinese);
cadRasterizationOptions.setBackgroundColor(Color.getWhite()); Image cadImage = Image.load(inputFilePath, opts);
cadRasterizationOptions.setPageWidth(1400); CadRasterizationOptions cadRasterizationOptions = new CadRasterizationOptions();
cadRasterizationOptions.setPageHeight(650); cadRasterizationOptions.setBackgroundColor(Color.getWhite());
cadRasterizationOptions.setAutomaticLayoutsScaling(true); cadRasterizationOptions.setPageWidth(1400);
cadRasterizationOptions.setNoScaling(false); cadRasterizationOptions.setPageHeight(650);
cadRasterizationOptions.setDrawType(1); cadRasterizationOptions.setAutomaticLayoutsScaling(true);
PdfOptions pdfOptions = new PdfOptions(); cadRasterizationOptions.setNoScaling(false);
pdfOptions.setVectorRasterizationOptions(cadRasterizationOptions); cadRasterizationOptions.setDrawType(1);
OutputStream stream = null; SvgOptions SvgOptions = null;
PdfOptions pdfOptions = null;
TiffOptions TiffOptions = null;
switch (cadPreviewType) { //新增格式方法
case "svg":
SvgOptions = new SvgOptions();
SvgOptions.setVectorRasterizationOptions(cadRasterizationOptions);
SvgOptions.setInterruptionToken(source.getToken());
break;
case "pdf":
pdfOptions = new PdfOptions();
pdfOptions.setVectorRasterizationOptions(cadRasterizationOptions);
pdfOptions.setInterruptionToken(source.getToken());
break;
case "tif":
TiffOptions = new TiffOptions(TiffExpectedFormat.TiffJpegRgb);
TiffOptions.setVectorRasterizationOptions(cadRasterizationOptions);
TiffOptions.setInterruptionToken(source.getToken());
break;
}
try (OutputStream stream = new FileOutputStream(outputFile)) {
switch (cadPreviewType) {
case "svg":
cadImage.save(stream, SvgOptions);
break;
case "pdf":
cadImage.save(stream, pdfOptions);
break;
case "tif":
cadImage.save(stream, TiffOptions);
break;
}
} catch (IOException e) {
logger.error("PDFFileNotFoundExceptioninputFilePath{}", inputFilePath, e);
return null;
} finally {
//关闭
if (cadImage != null) { //关闭
cadImage.dispose();
}
source.interrupt(); //结束任务
}
return "true";
};
Future<String> result = pool.submit(call);
try { try {
stream = new FileOutputStream(outputFile); // 如果在超时时间内没有数据返回则抛出TimeoutException异常
cadImage.save(stream, pdfOptions); result.get(Long.parseLong(ConfigConstants.getCadTimeout()), TimeUnit.SECONDS);
} catch (IOException e) { } catch (InterruptedException e) {
logger.error("PDFFileNotFoundExceptioninputFilePath{}", inputFilePath, e); System.out.println("InterruptedException发生");
return "null"; return null;
} catch (ExecutionException e) {
System.out.println("ExecutionException发生");
return null;
} catch (TimeoutException e) {
System.out.println("TimeoutException发生意味着线程超时报错");
return null;
} finally { } finally {
if (stream != null) { //关闭 source.dispose();
stream.close();
}
if (cadImage != null) { //关闭
cadImage.close();
}
} }
return "true"; return "true";
} }

View File

@ -1,5 +1,6 @@
package cn.keking.service; package cn.keking.service;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute; import cn.keking.model.FileAttribute;
import com.sun.star.document.UpdateDocMode; import com.sun.star.document.UpdateDocMode;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -33,15 +34,36 @@ public class OfficeToPdfService {
logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end); logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end);
} }
LocalConverter.Builder builder; LocalConverter.Builder builder;
Map<String, Object> filterData = new HashMap<>();
filterData.put("EncryptFile", true);
if(!ConfigConstants.getOfficePageRange().equals("false")){
filterData.put("PageRange", ConfigConstants.getOfficePageRange()); //限制页面
}
if(!ConfigConstants.getOfficeWatermark().equals("false")){
filterData.put("Watermark", ConfigConstants.getOfficeWatermark()); //水印
}
filterData.put("Quality", ConfigConstants.getOfficeQuality()); //图片压缩
filterData.put("MaxImageResolution", ConfigConstants.getOfficeMaxImageResolution()); //DPI
if(ConfigConstants.getOfficeExportBookmarks()){
filterData.put("ExportBookmarks", true); //导出书签
}
if(ConfigConstants.getOfficeExportNotes()){
filterData.put("ExportNotes", true); //批注作为PDF的注释
}
if(ConfigConstants.getOfficeDocumentOpenPasswords()){
filterData.put("DocumentOpenPassword", fileAttribute.getFilePassword()); //给PDF添加密码
}
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("FilterData", filterData);
if (StringUtils.isNotBlank(fileAttribute.getFilePassword())) { if (StringUtils.isNotBlank(fileAttribute.getFilePassword())) {
Map<String, Object> loadProperties = new HashMap<>(); Map<String, Object> loadProperties = new HashMap<>();
loadProperties.put("Hidden", true); loadProperties.put("Hidden", true);
loadProperties.put("ReadOnly", true); loadProperties.put("ReadOnly", true);
loadProperties.put("UpdateDocMode", UpdateDocMode.NO_UPDATE); loadProperties.put("UpdateDocMode", UpdateDocMode.NO_UPDATE);
loadProperties.put("Password", fileAttribute.getFilePassword()); loadProperties.put("Password", fileAttribute.getFilePassword());
builder = LocalConverter.builder().loadProperties(loadProperties); builder = LocalConverter.builder().loadProperties(loadProperties).storeProperties(customProperties);
} else { } else {
builder = LocalConverter.builder(); builder = LocalConverter.builder().storeProperties(customProperties);
} }
builder.build().convert(inputFile).to(outputFile).execute(); builder.build().convert(inputFile).to(outputFile).execute();
} }

View File

@ -3,17 +3,15 @@ package cn.keking.service.impl;
import cn.keking.config.ConfigConstants; import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute; import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse; import cn.keking.model.ReturnResponse;
import cn.keking.service.FileHandlerService;
import cn.keking.service.FilePreview; import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils; import cn.keking.utils.DownloadUtils;
import cn.keking.service.FileHandlerService;
import cn.keking.utils.KkFileUtils; import cn.keking.utils.KkFileUtils;
import cn.keking.web.filter.BaseUrlFilter; import cn.keking.web.filter.BaseUrlFilter;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.List;
import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType; import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
/** /**
@ -43,7 +41,8 @@ public class CadFilePreviewImpl implements FilePreview {
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); boolean forceUpdatedCache=fileAttribute.forceUpdatedCache();
String fileName = fileAttribute.getName(); String fileName = fileAttribute.getName();
String suffix = fileAttribute.getSuffix(); String suffix = fileAttribute.getSuffix();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix +"." + "pdf" ; //生成文件添加类型后缀 防止同名文件 String cadPreviewType = ConfigConstants.getCadPreviewType();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix +"." + cadPreviewType ; //生成文件添加类型后缀 防止同名文件
String outFilePath = FILE_DIR + pdfName; String outFilePath = FILE_DIR + pdfName;
// 判断之前是否已转换过如果转换过直接返回否则执行转换 // 判断之前是否已转换过如果转换过直接返回否则执行转换
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) { if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
@ -56,7 +55,7 @@ public class CadFilePreviewImpl implements FilePreview {
String imageUrls = null; String imageUrls = null;
if (StringUtils.hasText(outFilePath)) { if (StringUtils.hasText(outFilePath)) {
try { try {
imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath); imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath,cadPreviewType);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -73,12 +72,17 @@ public class CadFilePreviewImpl implements FilePreview {
} }
} }
} }
if("tif".equalsIgnoreCase(cadPreviewType)){
model.addAttribute("currentUrl", pdfName);
return TIFF_FILE_PREVIEW_PAGE;
}else if("svg".equalsIgnoreCase(cadPreviewType)){
model.addAttribute("currentUrl", pdfName);
return SVG_FILE_PREVIEW_PAGE;
}
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) { if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview); return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview);
} }
model.addAttribute("pdfUrl", pdfName); model.addAttribute("pdfUrl", pdfName);
return PDF_FILE_PREVIEW_PAGE; return PDF_FILE_PREVIEW_PAGE;
} }
} }

View File

@ -6,7 +6,6 @@ import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview; import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils; import cn.keking.utils.DownloadUtils;
import cn.keking.service.FileHandlerService; import cn.keking.service.FileHandlerService;
import cn.keking.web.filter.BaseUrlFilter;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -37,7 +36,6 @@ public class PdfFilePreviewImpl implements FilePreview {
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileName = fileAttribute.getName(); String fileName = fileAttribute.getName();
String officePreviewType = fileAttribute.getOfficePreviewType(); String officePreviewType = fileAttribute.getOfficePreviewType();
String baseUrl = BaseUrlFilter.getBaseUrl();
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); boolean forceUpdatedCache=fileAttribute.forceUpdatedCache();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf"; String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
String outFilePath = FILE_DIR + pdfName; String outFilePath = FILE_DIR + pdfName;

View File

@ -124,11 +124,15 @@ public class DownloadUtils {
if (!dirFile.exists() && !dirFile.mkdirs()) { if (!dirFile.exists() && !dirFile.mkdirs()) {
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir); logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
} }
// 文件已在本地存在跳过文件下载 Boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
File realFile = new File(realPath); //判断是否启用强制更新功能如果启用 文件必须重新下载
if (realFile.exists()) { if (null == forceUpdatedCache || !forceUpdatedCache) {
fileAttribute.setSkipDownLoad(true); // 文件已在本地存在跳过文件下载
return "cunzhai"; File realFile = new File(realPath);
if (realFile.exists()) {
fileAttribute.setSkipDownLoad(true);
return "cunzhai"; //这里给的值是不能修改的 对应的是下载方法里面有个强制输出地址的
}
} }
return realPath; return realPath;
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
package cn.keking.utils;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class RandomValidateCodeUtil {
private static final int width = 100;// 定义图片的width
private static final int height = 30;// 定义图片的height
private static final int codeCount = 4;// 定义图片上显示验证码的个数
private static final int xx = 18;
private static final int fontHeight = 28;
private static final int codeY = 27;
private static final char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R','T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a','b','c','d','e','f','g','h','j','k','m','n','p','q','r','s','t','u','v','w','x','y', '2', '3', '4','5', '6', '7', '8', '9' };
/**
* 生成一个map集合
* code为生成的验证码
* codePic为生成的验证码BufferedImage对象
*/
public static Map<String,Object> generateCodeAndPic(String ip, String sessionCode, int lx) {
// 定义图像buffer
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics2D gd = buffImg.createGraphics();
// Graphics2D gd = (Graphics2D) buffImg.getGraphics();
Graphics gd = buffImg.getGraphics();
// 创建一个随机数生成器类
Random random = new Random();
// 将图像填充为白色
gd.setColor(Color.WHITE);
gd.fillRect(0, 0, width, height);
// 创建字体字体的大小应该根据图片的高度来定
Font font = new Font("Times New Roman", Font.BOLD, fontHeight);
// 设置字体
gd.setFont(font);
// 画边框
gd.setColor(Color.BLACK);
gd.drawRect(0, 0, width - 1, height - 1);
// 随机产生40条干扰线使图象中的认证码不易被其它程序探测到
gd.setColor(Color.BLACK);
for (int i = 0; i < 30; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
gd.drawLine(x, y, x + xl, y + yl);
}
StringBuffer randomCode = new StringBuffer();
Map<String,Object> map = new HashMap<>();
// randomCode用于保存随机产生的验证码以便用户登录后进行验证
int red, green, blue;
if (lx ==1){
// 产生随机的颜色分量来构造颜色值这样输出的每位数字的颜色值都将不同
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
// 用随机产生的颜色将验证码绘制到图像中
gd.setColor(new Color(red, green, blue));
gd.drawString(sessionCode, 18, codeY);
randomCode.append(sessionCode);
}else {
// 随机产生codeCount数字的验证码
for (int i = 0; i < codeCount; i++) {
// 得到随机产生的验证码数字
String code = String.valueOf(codeSequence[random.nextInt(52)]);
// 产生随机的颜色分量来构造颜色值这样输出的每位数字的颜色值都将不同
red = random.nextInt(255);
green = random.nextInt(255);
blue = random.nextInt(255);
// 用随机产生的颜色将验证码绘制到图像中
gd.setColor(new Color(red, green, blue));
gd.drawString(code, (i + 1) * xx, codeY);
// 将产生的四个随机数组合在一起
randomCode.append(code);
}
}
//存放验证码
map.put("code", randomCode);
//存放生成的验证码BufferedImage对象
map.put("codePic", buffImg);
return map;
}
}

View File

@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -59,15 +60,28 @@ public class FileController {
} }
@GetMapping("/deleteFile") @GetMapping("/deleteFile")
public ReturnResponse<Object> deleteFile(String fileName,String password) { public ReturnResponse<Object> deleteFile(HttpServletRequest request, String fileName, String password) {
ReturnResponse<Object> checkResult = this.deleteFileCheck(fileName); ReturnResponse<Object> checkResult = this.deleteFileCheck(fileName);
if (checkResult.isFailure()) { if (checkResult.isFailure()) {
return checkResult; return checkResult;
} }
fileName = checkResult.getContent().toString(); fileName = checkResult.getContent().toString();
if(!ConfigConstants.getPassword().equalsIgnoreCase(password)) { if(ConfigConstants.getDeleteCaptcha()){
logger.error("删除文件【{}】失败,密码错误!",fileName); String sessionCode;
return ReturnResponse.failure("删除文件失败,密码错误!"); try {
sessionCode = request.getSession().getAttribute("code").toString(); //获取已经保存的验证码
} catch (Exception e) {
sessionCode = "null";
}
if (password==null || !sessionCode.equalsIgnoreCase(password)){
logger.error("删除文件【{}】失败,密码错误!",fileName);
return ReturnResponse.failure("删除文件失败,密码错误!");
}
}else {
if(password==null || !ConfigConstants.getPassword().equalsIgnoreCase(password)) {
logger.error("删除文件【{}】失败,密码错误!",fileName);
return ReturnResponse.failure("删除文件失败,密码错误!");
}
} }
File file = new File(fileDir + demoPath + fileName); File file = new File(fileDir + demoPath + fileName);
logger.info("删除文件:{}", file.getAbsolutePath()); logger.info("删除文件:{}", file.getAbsolutePath());
@ -76,6 +90,7 @@ public class FileController {
logger.error(msg); logger.error(msg);
return ReturnResponse.failure(msg); return ReturnResponse.failure(msg);
} }
request.getSession().removeAttribute("code"); //删除缓存验证码
return ReturnResponse.success(); return ReturnResponse.success();
} }

View File

@ -1,5 +1,6 @@
package cn.keking.web.controller; package cn.keking.web.controller;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute; import cn.keking.model.FileAttribute;
import cn.keking.service.FileHandlerService; import cn.keking.service.FileHandlerService;
import cn.keking.service.FilePreview; import cn.keking.service.FilePreview;
@ -7,6 +8,7 @@ import cn.keking.service.FilePreviewFactory;
import cn.keking.service.cache.CacheService; import cn.keking.service.cache.CacheService;
import cn.keking.service.impl.OtherFilePreviewImpl; import cn.keking.service.impl.OtherFilePreviewImpl;
import cn.keking.utils.KkFileUtils; import cn.keking.utils.KkFileUtils;
import cn.keking.utils.RandomValidateCodeUtil;
import cn.keking.utils.WebUtils; import cn.keking.utils.WebUtils;
import fr.opensagres.xdocreport.core.io.IOUtils; import fr.opensagres.xdocreport.core.io.IOUtils;
import io.mola.galimatias.GalimatiasParseException; import io.mola.galimatias.GalimatiasParseException;
@ -15,18 +17,26 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.awt.image.RenderedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE; import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE;
@ -160,6 +170,82 @@ public class OnlinePreviewController {
} }
} }
} }
/**
* 验证码方法
*/
@RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
if(!ConfigConstants.getDeleteCaptcha()){
return;
}
response.setContentType("image/gif");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
Date date = new Date(); // 当前时间
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置时间格式
String sessionCode;
try {
sessionCode = request.getSession().getAttribute("code").toString(); //获取已经保存的验证码
} catch (Exception e) {
sessionCode= null;
}
Object time = request.getSession().getAttribute("time"); //获取已经保存的时间
if (ObjectUtils.isEmpty(time)){ //判断时间是否为空
request.getSession().setAttribute("time", formater.format(date)); //为空重新添加缓存时间
time = request.getSession().getAttribute("time");
}
Date joinTime = formater.parse(String.valueOf(time));
String dateStart = formater.format(joinTime);
Date d1=formater.parse(dateStart);
// 时间差
long diff = date.getTime() - d1.getTime();
long diffSeconds = diff / 1000 % 60;
String ip=request.getRemoteAddr();
ServletOutputStream sos = null;
if (ObjectUtils.isEmpty(sessionCode) || diffSeconds > 50){ //判断验证码是否为空 为空重新生成 判断是否在有效时间内 默认50秒
Map<String, Object> codeMap = RandomValidateCodeUtil.generateCodeAndPic(ip,sessionCode,0);
// 验证码存入session
request.getSession().setAttribute("code", codeMap.get("code").toString());
// 时间存入session
request.getSession().setAttribute("time", formater.format(date));
// 禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setContentType("image/jpeg");
// 将图像输出到Servlet输出流中
try {
sos = response.getOutputStream();
ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos);
} catch (IOException e) {
e.printStackTrace();
} finally {
assert sos != null;
sos.close();
}
}else {
// System.out.println("请输入你的姓名:");
Map<String, Object> codeMap = RandomValidateCodeUtil.generateCodeAndPic(ip,sessionCode,1);
// 禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setContentType("image/jpeg");
// 将图像输出到Servlet输出流中
try {
sos = response.getOutputStream();
ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos);
} catch (IOException e) {
e.printStackTrace();
} finally {
assert sos != null;
sos.close();
}
}
}
/** /**
* 通过api接口入队 * 通过api接口入队

View File

@ -42,6 +42,7 @@ public class AttributeSetFilter implements Filter {
request.setAttribute("fileUploadDisable", ConfigConstants.getFileUploadDisable()); request.setAttribute("fileUploadDisable", ConfigConstants.getFileUploadDisable());
request.setAttribute("beian", ConfigConstants.getBeian()); request.setAttribute("beian", ConfigConstants.getBeian());
request.setAttribute("size", ConfigConstants.maxSize()); request.setAttribute("size", ConfigConstants.maxSize());
request.setAttribute("deleteCaptcha", ConfigConstants.getDeleteCaptcha());
} }
/** /**

View File

@ -7,7 +7,7 @@
|_|\_\ |_|\_\ |_| |_| |_| \___| \/ |_| \___| \_/\_/ |_|\_\ |_|\_\ |_| |_| |_| \___| \/ |_| \___| \_/\_/
=> Spring Boot :: ${spring-boot.version} => Spring Boot :: ${spring-boot.version}
=> kkFileView :: 4.3.0 => kkFileView :: 4.4.0-SNAPSHOT
=> Home site :: https://kkview.cn => Home site :: https://kkview.cn
=> Github :: https://github.com/kekingcn/kkFileView => Github :: https://github.com/kekingcn/kkFileView
=> Gitee :: https://gitee.com/kekingcn/file-online-preview => Gitee :: https://gitee.com/kekingcn/file-online-preview

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -6450,7 +6450,34 @@ window.sheetConditionFormat = {
"conditionName": "occurrenceDate", "conditionName": "occurrenceDate",
"conditionRange": [], "conditionRange": [],
"conditionValue": ["2020/07/23 - 2020/07/29"] "conditionValue": ["2020/07/23 - 2020/07/29"]
}, { },{
"type": "default",
"cellrange": [{
"row": [10, 19],
"column": [0, 0]
}],
"format": {
"textColor": "#000000",
"cellColor": "#ff0000"
},
"conditionName": "regExp",
"conditionRange": [],
"conditionValue": [/^\d{1,}\.\d{1,}$/]
},{
"type": "default",
"cellrange": [{
"row": [0, 9],
"column": [0, 0]
}],
"format": {
"textColor": "#000000",
"cellColor": "#ff0000"
},
"conditionName": "sort",
"conditionRange": [],
"conditionValue": ['desc']
},
{
"type": "colorGradation", "type": "colorGradation",
"cellrange": [{ "cellrange": [{
"left": 422, "left": 422,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,46 @@
.luckysheet-print span[role="heading"] {
font-size: 30px;
font-weight: bold;
}
.luckysheet-print-suggest {
font-size: 12px;
}
.luckysheet-print-title {
font-weight: bold;
font-size: 18px;
}
.luckysheet-print-radio {
display: flex;
}
.luckysheet-print-radio > div {
width: 50%;
}
.luckysheet-print select {
height: 30px;
}
.luckysheet-print .luckysheet-modal-dialog-buttons {
display: flex;
flex-direction: row-reverse;
}
.luckysheet-print-box canvas {
display: block;
}
@media print {
:not(html, head, body, .luckysheet-print-preview, .luckysheet-print-preview *) {
display: none;
}
.luckysheet-print-break {
page-break-after: always;
}
#print-layout-options {
display: none;
}
}

View File

@ -2,13 +2,14 @@
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Hello xlsx!</title> <title>xlsx在线预览</title>
<link rel='stylesheet' href='plugins/css/pluginsCss.css' /> <link rel='stylesheet' href='plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='plugins/plugins.css' /> <link rel='stylesheet' href='plugins/plugins.css' />
<link rel='stylesheet' href='css/luckysheet.css' /> <link rel='stylesheet' href='css/luckysheet.css' />
<link rel='stylesheet' href='assets/iconfont/iconfont.css' /> <link rel='stylesheet' href='assets/iconfont/iconfont.css' />
<script src="plugins/js/plugin.js"></script> <script src="plugins/js/plugin.js"></script>
<script src="luckysheet.umd.js"></script> <script src="luckysheet.umd.js"></script>
<script src="../js/base64.min.js" type="text/javascript"></script>
</head> </head>
<body> <body>
<div id="lucky-mask-demo" style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">Downloading</div> <div id="lucky-mask-demo" style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">Downloading</div>
@ -17,56 +18,67 @@
<div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 50px;bottom: 0px;outline: none;"></div> <div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 50px;bottom: 0px;outline: none;"></div>
<script src="luckyexcel.umd.js"></script> <script src="luckyexcel.umd.js"></script>
<script> <script>
function demoHandler(){ let str =location.search;
let search =str.substr(1);
//console.log(search);
search = Base64.decode(decodeURIComponent(search));
// console.log(search);
let mask = document.getElementById("lucky-mask-demo"); let mask = document.getElementById("lucky-mask-demo");
function loadText() {
window.onload = () => { var value = search;
var value = 'kex.xlsx'; var name = 'xlsx.xlsx';
var name = 'xlsx';
if(value==""){ if(value==""){
return; return;
} }
// mask.style.display = "flex"; // mask.style.display = "flex";
LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile){ LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile){
if(exportJson.sheets==null || exportJson.sheets.length==0){ if(exportJson.sheets==null || exportJson.sheets.length==0){
alert("Failed to read the content of the excel file, currently does not support xls files!"); alert("读取excel文件内容失败!");
return; return;
} }
// console.log(exportJson, luckysheetfile);
mask.style.display = "none"; mask.style.display = "none";
window.luckysheet.destroy(); window.luckysheet.destroy();
window.luckysheet.create({ window.luckysheet.create({
container: 'luckysheet', //luckysheet is the container id container: 'luckysheet', //luckysheet is the container id
lang: "zh", lang: "zh",
showtoolbarConfig:{
image: true,
print: false, //关闭打印按钮 启用也不能用 等以后看情况而定
exportXlsx: false, //关闭导出按钮 启用也不能用 等以后看情况而定
},
allowCopy: true, // 是否允许拷贝 allowCopy: true, // 是否允许拷贝
showtoolbar: true, // 是否显示工具栏 showtoolbar: true, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏 showinfobar: false, // 是否显示顶部信息栏
// myFolderUrl: "/",//作用左上角<返回按钮的链接
showsheetbar: true, // 是否显示底部sheet页按钮 showsheetbar: true, // 是否显示底部sheet页按钮
showstatisticBar: true, // 是否显示底部计数栏 showstatisticBar: true, // 是否显示底部计数栏
sheetBottomConfig: false, // sheet页下方的添加行按钮和回到顶部按钮配置 sheetBottomConfig: true, // sheet页下方的添加行按钮和回到顶部按钮配置
allowEdit: true, // 是否允许前台编辑 allowEdit: true, // 是否允许前台编辑
enableAddRow: false, // 允许增加行 enableAddRow: false, // 允许增加行
enableAddCol: false, // 允许增加列 enableAddCol: false, // 允许增加列
userInfo: false, // 右上角的用户信息展示样式 userInfo: false, // 右上角的用户信息展示样式
showRowBar: true, // 是否显示行号区域 showRowBar: true, // 是否显示行号区域
showColumnBar: false, // 是否显示列号区域 showColumnBar: false, // 是否显示列号区域
sheetFormulaBar: true, // 是否显示公式栏 sheetFormulaBar: false, // 是否显示公式栏
enableAddBackTop: true,//返回头部按钮 enableAddBackTop: true,//返回头部按钮
forceCalculation: false, //下面是导出插件 默认关闭
enableAddRow: false, // 允许增加行
plugins: [{ name: 'chart' }, { name: 'exportXlsx', config: { url: 'luckyToXlsx' } }, {
name: 'print', config: {
license: ''
}
}],
data:exportJson.sheets, data:exportJson.sheets,
title:exportJson.info.name, title:exportJson.info.name,
userInfo:exportJson.info.name.creator userInfo:exportJson.info.name.creator
}); });
}); });
} }
} loadText();
demoHandler();
</script> </script>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -22,6 +22,39 @@
width: 50%; width: 50%;
} }
</style> </style>
<#-- 删除吗CSS样式 -->
<#if deleteCaptcha >
<style>
.code{
position: fixed;
width: 300px;
height: 200px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background-color: #F0FFF0;
text-align: center;
padding: 20px;
z-index: 100002;
}
.close{
margin-top: 20px;
}
.code-input{
border: 1px solid #ccc;
border-radius: 3px;
width: 110px;
height: 40px;
}
.code-input:focus{
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
}
</style>
</#if>
</head> </head>
<body> <body>
@ -111,6 +144,10 @@
</form> </form>
</div> </div>
</div> </div>
<#-- 删除吗弹窗 -->
<#if deleteCaptcha >
<div id="codeContent"> </div>
</#if>
<#-- 预览测试 --> <#-- 预览测试 -->
<div class="panel panel-success"> <div class="panel panel-success">
<div class="panel-heading"> <div class="panel-heading">
@ -162,13 +199,82 @@
</div> </div>
</#if> </#if>
<script> <script>
<#if deleteCaptcha >
function deleteFile(fileName) {
var codename =`<div class="code"><h4>请输入下面删除码!</h4><div><img id="verImg" width="130px" height="48px" src="/captcha"></div><form><input type="type" oninput="if(value.length>5)value=value.slice(0,5);" class="code-input" id="_code" placeholder="请输入验证码"><button id="deleteFile1" type="button" class="btn btn-success">提交</button></form><button id="close" type="button"class="btn btn-danger">关闭</button></div>`;
$('#codeContent').html(codename);
var code = document.querySelector('.code');
var closeBtn = document.getElementById("close");
closeBtn.addEventListener('click', hidePopup);
function hidePopup(){
code.style.display = 'none';
}
var closedelete = document.getElementById("deleteFile1");
closedelete.addEventListener('click', deleteFile1);
function deleteFile1(){
var password = $("#_code").val();
//console.log(password);
$.ajax({
url: '${baseUrl}deleteFile?fileName=' + fileName +'&password='+password,
success: function (data) {
// console.log(data);
// 删除完成刷新table
if ("删除文件失败,密码错误!" === data.msg) {
alert(data.msg);
} else {
$('#table').bootstrapTable('refresh', {});
code.style.display = 'none';
}
},
error: function (data) {
return false;
}
})
}
var windowUrl = window.URL || window.webkitURL; //处理浏览器兼容性
document.getElementById('verImg').onclick = function(e){
//1创建ajax对象
var xhr = null;
try{
xhr = new XMLHttpRequest();
}catch(error){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//2调用open
xhr.open("get", "/captcha", true);
xhr.responseType = "blob";
//3调用send
xhr.send();
//4等待数据响应
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
//判断本次下载的状态码都是多少
if(xhr.status == 200){
var blob = this.response;
$("#verImg").attr("src",windowUrl.createObjectURL(blob));
//$('#verImg').attr('src', xhr.responseText);
// alert(windowUrl.createObjectURL(blob));
}else{
alert("Error:" + xhr.status);
}
}
}
}
}
<#else>
function deleteFile(fileName,password) { function deleteFile(fileName,password) {
if(window.confirm('你确定要删除文件吗')){ if(window.confirm('你确定要删除文件吗')){
<#if deleteCaptcha >
password = prompt("请输入获取的验证码:");
<#else>
password = prompt("请输入默认密码:123456"); password = prompt("请输入默认密码:123456");
</#if>
$.ajax({ $.ajax({
url: '${baseUrl}deleteFile?fileName=' + fileName +'&password='+password, url: '${baseUrl}deleteFile?fileName=' + fileName +'&password='+password,
success: function (data) { success: function (data) {
// console.log(data); // console.log(data);
// 删除完成刷新table // 删除完成刷新table
if ("删除文件失败,密码错误!" === data.msg) { if ("删除文件失败,密码错误!" === data.msg) {
alert(data.msg); alert(data.msg);
@ -185,6 +291,7 @@
} }
} }
</#if>
function showLoadingDiv() { function showLoadingDiv() {
var height = window.document.documentElement.clientHeight - 1; var height = window.document.documentElement.clientHeight - 1;

View File

@ -1,28 +1,28 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>${file.name}预览</title> <title>${file.name}预览</title>
<link rel='stylesheet' href='xlsx/plugins/css/pluginsCss.css' /> <link rel='stylesheet' href='xlsx/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='xlsx/plugins/plugins.css' /> <link rel='stylesheet' href='xlsx/plugins/plugins.css' />
<link rel='stylesheet' href='xlsx/css/luckysheet.css' /> <link rel='stylesheet' href='xlsx/css/luckysheet.css' />
<link rel='stylesheet' href='xlsx/assets/iconfont/iconfont.css' /> <link rel='stylesheet' href='xlsx/assets/iconfont/iconfont.css' />
<script src="xlsx/plugins/js/plugin.js"></script> <script src="xlsx/plugins/js/plugin.js"></script>
<script src="xlsx/luckysheet.umd.js"></script> <script src="xlsx/luckysheet.umd.js"></script>
<script src="js/watermark.js" type="text/javascript"></script> <script src="js/watermark.js" type="text/javascript"></script>
<script src="js/base64.min.js" type="text/javascript"></script> <script src="js/base64.min.js" type="text/javascript"></script>
</head> </head>
<#if pdfUrl?contains("http://") || pdfUrl?contains("https://") || pdfUrl?contains("ftp://")> <#if pdfUrl?contains("http://") || pdfUrl?contains("https://") || pdfUrl?contains("ftp://")>
<#assign finalUrl="${pdfUrl}"> <#assign finalUrl="${pdfUrl}">
<#else> <#else>
<#assign finalUrl="${baseUrl}${pdfUrl}"> <#assign finalUrl="${baseUrl}${pdfUrl}">
</#if> </#if>
<script> <script>
/** /**
* 初始化水印 * 初始化水印
*/ */
function initWaterMark() { function initWaterMark() {
let watermarkTxt = '${watermarkTxt}'; let watermarkTxt = '${watermarkTxt}';
if (watermarkTxt !== '') { if (watermarkTxt !== '') {
watermark.init({ watermark.init({
@ -57,89 +57,89 @@
} }
</style> </style>
<body> <body>
<div id="lucky-mask-demo" style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">加载中</div> <div id="lucky-mask-demo" style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">加载中</div>
<p style="text-align:center;"> <p style="text-align:center;">
<div id="button-area"> <div id="button-area">
<label><button onclick="tiaozhuan()">跳转HTML预览</button></label> <label><button onclick="tiaozhuan()">跳转HTML预览</button></label>
<button id="confirm-button" onclick="print()">打印</button> <button id="confirm-button" onclick="print()">打印</button>
</div> </div>
<div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 20px;bottom: 0px;outline: none;"></div> <div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 20px;bottom: 0px;outline: none;"></div>
<script src="xlsx/luckyexcel.umd.js"></script> <script src="xlsx/luckyexcel.umd.js"></script>
<script> <script>
function tiaozhuan(){ function tiaozhuan(){
var test = window.location.href; var test = window.location.href;
test = test.replace(new RegExp("&officePreviewType=xlsx",("gm")),""); test = test.replace(new RegExp("&officePreviewType=xlsx",("gm")),"");
test = test+'&officePreviewType=html'; test = test+'&officePreviewType=html';
   window.location.href=test; window.location.href=test;
   } }
var url = '${finalUrl}'; var url = '${finalUrl}';
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/'; var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
if (!url.startsWith(baseUrl)) { if (!url.startsWith(baseUrl)) {
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url)); url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url));
} }
let mask = document.getElementById("lucky-mask-demo"); let mask = document.getElementById("lucky-mask-demo");
function loadText() {
function loadText() { initWaterMark(); // 是否显示水印
initWaterMark(); // 是否显示水印 var value = url;
var value = url; var name = '${file.name}';
var name = '${file.name}'; if(value==""){
if(value==""){ return;
return;
}
// mask.style.display = "flex";
LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile){
if(exportJson.sheets==null || exportJson.sheets.length==0){
alert("读取excel文件内容失败!");
return;
}
// console.log(exportJson.sheets);
mask.style.display = "none";
window.luckysheet.destroy();
window.luckysheet.create({
container: 'luckysheet', //luckysheet is the container id
lang: "zh",
showtoolbarConfig:{
image: true,
print: false,
},
hook:{
onTogglePager:function(range){
// range.data = exportJson.sheets
},
},
allowCopy: true, // 是否允许拷贝
showtoolbar: true, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏
// myFolderUrl: "/",//作用左上角<返回按钮的链接
showsheetbar: true, // 是否显示底部sheet页按钮
showstatisticBar: true, // 是否显示底部计数栏
sheetBottomConfig: true, // sheet页下方的添加行按钮和回到顶部按钮配置
allowEdit: true, // 是否允许前台编辑
enableAddRow: false, // 允许增加行
enableAddCol: false, // 允许增加列
userInfo: false, // 右上角的用户信息展示样式
showRowBar: true, // 是否显示行号区域
showColumnBar: false, // 是否显示列号区域
sheetFormulaBar: false, // 是否显示公式栏
enableAddBackTop: true,//返回头部按钮
data:exportJson.sheets,
title:exportJson.info.name,
plugins: ['chart'],
userInfo:exportJson.info.name.creator
});
});
}
loadText();
// 打印时获取luckysheet指定区域html内容拼接至div隐藏luckysheet容器并显示打印区域html
function to_print() {
const html = luckysheet.getRangeHtml();
document.querySelector('#print-html').innerHTML = html;
document.querySelector('#print-area').style.display = 'block';
document.querySelector('#button-area').style.display = 'none';
} }
</script> // mask.style.display = "flex";
</body> LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile){
if(exportJson.sheets==null || exportJson.sheets.length==0){
alert("读取excel文件内容失败!");
return;
}
mask.style.display = "none";
window.luckysheet.destroy();
window.luckysheet.create({
container: 'luckysheet', //luckysheet is the container id
lang: "zh",
showtoolbarConfig:{
image: true,
print: false, //关闭打印按钮 启用也不能用 等以后看情况而定
exportXlsx: false, //关闭导出按钮 启用也不能用 等以后看情况而定
},
allowCopy: true, // 是否允许拷贝
showtoolbar: true, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏
// myFolderUrl: "/",//作用左上角<返回按钮的链接
showsheetbar: true, // 是否显示底部sheet页按钮
showstatisticBar: true, // 是否显示底部计数栏
sheetBottomConfig: true, // sheet页下方的添加行按钮和回到顶部按钮配置
allowEdit: true, // 是否允许前台编辑
enableAddRow: false, // 允许增加行
enableAddCol: false, // 允许增加列
userInfo: false, // 右上角的用户信息展示样式
showRowBar: true, // 是否显示行号区域
showColumnBar: false, // 是否显示列号区域
sheetFormulaBar: false, // 是否显示公式栏
enableAddBackTop: true,//返回头部按钮
forceCalculation: false, //下面是导出插件 默认关闭
enableAddRow: false, // 允许增加行
plugins: [{ name: 'chart' }, { name: 'exportXlsx', config: { url: 'luckyToXlsx' } }, {
name: 'print', config: {
license: ''
}
}],
data:exportJson.sheets,
title:exportJson.info.name,
userInfo:exportJson.info.name.creator
});
});
}
loadText();
// 打印时获取luckysheet指定区域html内容拼接至div隐藏luckysheet容器并显示打印区域html
function to_print() {
const html = luckysheet.getRangeHtml();
document.querySelector('#print-html').innerHTML = html;
document.querySelector('#print-area').style.display = 'block';
document.querySelector('#button-area').style.display = 'none';
}
</script>
</body>
</html> </html>

View File

@ -0,0 +1,28 @@
package cn.keking;
import cn.keking.utils.EncodingDetects;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.net.URISyntaxException;
/**
* 编码检测测试类
*
* @author asiawu3
* @create 2023-07-24 16:53
**/
@SpringBootTest
public class EncodingTests {
@Test
void testCharDet() throws URISyntaxException {
for (int i = 0; i < 28; i++) {
File dir = new File(getClass().getClassLoader().getResource("testData\\" + i).toURI());
String dirPath = dir.getPath();
String textFileName = dir.list()[0];
String textFilePath = dirPath + "/" + textFileName;
System.out.printf("%-15s -->\t %-10s\n", textFileName, EncodingDetects.getJavaEncode(textFilePath));
}
}
}

View File

@ -4,10 +4,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest @SpringBootTest
class ServerMainTests { class ServerMainTests {
@Test @Test
void contextLoads() { void contextLoads() {
} }
} }

View File

@ -0,0 +1 @@
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

View File

@ -0,0 +1 @@
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

View File

@ -0,0 +1 @@
ポリシーパターンは、一連のアルゴリズムを定義し、それぞれのアルゴリズムをパッケージ化して相互に置換できるようにし、アルゴリズムの変化は、アルゴリズムを使用する顧客に影響を与えません。ポリシーパターンは、アルゴリズムをカプセル化することで、アルゴリズムを使用する責任とアルゴリズムを実装する責任を分離し、アルゴリズムの管理を異なるオブジェクトに委ねます。

View File

@ -0,0 +1 @@
정책 모델은 알고리즘의 집합을 정의하며, 각각의 알고리즘은 변경되지 않고 변경될 수 있도록 패키지된다.정책 모델은 객체 행동 모델에 속하며, 알고리즘의 사용과 구현에 대한 책임을 분리하여 알고리즘을 관리하기 위해 다른 객체들에게 위임한다.

View File

@ -0,0 +1 @@
Стратегическая модель определяет ряд алгоритмов и запечатывает каждый из них, чтобы они могли быть заменены друг на друга, и изменения алгоритма не влияют на клиентов, которые используют алгоритм. Стратегическая модель относится к модели поведения объекта, которая разделяет ответственность за использование алгоритма и реализацию алгоритма путем инжинизации алгоритма и поручает управление этим алгоритмам различным объектам.

View File

@ -0,0 +1 @@
Le schéma de politique définit une série d?algorithmes et encapsule chacun de manière à ce qu?ils puissent être remplacés les uns par les autres et que les changements d?algorithmes n?affectent pas les clients qui utilisent l?algorithme. Le mode de politique appartient au mode de comportement des objets. Il scinde la responsabilité de l?utilisation de l?algorithme et de sa mise en ?uvre en encapsulant l?algorithme et en déléguant la gestion de ces algorithmes à différents objets.

View File

@ -0,0 +1 @@
Wzorzec strategii definiuje serię algorytmów i hermetyzuje każdy algorytm, dzięki czemu można je zastąpić sobą, a zmiana algorytmu nie wpłynie na klientów korzystających z algorytmu. Wzorzec strategii należy do wzorca zachowania obiektu, zawiera w sobie algorytm, oddziela odpowiedzialność za użycie algorytmu od implementacji algorytmu i deleguje różne obiekty do zarządzania tymi algorytmami.

View File

@ -0,0 +1 @@
Strateji modeli, bir dizi algoritmay¹ tan¹mlar ve her bir algoritmay¹ kendi aralar¹nda de»iºtirilebilecek ºekilde kapsüller ve algoritma de»iºikli»i, algoritmay¹ kullanan müºterileri etkilemez. Strateji kal¹b¹, nesne davran¹º kal¹b¹na aittir, algoritmay¹ kapsar, algoritmay¹ kullanma sorumlulu»unu algoritman¹n gerçekleºtirilmesinden ay¹r¹r ve bu algoritmalar¹ yönetmek için farkl¹ nesnelere yetki verir.

View File

@ -0,0 +1 @@
Strateegiamuster määratleb algoritmide seeria ja kapseldab iga algoritmi nii, et neid saaks üksteisega asendada ning algoritmi muutmine ei mõjuta algoritmi kasutavaid kliente. Strateegiamuster kuulub objekti käitumismustrisse, mis kapseldab algoritmi, eraldab algoritmi kasutamise vastutuse algoritmi realiseerimisest ja delegeerib erinevatele objektidele nende algoritmide haldamise.

View File

@ -0,0 +1 @@
Шаблон стратегии определяет ряд алгоритмов и инкапсулирует каждый алгоритм, чтобы их можно было заменить друг другом, а изменение алгоритма не повлияет на клиентов, которые его используют. Паттерн стратегии относится к паттерну поведения объекта, инкапсулирует алгоритм, отделяет ответственность за использование алгоритма от реализации алгоритма и делегирует управление этими алгоритмами разным объектам.

View File

@ -0,0 +1 @@
يحدد نمط الإستراتيجية سلسلة من الخوارزميات ويغلف كل خوارزمية بحيث يمكن استبدالها ببعضها البعض ، ولن يؤثر تغيير الخوارزمية على العملاء الذين يستخدمون الخوارزمية. ينتمي نمط الإستراتيجية إلى نمط سلوك الكائن ، حيث يقوم بتغليف الخوارزمية ، ويفصل مسؤولية استخدام الخوارزمية عن تحقيق الخوارزمية ، ويفوض إلى كائنات مختلفة لإدارة هذه الخوارزميات.

View File

@ -0,0 +1 @@
Το μοτίβο στρατηγικής ορίζει μια σειρά από αλγόριθμους και ενσωματώνει κάθε αλγόριθμο έτσι ώστε να μπορούν να αντικατασταθούν μεταξύ τους και η αλλαγή του αλγορίθμου δεν θα επηρεάσει τους πελάτες που χρησιμοποιούν τον αλγόριθμο. Το μοτίβο στρατηγικής ανήκει στο μοτίβο συμπεριφοράς αντικειμένου.Ενθυλακώνει τον αλγόριθμο, διαχωρίζει την ευθύνη χρήσης του αλγορίθμου από την υλοποίηση του αλγορίθμου και αναθέτει σε διαφορετικά αντικείμενα τη διαχείριση αυτών των αλγορίθμων.

Binary file not shown.

View File

@ -0,0 +1 @@
דפוס האסטרטגיה מגדיר סדרה של אלגוריתמים ומעטף כל אלגוריתם כך שניתן להחליפם זה בזה, ושינוי האלגוריתם לא ישפיע על הלקוחות המשתמשים באלגוריתם. דפוס האסטרטגיה שייך לדפוס התנהגות האובייקט, הוא מקפל את האלגוריתם, מפריד בין אחריות השימוש באלגוריתם לבין יישום האלגוריתם ומאציל לאובייקטים שונים לנהל את האלגוריתמים הללו.

View File

@ -0,0 +1 @@
Strateji modeli, bir dizi algoritmayı tanımlar ve her bir algoritmayı kendi aralarında değiştirilebilecek şekilde kapsüller ve algoritma değişikliği, algoritmayı kullanan müşterileri etkilemez. Strateji kalıbı, nesne davranış kalıbına aittir, algoritmayı kapsar, algoritmayı kullanma sorumluluğunu algoritmanın gerçekleştirilmesinden ayırır ve bu algoritmaları yönetmek için farklı nesnelere yetki verir.

View File

@ -0,0 +1 @@
Strategimønsteret definerer en række algoritmer og indkapsler hver algoritme, så de kan erstattes med hinanden, og ændringen af ??algoritmen vil ikke påvirke de kunder, der bruger algoritmen. Strategimønsteret hører til objektadfærdsmønsteret. Det indkapsler algoritmen, adskiller ansvaret for at bruge algoritmen fra realiseringen af ??algoritmen og uddelegerer til forskellige objekter for at styre disse algoritmer.

View File

@ -0,0 +1 @@
觅会汉仑犯臁铀勾<EFBFBD>储艇脱拧兔苑至崤惺秘会佃判脱拧兔苑至嗑阻豌碎室烈枚岱狗砧⊙逛撮 崤小颐嗷耪杪贯慌Б艇脱拧兔苑至ㄐ淞枋瑙寂蟹旱柰刨·橐氛桡<E6B09B>脱拧兔苑至 觅会汉仑犯爨荤耿艇觅会汉灸翟昧⑼<E698A7>秃啜〉<E5959C> <20>瑙ㄐ拭鼗脱拧兔苑至 崧·且撩押荚椽秃⑼А颐悛橥雅⊥迷分镣汀ㄒ 颐酚闼猷荤龚迷Б艇脱拧兔苑至 崤辛秃肆衣闼橥缤亨ㄧ〉斓枰ф ㄑ础颐脱拧兔苑至嗨盆夜臻

View File

@ -0,0 +1 @@
Strateegiamuster määratleb algoritmide seeria ja kapseldab iga algoritmi nii, et neid saaks üksteisega asendada ning algoritmi muutmine ei mõjuta algoritmi kasutavaid kliente. Strateegiamuster kuulub objekti käitumismustrisse, mis kapseldab algoritmi, eraldab algoritmi kasutamise vastutuse algoritmi realiseerimisest ja delegeerib erinevatele objektidele nende algoritmide haldamise.

View File

@ -0,0 +1 @@
Mae patrwm y strategaeth yn diffinio cyfres o algorithmau ac yn crynhoi pob algorithm fel y gellir eu disodli â'i gilydd, ac ni fydd newid yr algorithm yn effeithio ar y cwsmeriaid sy'n defnyddio'r algorithm. Mae'r patrwm strategaeth yn perthyn i'r patrwm ymddygiad gwrthrych, mae'n crynhoi'r algorithm, yn gwahanu'r cyfrifoldeb o ddefnyddio'r algorithm oddi wrth wireddu'r algorithm, ac yn dirprwyo i wahanol wrthrychau i reoli'r algorithmau hyn.

View File

@ -0,0 +1 @@
Strategiamalli määrittelee sarjan algoritmeja ja kapseloi jokaisen algoritmin siten, että ne voidaan korvata toisillaan, eikä algoritmin muutos vaikuta algoritmia käyttäviin asiakkaisiin. Kohteen käyttäytymismalliin kuuluu strategiamalli, joka kapseloi algoritmin, erottaa algoritmin käytön vastuun algoritmin toteuttamisesta ja delegoi eri objekteille näiden algoritmien hallinnan.

View File

@ -0,0 +1 @@
Strate¨ki obrazac definira niz algoritama i enkapsulira svaki algoritam tako da se mogu meðusobno zamijeniti, a promjena algoritma neåe utjecati na kupce koji koriste algoritam. Strate¨ki obrazac pripada obrascu pona¨anja objekta. On enkapsulira algoritam, odvaja odgovornost za kori¨tenje algoritma od realizacije algoritma i delegira razli¹itim objektima da upravljaju tim algoritmima.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

View File

@ -0,0 +1 @@
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

View File

@ -0,0 +1 @@
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

View File

@ -0,0 +1 @@
策略模式定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。策略模式屬於對象行為模式,它通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,並委派給不同的對象對這些算法進行管理。