Compare commits

...

64 Commits
v1.0 ... v2.1.0

Author SHA1 Message Date
陈精华
9786fa8275 2.1.0版 2019-06-19 15:24:24 +08:00
陈精华
37762cf034 支持FTP文件地址作为预览源url 2019-06-19 15:24:24 +08:00
陈精华
a78f1e5f8e Docker构建 2019-06-19 15:24:24 +08:00
陈精华
440b8030e0 新增Docker构建 2019-06-19 15:24:24 +08:00
陈精华
fb7cdfbef7 支持http/https文件流作为预览源url 2019-06-19 15:24:24 +08:00
陈精华
cf1ee9c631 支持自动清理预览文件及缓存 2019-06-19 15:24:24 +08:00
陈精华
13123f8f9d addTask转码优化 2019-06-19 15:24:24 +08:00
陈精华
189bc3965d 2.1.0迭代 2019-06-19 15:24:24 +08:00
kl
0aa7444dba Update pom.xml 2019-05-30 09:08:08 +08:00
陈精华
628efec6bd 2.0.2版 2019-05-23 09:53:37 +08:00
陈精华
6d0846a551 修复rocksdb缓存只缓存一条数据问题 2019-05-23 09:53:37 +08:00
陈精华
41d9015023 支持flv视频预览 2019-05-23 09:53:37 +08:00
陈精华
3f40b60c64 支持7z文件预览 2019-05-23 09:53:37 +08:00
陈精华
f244054462 优化读取动态配置 2019-05-23 09:53:37 +08:00
陈精华
37fbc98827 2.0.2迭代 2019-05-23 09:53:37 +08:00
陈精华
795cf3393e 2.0.1版 2019-05-09 15:20:15 +08:00
陈精华
70323b8ee3 pdf预览支持url中有中文或特殊字符 2019-05-09 15:20:15 +08:00
陈精华
67686e99f0 修复excel预览网页乱码问题 2019-05-09 15:20:15 +08:00
陈精华
90554462dc pdf默认预览模式也从配置文件中取,和word ppt统一 2019-05-09 15:20:15 +08:00
kl
ba3084d698 Update README.md 2019-05-09 09:18:54 +08:00
陈精华
3813f75f65 2.0版本 2019-05-07 10:16:26 +08:00
陈精华
a663e99bcd 背景色统一 2019-04-28 13:55:40 +08:00
陈精华
d517ab4e6f 替换pdf和图片预览相互转跳按钮图标 2019-04-28 13:55:40 +08:00
陈精华
29726c11a3 PDF预览也支持图片模式和查看大图 2019-04-28 13:55:40 +08:00
陈精华
336a18ade7 office预览只有PDF转图片 2019-04-26 15:35:43 +08:00
陈精华
53814fe6ab office图片&PDF预览背景色统一 2019-04-26 14:54:09 +08:00
陈精华
50fb586e6f office图片预览打开大图新开窗口 2019-04-26 14:25:35 +08:00
陈精华
a49ee9d726 图片预览可在viewjs中大图预览&翻页 2019-04-26 14:15:08 +08:00
陈精华
ae40d0233b 加入shutdown脚本 2019-04-26 14:15:08 +08:00
陈精华
8f7c13850e 修复调试时只打开jodconverter-web目录里读不到配置文件异常 2019-04-26 14:15:08 +08:00
陈精华
b4d3419797 word、ppt文档新增图片预览模式 2019-04-26 09:04:34 +08:00
陈精华
68aa5db66b RocksDB缓存实现,并更换默认实现为RocksDB 2019-04-23 11:40:44 +08:00
陈精华
7e8de7c754 解压相关 2019-04-18 16:14:58 +08:00
陈精华
f989fbf9c9 优先使用自定义office.home 2019-04-18 11:53:59 +08:00
陈精华
af8ddc10da 文件转换编码默认根据操作系统获取,变为可选配置
文本和多媒体类型添加默认值,变为可选配置
2019-04-17 13:32:14 +08:00
陈精华
3713e6e550 MacOS下office安装路径更新 2019-04-17 13:32:14 +08:00
陈精华
4a7ba07df1 file.Dir变为选配置添加其默认值 2019-04-16 22:10:48 +08:00
陈精华
b625381de3 脚本修改 2019-04-16 16:11:22 +08:00
陈精华
0968ac774a 脚本修改 2019-04-16 16:11:22 +08:00
陈精华
0db6b23bf7 Linux下集成OpenOffice 2019-04-16 16:11:22 +08:00
陈精华
6dc10e8df4 解决tar包office目录层级过长问题 2019-04-16 16:11:22 +08:00
陈精华
9976f0ae99 dev和release区分开 2019-04-16 16:11:22 +08:00
陈精华
55537d3a25 Windows下集成OpenOffice 2019-04-16 16:11:22 +08:00
陈精华
02e116fd8a 完善启动脚本 2019-04-16 16:11:22 +08:00
陈精华
5af3a97720 支持部分配置在运行时动态改变 2019-04-16 16:11:22 +08:00
陈精华
bf08c2c26f 更新记录 2019-04-16 16:11:22 +08:00
陈精华
236ed405f2 启动脚本&配置文件 2019-04-16 16:11:22 +08:00
陈精华
0fb02e3ccb 打包为zip和tar.gz包 2019-04-16 16:11:22 +08:00
陈精华
3dd6609fd6 缓存及队列实现抽象,提供JDK和REDIS两种实现 2019-04-16 16:11:22 +08:00
kl
dd876792c7 Update pom.xml 2018-10-22 11:34:30 +08:00
kl
3b79ef31e8 Update pom.xml
更新jar版本依赖,老版本有安全风险
2018-10-17 09:09:02 +08:00
kl
deb3abcac1 Merge remote-tracking branch 'origin/master' 2018-03-26 17:06:42 +08:00
kl
1c1a945959 使用畅言替换友言社评服务 2018-03-26 17:03:20 +08:00
duanmuxiangxiao
d1c5211d03 viewerjs版本升级release 1.0.0-rc.1 2018-03-26 16:48:02 +08:00
duanmuxiangxiao
d73bc3a031 图片轮播,修改图片切换按钮样式 2018-03-26 13:39:54 +08:00
chenkailing
6f2001b8c9 1.修复不支持文件类型提示时抛异常的问题
2.添加多媒体文件预览支持,如mp4,mp3等文件
2018-03-25 13:26:51 +08:00
kl
378920b773 解决多图片轮播预览数据量大的问题 2018-03-08 14:28:44 +08:00
kl
c78bf0605d 完善多图片轮播预览接口逻辑 2018-03-08 09:51:47 +08:00
kl
e8f0efe1ec Update README.md 2018-01-22 09:18:24 +08:00
kl
f8ebc4e39b Merge remote-tracking branch 'origin/master' 2018-01-19 15:14:38 +08:00
kl
3ecea6ee6c 修复包名异常问题 2018-01-19 15:14:01 +08:00
kl
540e434954 Update README.md 2018-01-19 14:57:08 +08:00
kl
6754232a1d 1.大文件入队提前处理
2.新增addTask文件转换入队接口
3.支持kkFIleView接口和异构系统redis入队
2018-01-19 14:51:18 +08:00
spiritree
ad790f4ae9 Update README.en.md 2018-01-18 09:06:52 +08:00
3675 changed files with 674572 additions and 297 deletions

5
.gitignore vendored
View File

@@ -28,7 +28,6 @@ nbdist/
.classpath
.project
**/.settings
**/bin/
**/build/
**/.externalToolBuilders/
*.iml
@@ -38,4 +37,6 @@ nbdist/
/producer/tmp
/.temfile
.temfile
convertedFile/
convertedFile/
jodconverter-web/src/main/cache/
jodconverter-web/src/main/file/

31
Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
FROM centos:centos7.6.1810
MAINTAINER chenjh "842761733@qq.com"
ADD jodconverter-web/target/kkFileView-*.tar.gz /opt/
COPY fonts/* /usr/share/fonts/
RUN yum install -y kde-l10n-Chinese &&\
yum install -y glibc-common &&\
yum install -y fontconfig &&\
yum install -y mkfontscale &&\
localedef -c -f UTF-8 -i zh_CN zh_CN.utf8 &&\
export LANG=zh_CN.UTF-8 &&\
echo "export LANG=zh_CN.UTF-8" >> /etc/locale.conf &&\
LANG="zh_CN.UTF-8" &&\
yum install -y java-1.8.0-openjdk.x86_64 &&\
yum install -y wget &&\
yum install -y libXext.x86_64 &&\
yum groupinstall -y "X Window System" &&\
cd /tmp &&\
wget https://iweb.dl.sourceforge.net/project/openofficeorg.mirror/4.1.6/binaries/zh-CN/Apache_OpenOffice_4.1.6_Linux_x86-64_install-rpm_zh-CN.tar.gz -cO openoffice_rpm.tar.gz &&\
tar zxf /tmp/openoffice_rpm.tar.gz &&\
cd /tmp/zh-CN/RPMS &&\
rpm -Uvih *.rpm &&\
rpm -Uvih desktop-integration/openoffice4.1.6-redhat-menus-4.1.6-9790.noarch.rpm &&\
rm -f /tmp/openoffice_rpm.tar.gz &&\
rm -rf /tmp/zh-CN &&\
cd /usr/share/fonts &&\
mkfontscale &&\
mkfontdir &&\
fc-cache -fv
ENV LC_ALL zh_CN.UTF-8
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-2.1.0/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-2.1.0/conf/application.properties","-jar","/opt/kkFileView-2.1.0/bin/kkFileView-2.1.0.jar"]

View File

@@ -1,26 +1,33 @@
# file-online-preview
This kekingcn kkFileView software is intended to be a solution for previewing documents online. There are some similar paid products in the industry, at present.
Such as 【[永中office](http://dcs.yozosoft.com/)】,【[office365](http://www.officeweb365.com/)】,【[idocv](https://www.idocv.com/)】, etc..
The kekingcn kkFileView software is an open source implementation and released under the Apache License version 2. It's aimed to feedback the community after obtaining the consent of company executives,
[![GitHub license](https://img.shields.io/github/license/kekingcn/kkFileView.svg?style=flat-square)](https://github.com/kekingcn/kkFileView/blob/master/LICENSE)
### Introduction
This kekingcn kkFileView project is intended to be a solution for previewing documents online. At present,there are some similar paid products in the industry.
Such as 【[永中office](http://dcs.yozosoft.com/)】,【[office365](http://www.officeweb365.com/)】,【[idocv](https://www.idocv.com/)】, etc...
It is an open source implementation and released under the Apache License version 2.0. Finally,It is aimed to feedback the community after obtaining the consent of company executives,
special thanks to the supports of @唐老大 and the contributions of @端木详笑.
### Advantages
* build with the popular frame spring boot,
* easy to deploy and deploy,
* basically support online preview of mainstream office documents, such as Doc, docx, Excel, PDF, TXT, zip, rar, pictures, etc.
### Features
- Build with the popular frame spring boot
- Easy to build and deploy
- Basically support online preview of mainstream office documents, such as Doc, docx, Excel, PDF, TXT, zip, rar, pictures, etc
- REST API
- Abstract file preview interface so that it is easy to extend more file extensions and develop this project on your own
### The demo online
### Live demo
> Please treat public service kindly, or this would stop at any time.
URLhttp://file.keking.cn/
### Project documentation
### Documentation
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://github.com/kekingcn/kkFileView/blob/master/README.en.md
### Contact us && Join us
> We will answer everyone's questions which are found when using this project patiently.
And please Google or Baidu first before asking a question, so that we can solve then efficiently.
> We will answer everyone's questions in use of this project.
And please Google or Baidu first before asking a question, so that we can solve it efficiently.
Cherish life away from ineffective communication.
![输入图片说明](https://gitee.com/uploads/images/2017/1219/173717_934cb068_492218.png "屏幕截图.png")
@@ -41,49 +48,54 @@ QQ group613025121
> png,jpeg,jpg,etc., support for zooming with mouse scroll, rotation, inversion,etc.
![输入图片说明](https://gitee.com/uploads/images/2017/1213/094335_657a6f60_492218.png "屏幕截图.png")
Considering space issues, the pictures of other types of documents will not be shown here.You can deploy it by yourself if you are interested in our project.The way to deploy is as below.
Considering space issues, the pictures of other types of documents will not be shown here.You can deploy it by yourself if you are interested in our project.There is a way to deploy it as below.
### Quick Start
> Technologies in this project
- spring boot [spring boot Development Reference Guide](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- freemarker
- redisson
- jodconverter
> Dependent External Environment
- redis
- OpenOffice or LibreOffice
> Technology stack
- Spring boot [spring boot Development Reference Guide](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- Freemarker
- Redisson
- Jodconverter
> Dependencies
- Redis(Optional, Unnecessary by default)
- OpenOffice or LibreOffice(Integrated on Windows, will be installed automatically on Linux, need to be manually installed on Mac OS)
1. First steppull https://github.com/kekingcn/file-online-preview.git
1. First step`git pull https://github.com/kekingcn/file-online-preview.git`
2. Second stepconfigure redis address and OpenOffice directorysuch as
```
#=============================================#Spring Redisson Configuration#===================================#
spring.redisson.address = 192.168.1.204:6379
##The folder for files which are uploaded to the server(Because of running as jar)
file.dir = C:\\Users\\yudian\\Desktop\\dev\\
## openoffice configuration
office.home = C:\\Program Files (x86)\\OpenOffice 4
```
'file.dir' is the real storage address of the converted files, please end with '/'.
3. Third stepRun the main method of FilePreviewApplication.java.After starting,visit 'http://localhost:8012/'.
2. Third stepRun the main method of FilePreviewApplication.java.After starting,visit `http://localhost:8012/`.
If everything is ok,you will see the picture below.
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### System Update History
### Changelog
> January 12th 2018
> June 18th 2019
1. Support automatic cleaning of cache and preview files
2. Support http/https stream url file preview
3. Support FTP url file preview
4. Add Docker build
> April 8th 2019
1. Cache and queue implementations abstract, providing JDK and REDIS implementations (REDIS becomes optional dependencies)
2. Provides zip and tar.gz packages, and provides a one-click startup script
> January 17th 2018
1. Refined the project directory, abstract file preview interface, Easy to extend more file extensions and depoly this project on your own
1. Added English documentation (@幻幻Fate@汝辉) contribution
1. Support for more image file extensions
1. Fixed the issue that image carousel in zip file will always start from the first
> January 12th 2018
1. Support for multiple images preview
1. Support for images rotation preview in rar/zip
> January 2nd 2018
> January 2nd 2018
1. fixed gibberish issue when preview a txt document caused by the file encoding problem
1. fixed the issue that some module dependencies can not be found
1. add a spring boot profile, and support for Multi-environment configuration
1. add 'pdf.js' to preview the documents such as doc,etc.,support for generating doc headlines as pdf menusupport for mobile preview
1. Fixed gibberish issue when preview a txt document caused by the file encoding problem
1. Fixed the issue that some module dependencies can not be found
1. Add a spring boot profile, and support for Multi-environment configuration
1. Add `pdf.js` to preview the documents such as doc,etc.,support for generating doc headlines as pdf menusupport for mobile preview
### Register Usage
If this project is helpful for you, please register on 'https://gitee.com/kekingcn/file-online-preview/issues/IGSBV',

View File

@@ -7,7 +7,7 @@
1. 支持zip,rar,jar,tar,gzip等压缩包
1. 支持jpgjpegpnggif等图片预览翻转缩放镜像
1. 使用spring boot开发预览服务搭建部署非常简便
1. rest接口提供服务应用接入简单方便
1. rest接口提供服务跨平台特性(java,php,python,go,php....)都支持,应用接入简单方便
1. 抽象预览服务接口,方便二次开发,非常方便添加其他类型文件预览支持
1. 最最重要Apache协议开源代码pull下来想干嘛就干嘛
@@ -17,6 +17,7 @@
地址http://file.keking.cn/
### 项目文档Project documentation
1. 详细wiki文档https://gitee.com/kekingcn/file-online-preview/wikis/pages
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://github.com/kekingcn/kkFileView/blob/master/README.en.md
@@ -50,29 +51,33 @@ QQ群号613025121
- redisson
- jodconverter
> 依赖外部环境
- redis
- OpenOffice或者LibreOffice
- redis (可选,默认不用)
- OpenOffice或者LibreOffice(Windows下已内置Linux会自动安装Mac OS下需要手动安装)
1. 第一步pull项目https://github.com/kekingcn/file-online-preview.git
2. 第二步:配置redis地址和OpenOffice目录
```
#=============================================#spring Redisson配置#===================================#
spring.redisson.address = 192.168.1.204:6379
##资源映射路径(因为jar方式运行的原因)
file.dir = C:\\Users\\yudian\\Desktop\\dev\\
## openoffice相关配置
office.home = C:\\Program Files (x86)\\OpenOffice 4
```
file.dir为转换文件实际存储地址注意要以/结尾
3. 第三步运行FilePreviewApplication的main方法服务启动后访问http://localhost:8012/
3. 第二步:运行FilePreviewApplication的main方法服务启动后访问http://localhost:8012/
会看到如下界面,代表服务启动成功
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### 历史更新记录
> 2019年06月18日
1. 支持自动清理缓存及预览文件
2. 支持http/https下载流url文件预览
3. 支持FTP url文件预览
4. 加入Docker构建
> 2019年04月08日
1. 缓存及队列实现抽象提供JDK和REDIS两种实现(REDIS成为可选依赖)
2. 打包方式提供zip和tar.gz包并提供一键启动脚本
> 2018年01月19日
1. 大文件入队提前处理
1. 新增addTask文件转换入队接口
1. 采用redis队列支持kkFIleView接口和异构系统入队两种方式
> 2018年01月17日
1. 优化项目结构,抽象文件预览接口,更方便的加入更多的文件类型预览支持,方便二次开发

0
fonts/.gitkeep Normal file
View File

View File

@@ -12,8 +12,11 @@
//
package org.artofsolving.jodconverter.office;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Map;
import java.util.Properties;
import org.artofsolving.jodconverter.util.PlatformUtils;
@@ -61,29 +64,40 @@ public class OfficeUtils {
}
public static File getDefaultOfficeHome() {
if (System.getProperty("office.home") != null) {
return new File(System.getProperty("office.home"));
Properties properties = new Properties();
String customizedConfigPath = getCustomizedConfigPath();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
properties.load(bufferedReader);
} catch (Exception e) {}
if (properties.getProperty("office.home") != null) {
return new File(properties.getProperty("office.home"));
}
if (PlatformUtils.isWindows()) {
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
String homePath = OfficeUtils.getHomePath();
String programFiles = System.getenv("ProgramFiles(x86)");
if (programFiles == null) {
programFiles = System.getenv("ProgramFiles");
}
return findOfficeHome(
programFiles + File.separator + "OpenOffice 4",
programFiles + File.separator + "LibreOffice 4"
programFiles + File.separator + "LibreOffice 4",
homePath + File.separator + "office"
);
} else if (PlatformUtils.isMac()) {
return findOfficeHome(
"/Applications/OpenOffice.org.app/Contents",
"/Applications/OpenOffice.app/Contents",
"/Applications/LibreOffice.app/Contents"
);
} else {
// Linux or other *nix variants
return findOfficeHome(
"/opt/openoffice.org3",
"/opt/openoffice",
"/opt/libreoffice",
"/opt/openoffice4",
"/usr/lib/openoffice",
"/usr/lib/libreoffice"
);
@@ -108,4 +122,29 @@ public class OfficeUtils {
}
}
public static String getHomePath() {
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
if (userDir == null) {
userDir = System.getProperty("user.dir");
}
if (userDir.endsWith("bin")) {
userDir = userDir.substring(0, userDir.length() - 4);
} else {
String separator = File.separator;
if (userDir.contains("jodconverter-web")) {
userDir = userDir + separator + "src" + separator + "main";
} else {
userDir = userDir + separator + "jodconverter-web" + separator + "src" + separator + "main";
}
}
return userDir;
}
public static String getCustomizedConfigPath() {
String homePath = OfficeUtils.getHomePath();
String separator = java.io.File.separator;
String configFilePath = homePath + separator + "conf" + separator + "application.properties";
return configFilePath;
}
}

View File

@@ -10,7 +10,9 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jodconverter-web</artifactId>
<groupId>cn.keking</groupId>
<artifactId>kkFileView</artifactId>
<version>2.1.0</version>
<properties>
@@ -104,13 +106,19 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.9</version>
<version>1.18</version>
</dependency>
<!-- 解压(rar)-->
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>0.7</version>
<version>4.0.0</version>
</dependency>
<!-- 解压(7z)-->
<dependency>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jchardet</groupId>
@@ -139,16 +147,42 @@
<artifactId>commons-cli</artifactId>
<version>1.2</version>
</dependency>
<!-- FTP -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
<version>1.4.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
<artifactId>concurrentlinkedhashmap-lru</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.rocksdb</groupId>
<artifactId>rocksdbjni</artifactId>
<version>5.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.15</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.15</version>
</dependency>
</dependencies>
<build>
<resources>
@@ -159,12 +193,36 @@
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/conf</directory>
<excludes>
<exclude>${build.exclude.resource}</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/resources/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@@ -0,0 +1,2 @@
#!/bin/bash
kill 15 `ps -ef|grep kkFileView|awk '{print $2}'`

View File

@@ -0,0 +1,7 @@
@echo off
set "KKFILEVIEW_BIN_FOLDER=%cd%"
cd "%KKFILEVIEW_BIN_FOLDER%"
echo Using KKFILEVIEW_BIN_FOLDER %KKFILEVIEW_BIN_FOLDER%
echo Starting kkFileView...
echo Please check log file for more information
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\conf\application.properties -jar kkFileView-2.1.0.jar -> ..\log\kkFileView.log

View File

@@ -0,0 +1,30 @@
#!/bin/bash
DIR_HOME=("/opt/openoffice.org3" "/opt/libreoffice" "/opt/openoffice4" "/usr/lib/openoffice" "/usr/lib/libreoffice")
FLAG=
OFFICE_HOME=
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")";pwd)
export KKFILEVIEW_BIN_FOLDER=$KKFILEVIEW_BIN_FOLDER
cd $KKFILEVIEW_BIN_FOLDER
echo "Using KKFILEVIEW_BIN_FOLDER $KKFILEVIEW_BIN_FOLDER"
grep 'office\.home' ../conf/application.properties | grep '!^#'
if [ $? -eq 0 ]; then
echo "Using customized office.home"
else
for i in ${DIR_HOME[@]}
do
if [ -f $i"/program/soffice.bin" ]; then
FLAG=true
OFFICE_HOME=${i}
break
fi
done
if [ ! -n "${FLAG}" ]; then
echo "Installing OpenOffice"
sh ../script/install.sh
else
echo "Detected office component has been installed in $OFFICE_HOME"
fi
fi
echo "Starting kkFileView..."
echo "Please check log file for more information"
nohup java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../conf/application.properties -jar kkFileView-2.1.0.jar > ../log/kkFileView.log 2>&1 &

View File

@@ -0,0 +1,48 @@
#######################################不可动态配置,需要重启生效#######################################
server.port = 8012
spring.http.encoding.charset = utf8
## Freemarker 配置
spring.freemarker.template-loader-path = classpath:/web/
spring.freemarker.cache = false
spring.freemarker.charset = UTF-8
spring.freemarker.check-template-location = true
spring.freemarker.content-type = text/html
spring.freemarker.expose-request-attributes = true
spring.freemarker.expose-session-attributes = true
spring.freemarker.request-context-attribute = request
spring.freemarker.suffix = .ftl
server.tomcat.uri-encoding = UTF-8
#文件上传限制
spring.http.multipart.max-request-size=100MB
spring.http.multipart.max-file-size=100MB
#文件资源路径默认为打包根路径下的file目录下
#file.dir = D:\\kkFileview\\
#openoffice home路径
#office.home = C:\\Program Files (x86)\\OpenOffice 4
#缓存实现类型不配默认为内嵌RocksDB实现可配置为redis(type = redis)实现需要配置spring.redisson.address等参数和 JDK 内置对象实现type = jdk,
#cache.type = redis
#redis连接
#spring.redisson.address = 192.168.1.204:6379
#spring.redisson.password = xxx
#缓存自动清理(每晚3点自动清理) true 为开启,注释掉或其他值都为关闭
cache.clean = true
#######################################可在运行时动态配置#######################################
#文本类型,默认如下,可自定义添加
#simText = txt,html,xml,properties,md,java,py,c,cpp,sql
#多媒体类型,默认如下,可自定义添加
#media = mp3,wav,mp4,flv
#文件转换编码,默认根据操作系统获取
#converted.file.charset = GBK
#office类型文档(word ppt)样式,默认为图片(image)可配置为pdf预览时也有按钮切换
#office.preview.type = pdf
#预览源为FTP时 FTP用户名可在ftp url后面加参数ftp.username=ftpuser指定不指定默认用配置的
ftp.username = ftpuser
#预览源为FTP时 FTP密码可在ftp url后面加参数ftp.password=123456指定不指定默认用配置的
ftp.password = 123456
#预览源为FTP时, FTP连接默认ControlEncoding(根据FTP服务器操作系统选择Linux一般为UTF-8Windows一般为GBK)可在ftp url后面加参数ftp.control.encoding=UTF-8指定不指定默认用配置的
ftp.control.encoding = UTF-8

View File

@@ -0,0 +1,96 @@
package cn.keking.config;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
/**
* @auther: chenjh
* @time: 2019/4/10 17:22
* @description
*/
@Component
public class ConfigConstants {
private static String[] simText = {};
private static String[] media = {};
private static String convertedFileCharset;
private static String officePreviewType;
private static String ftpUsername;
private static String ftpPassword;
private static String ftpControlEncoding;
private static String fileDir = OfficeUtils.getHomePath() + File.separator + "file" + File.separator;
public static String[] getSimText() {
return simText;
}
public static void setSimText(String[] simText) {
ConfigConstants.simText = simText;
}
public static String[] getMedia() {
return media;
}
public static void setMedia(String[] media) {
ConfigConstants.media = media;
}
public static String getConvertedFileCharset() {
return convertedFileCharset;
}
public static void setConvertedFileCharset(String convertedFileCharset) {
ConfigConstants.convertedFileCharset = convertedFileCharset;
}
public static String getOfficePreviewType() {
return officePreviewType;
}
public static void setOfficePreviewType(String officePreviewType) {
ConfigConstants.officePreviewType = officePreviewType;
}
public static String getFtpUsername() {
return ftpUsername;
}
public static void setFtpUsername(String ftpUsername) {
ConfigConstants.ftpUsername = ftpUsername;
}
public static String getFtpPassword() {
return ftpPassword;
}
public static String getFtpControlEncoding() {
return ftpControlEncoding;
}
public static void setFtpControlEncoding(String ftpControlEncoding) {
ConfigConstants.ftpControlEncoding = ftpControlEncoding;
}
public static void setFtpPassword(String ftpPassword) {
ConfigConstants.ftpPassword = ftpPassword;
}
public static String getFileDir() {
return fileDir;
}
@Value("${file.dir:default}")
public void setFileDir(String fileDir) {
if (!"default".equals(fileDir)) {
if (!fileDir.endsWith(File.separator)) {
fileDir = fileDir + File.separator;
}
ConfigConstants.fileDir = fileDir;
}
}
}

View File

@@ -0,0 +1,83 @@
package cn.keking.config;
import cn.keking.service.impl.OfficeFilePreviewImpl;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
/**
* @auther: chenjh
* @time: 2019/4/10 16:16
* @description 每隔1s读取并更新一次配置文件
*/
@Component
public class ConfigRefreshComponent {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRefreshComponent.class);
public static final String DEFAULT_TXT_TYPE = "txt,html,xml,properties,md,java,py,c,cpp,sql";
public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv";
public static final String DEFAULT_CONVERTER_CHARSET = System.getProperty("sun.jnu.encoding");
public static final String DEFAULT_FTP_USERNAME = null;
public static final String DEFAULT_FTP_PASSWORD = null;
public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8";
@PostConstruct
void refresh() {
Thread configRefreshThread = new Thread(new ConfigRefreshThread());
configRefreshThread.start();
}
class ConfigRefreshThread implements Runnable {
@Override
public void run() {
try {
Properties properties = new Properties();
String text;
String media;
String[] textArray;
String[] mediaArray;
String convertedFileCharset;
String officePreviewType;
String ftpUsername;
String ftpPassword;
String ftpControlEncoding;
String configFilePath = OfficeUtils.getCustomizedConfigPath();
while (true) {
FileReader fileReader = new FileReader(configFilePath);
BufferedReader bufferedReader = new BufferedReader(fileReader);
properties.load(bufferedReader);
text = properties.getProperty("simText", DEFAULT_TXT_TYPE);
media = properties.getProperty("media", DEFAULT_MEDIA_TYPE);
convertedFileCharset = properties.getProperty("converted.file.charset", DEFAULT_CONVERTER_CHARSET);
officePreviewType = properties.getProperty("office.preview.type", OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE);
ftpUsername = properties.getProperty("ftp.username", DEFAULT_FTP_USERNAME);
ftpPassword = properties.getProperty("ftp.password", DEFAULT_FTP_PASSWORD);
ftpControlEncoding = properties.getProperty("ftp.control.encoding", DEFAULT_FTP_CONTROL_ENCODING);
textArray = text.split(",");
mediaArray = media.split(",");
ConfigConstants.setSimText(textArray);
ConfigConstants.setMedia(mediaArray);
ConfigConstants.setConvertedFileCharset(convertedFileCharset);
ConfigConstants.setOfficePreviewType(officePreviewType);
ConfigConstants.setFtpUsername(ftpUsername);
ConfigConstants.setFtpPassword(ftpPassword);
ConfigConstants.setFtpControlEncoding(ftpControlEncoding);
bufferedReader.close();
fileReader.close();
Thread.sleep(1000L);
}
} catch (IOException | InterruptedException e) {
LOGGER.error("读取配置文件异常", e);
}
}
}
}

View File

@@ -1,10 +1,9 @@
package cn.keking.config;
import io.netty.channel.nio.NioEventLoopGroup;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -14,6 +13,7 @@ import org.springframework.util.ClassUtils;
* Created by kl on 2017/09/26.
* redisson 客户端配置
*/
@ConditionalOnExpression("'${cache.type:default}'.equals('redis')")
@ConfigurationProperties(prefix = "spring.redisson")
@Configuration
public class RedissonConfig {
@@ -42,8 +42,8 @@ public class RedissonConfig {
private String codec="org.redisson.codec.JsonJacksonCodec";
@Bean(destroyMethod = "shutdown")
RedissonClient redisson() throws Exception {
@Bean
Config config() throws Exception {
Config config = new Config();
config.useSingleServer().setAddress(address)
.setConnectionMinimumIdleSize(connectionMinimumIdleSize)
@@ -69,7 +69,7 @@ public class RedissonConfig {
config.setThreads(thread);
config.setEventLoopGroup(new NioEventLoopGroup());
config.setUseLinuxNativeEpoll(false);
return Redisson.create(config);
return config;
}
public int getThread() {

View File

@@ -0,0 +1,28 @@
package cn.keking.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @auther: chenjh
* @time: 2019/4/16 20:04
* @description
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
private final static Logger LOGGER = LoggerFactory.getLogger(WebConfig.class);
/**
* 访问外部文件配置
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String filePath = ConfigConstants.getFileDir();
LOGGER.info("Add resource locations: {}", filePath);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
super.addResourceHandlers(registry);
}
}

View File

@@ -10,7 +10,8 @@ public enum FileType {
office("officeFilePreviewImpl"),
simText("simTextFilePreviewImpl"),
pdf("pdfFilePreviewImpl"),
other("otherFilePreviewImpl");
other("otherFilePreviewImpl"),
media("mediaFilePreviewImpl");
private String instanceName;
FileType(String instanceName){

View File

@@ -1,4 +1,4 @@
package cn.keking.param;
package cn.keking.model;
import java.io.Serializable;

View File

@@ -0,0 +1,82 @@
package cn.keking.service;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.ExtendedModelMap;
import javax.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by kl on 2018/1/19.
* Content :消费队列中的转换文件
*/
@Service
public class FileConverQueueTask {
Logger logger= LoggerFactory.getLogger(getClass());
public static final String queueTaskName="FileConverQueueTask";
@Autowired
FilePreviewFactory previewFactory;
@Autowired
CacheService cacheService;
@Autowired
FileUtils fileUtils;
@PostConstruct
public void startTask(){
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new ConverTask(previewFactory, cacheService, fileUtils));
logger.info("队列处理文件转换任务启动完成 ");
}
class ConverTask implements Runnable{
FilePreviewFactory previewFactory;
CacheService cacheService;
FileUtils fileUtils;
public ConverTask(FilePreviewFactory previewFactory, CacheService cacheService, FileUtils fileUtils) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileUtils=fileUtils;
}
@Override
public void run() {
while (true) {
try {
String url = cacheService.takeQueueTask();
if(url != null){
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
logger.info("正在处理转换任务,文件名称【{}】",fileAttribute.getName());
FileType fileType=fileAttribute.getType();
if(fileType.equals(FileType.compress) || fileType.equals(FileType.office)){
FilePreview filePreview=previewFactory.get(fileAttribute);
filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute);
}
}
} catch (Exception e) {
try {
Thread.sleep(1000*10);
}catch (Exception ex){
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
package cn.keking.service;
import cn.keking.model.FileAttribute;
import org.springframework.ui.Model;
/**
@@ -7,5 +8,5 @@ import org.springframework.ui.Model;
* Content :
*/
public interface FilePreview {
String filePreviewHandle(String url, Model model);
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
}

View File

@@ -5,7 +5,6 @@ import cn.keking.utils.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.util.Map;
@@ -22,9 +21,8 @@ public class FilePreviewFactory {
@Autowired
ApplicationContext context;
public FilePreview get(String url) {
public FilePreview get(FileAttribute fileAttribute) {
Map<String, FilePreview> filePreviewMap = context.getBeansOfType(FilePreview.class);
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
return filePreviewMap.get(fileAttribute.getType().getInstanceName());
}
}

View File

@@ -0,0 +1,40 @@
package cn.keking.service.cache;
import java.util.List;
import java.util.Map;
/**
* @auther: chenjh
* @time: 2019/4/2 16:45
* @description
*/
public interface CacheService {
final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
final String REDIS_FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
final String REDIS_FILE_PREVIEW_PDF_IMGS_KEY = "converted-preview-pdfimgs-file";
final Integer DEFAULT_PDF_CAPACITY = 500000;
final Integer DEFAULT_IMG_CAPACITY = 500000;
final Integer DEFAULT_PDFIMG_CAPACITY = 500000;
void initPDFCachePool(Integer capacity);
void initIMGCachePool(Integer capacity);
void initPdfImagesCachePool(Integer capacity);
void putPDFCache(String key, String value);
void putImgCache(String key, List<String> value);
Map<String, String> getPDFCache();
String getPDFCache(String key);
Map<String, List<String>> getImgCache();
List<String> getImgCache(String key);
Integer getPdfImageCache(String key);
void putPdfImageCache(String pdfFilePath, int num);
void cleanCache();
void addQueueTask(String url);
String takeQueueTask() throws InterruptedException;
}

View File

@@ -0,0 +1,135 @@
package cn.keking.service.cache.impl;
import cn.keking.service.cache.CacheService;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.Weighers;
import org.rocksdb.RocksDB;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @auther: chenjh
* @time: 2019/4/2 17:21
* @description
*/
@Service
@ConditionalOnExpression("'${cache.type:default}'.equals('jdk')")
public class CacheServiceJDKImpl implements CacheService {
private Map<String, String> pdfCache;
private Map<String, List<String>> imgCache;
private Map<String, Integer> pdfImagesCache;
private static final int QUEUE_SIZE = 500000;
private BlockingQueue blockingQueue = new ArrayBlockingQueue(QUEUE_SIZE);
@Override
public void initPDFCachePool(Integer capacity) {
pdfCache = new ConcurrentLinkedHashMap.Builder<String, String>()
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
.build();
}
@Override
public void initIMGCachePool(Integer capacity) {
imgCache = new ConcurrentLinkedHashMap.Builder<String, List<String>>()
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
.build();
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
pdfImagesCache = new ConcurrentLinkedHashMap.Builder<String, Integer>()
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
.build();
}
@Override
public void putPDFCache(String key, String value) {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
pdfCache.put(key, value);
}
@Override
public void putImgCache(String key, List<String> value) {
if (imgCache == null) {
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
imgCache.put(key, value);
}
@Override
public Map<String, String> getPDFCache() {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
return pdfCache;
}
@Override
public String getPDFCache(String key) {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
return pdfCache.get(key);
}
@Override
public Map<String, List<String>> getImgCache() {
if (imgCache == null) {
initPDFCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
return imgCache;
}
@Override
public List<String> getImgCache(String key) {
if (imgCache == null) {
initPDFCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
return imgCache.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
return pdfImagesCache.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
pdfImagesCache.put(pdfFilePath, num);
}
@Override
public void cleanCache() {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);
}
@Override
public String takeQueueTask() throws InterruptedException {
return String.valueOf(blockingQueue.take());
}
}

View File

@@ -0,0 +1,130 @@
package cn.keking.service.cache.impl;
import cn.keking.service.FileConverQueueTask;
import cn.keking.service.cache.CacheService;
import org.redisson.Redisson;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* @auther: chenjh
* @time: 2019/4/2 18:02
* @description
*/
@ConditionalOnExpression("'${cache.type:default}'.equals('redis')")
@Service
public class CacheServiceRedisImpl implements CacheService {
private Config config;
@Autowired
public CacheServiceRedisImpl(Config config) {
this.config = config;
this.redissonClient = Redisson.create(config);
}
private RedissonClient redissonClient;
@Override
public void initPDFCachePool(Integer capacity) {
}
@Override
public void initIMGCachePool(Integer capacity) {
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
}
@Override
public void putPDFCache(String key, String value) {
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
convertedList.fastPut(key, value);
}
@Override
public void putImgCache(String key, List<String> value) {
RMapCache<String, List<String>> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
convertedList.fastPut(key, value);
}
@Override
public Map<String, String> getPDFCache() {
return redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
}
@Override
public String getPDFCache(String key) {
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
return convertedList.get(key);
}
@Override
public Map<String, List<String>> getImgCache() {
return redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
}
@Override
public List<String> getImgCache(String key) {
RMapCache<String, List<String>> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
return convertedList.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_IMGS_KEY);
return convertedList.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_IMGS_KEY);
convertedList.fastPut(pdfFilePath, num);
}
@Override
public void cleanCache() {
cleanPdfCache();
cleanImgCache();
cleanPdfImgCache();
}
@Override
public void addQueueTask(String url) {
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(FileConverQueueTask.queueTaskName);
queue.addAsync(url);
}
@Override
public String takeQueueTask() throws InterruptedException {
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(FileConverQueueTask.queueTaskName);
return queue.take();
}
private void cleanPdfCache() {
RMapCache<String, String> pdfCache = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
pdfCache.clear();
}
private void cleanImgCache() {
RMapCache<String, List<String>> imgCache = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
imgCache.clear();
}
private void cleanPdfImgCache() {
RMapCache<String, Integer> pdfImg = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_IMGS_KEY);
pdfImg.clear();
}
}

View File

@@ -0,0 +1,239 @@
package cn.keking.service.cache.impl;
import cn.keking.service.cache.CacheService;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @auther: chenjh
* @time: 2019/4/22 11:02
* @description
*/
@ConditionalOnExpression("'${cache.type:default}'.equals('default')")
@Service
public class CacheServiceRocksDBImpl implements CacheService {
static {
RocksDB.loadLibrary();
}
private static final String DB_PATH = OfficeUtils.getHomePath() + File.separator + "cache";
private static final int QUEUE_SIZE = 500000;
private static final Logger LOGGER = LoggerFactory.getLogger(CacheServiceRocksDBImpl.class);
private BlockingQueue blockingQueue = new ArrayBlockingQueue(QUEUE_SIZE);
private RocksDB db;
{
try {
db = RocksDB.open(DB_PATH);
if (db.get(REDIS_FILE_PREVIEW_PDF_KEY.getBytes()) == null) {
Map<String, String> initPDFCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(initPDFCache));
}
if (db.get(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes()) == null) {
Map<String, List<String>> initIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(initIMGCache));
}
if (db.get(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes()) == null) {
Map<String, Integer> initPDFIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(initPDFIMGCache));
}
} catch (RocksDBException | IOException e) {
LOGGER.error("Uable to init RocksDB" + e);
}
}
@Override
public void initPDFCachePool(Integer capacity) {
}
@Override
public void initIMGCachePool(Integer capacity) {
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
}
@Override
public void putPDFCache(String key, String value) {
try {
Map<String, String> pdfCacheItem = getPDFCache();
pdfCacheItem.put(key, value);
db.put(REDIS_FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(pdfCacheItem));
} catch (RocksDBException | IOException e) {
LOGGER.error("Put into RocksDB Exception" + e);
}
}
@Override
public void putImgCache(String key, List<String> value) {
try {
Map<String, List<String>> imgCacheItem = getImgCache();
imgCacheItem.put(key, value);
db.put(REDIS_FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(imgCacheItem));
} catch (RocksDBException | IOException e) {
LOGGER.error("Put into RocksDB Exception" + e);
}
}
@Override
public Map<String, String> getPDFCache() {
Map<String, String> result = new HashMap<>();
try{
result = (Map<String, String>) toObject(db.get(REDIS_FILE_PREVIEW_PDF_KEY.getBytes()));
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
@Override
public String getPDFCache(String key) {
String result = "";
try{
Map<String, String> map = (Map<String, String>) toObject(db.get(REDIS_FILE_PREVIEW_PDF_KEY.getBytes()));
result = map.get(key);
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
@Override
public Map<String, List<String>> getImgCache() {
Map<String, List<String>> result = new HashMap<>();
try{
result = (Map<String, List<String>>) toObject(db.get(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes()));
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
@Override
public List<String> getImgCache(String key) {
List<String> result = new ArrayList<>();
Map<String, List<String>> map;
try{
map = (Map<String, List<String>>) toObject(db.get(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes()));
result = map.get(key);
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
public Map<String, Integer> getPdfImageCaches() {
Map<String, Integer> map = new HashMap<>();
try{
map = (Map<String, Integer>) toObject(db.get(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes()));
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return map;
}
@Override
public Integer getPdfImageCache(String key) {
Integer result = 0;
Map<String, Integer> map;
try{
map = (Map<String, Integer>) toObject(db.get(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes()));
result = map.get(key);
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
try {
Map<String, Integer> pdfImageCacheItem = getPdfImageCaches();
pdfImageCacheItem.put(pdfFilePath, num);
db.put(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(pdfImageCacheItem));
} catch (RocksDBException | IOException e) {
LOGGER.error("Put into RocksDB Exception" + e);
}
}
@Override
public void cleanCache() {
try {
cleanPdfCache();
cleanImgCache();
cleanPdfImgCache();
} catch (IOException | RocksDBException e) {
LOGGER.error("Clean Cache Exception" + e);
}
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);
}
@Override
public String takeQueueTask() throws InterruptedException {
return String.valueOf(blockingQueue.take());
}
private byte[] toByteArray (Object obj) throws IOException {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray ();
oos.close();
bos.close();
return bytes;
}
private Object toObject (byte[] bytes) throws IOException, ClassNotFoundException {
Object obj = null;
ByteArrayInputStream bis = new ByteArrayInputStream (bytes);
ObjectInputStream ois = new ObjectInputStream (bis);
obj = ois.readObject();
ois.close();
bis.close();
return obj;
}
private void cleanPdfCache() throws IOException, RocksDBException {
Map<String, String> initPDFCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(initPDFCache));
}
private void cleanImgCache() throws IOException, RocksDBException {
Map<String, List<String>> initIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(initIMGCache));
}
private void cleanPdfImgCache() throws IOException, RocksDBException {
Map<String, Integer> initPDFIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(initPDFIMGCache));
}
}

View File

@@ -1,7 +1,7 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.param.ReturnResponse;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
@@ -28,16 +28,15 @@ public class CompressFilePreviewImpl implements FilePreview{
ZipReader zipReader;
@Override
public String filePreviewHandle(String url, Model model) {
FileAttribute fileAttribute=fileUtils.getFileAttribute(url);
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileName=fileAttribute.getName();
String decodedUrl=fileAttribute.getDecodedUrl();
String suffix=fileAttribute.getSuffix();
String fileTree = null;
// 判断文件名是否存在(redis缓存读取)
if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName))) {
ReturnResponse<String> response = downloadUtils.downLoad(decodedUrl, suffix, fileName);
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
@@ -46,15 +45,20 @@ public class CompressFilePreviewImpl implements FilePreview{
fileTree = zipReader.readZipFile(filePath, fileName);
} else if ("rar".equalsIgnoreCase(suffix)) {
fileTree = zipReader.unRar(filePath, fileName);
} else if ("7z".equalsIgnoreCase(suffix)) {
fileTree = zipReader.read7zFile(filePath, fileName);
}
if (fileTree != null && !"null".equals(fileTree)) {
fileUtils.addConvertedFile(fileName, fileTree);
}
fileUtils.addConvertedFile(fileName, fileTree);
} else {
fileTree = fileUtils.getConvertedFile(fileName);
}
if (null != fileTree) {
if (fileTree != null && !"null".equals(fileTree)) {
model.addAttribute("fileTree", fileTree);
return "compress";
} else {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", "压缩文件类型不受支持尝试在压缩的时候选择RAR4格式");
return "fileNotSupported";
}

View File

@@ -0,0 +1,32 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import cn.keking.utils.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
/**
* @author : kl
* @authorboke : kailing.pub
* @create : 2018-03-25 上午11:58
* @description:
**/
@Service
public class MediaFilePreviewImpl implements FilePreview {
@Autowired
FileUtils fileUtils;
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
model.addAttribute("mediaUrl", url);
String suffix=fileAttribute.getSuffix();
if ("flv".equalsIgnoreCase(suffix)) {
return "flv";
}
return "media";
}
}

View File

@@ -1,18 +1,20 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.param.ReturnResponse;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.OfficeToPdf;
import cn.keking.utils.PdfUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import java.io.File;
import java.util.List;
/**
* Created by kl on 2018/1/17.
@@ -24,8 +26,8 @@ public class OfficeFilePreviewImpl implements FilePreview {
@Autowired
FileUtils fileUtils;
@Value("${file.dir}")
String fileDir;
@Autowired
PdfUtils pdfUtils;
@Autowired
DownloadUtils downloadUtils;
@@ -33,26 +35,34 @@ public class OfficeFilePreviewImpl implements FilePreview {
@Autowired
private OfficeToPdf officeToPdf;
String fileDir = ConfigConstants.getFileDir();
public static final String OFFICE_PREVIEW_TYPE_PDF = "pdf";
public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
public static final String OFFICE_PREVIEW_TYPE_ALLIMAGES = "allImages";
@Override
public String filePreviewHandle(String url, Model model) {
FileAttribute fileAttribute=fileUtils.getFileAttribute(url);
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
// 预览Type参数传了就取参数的没传取系统默认
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
String originUrl = (String) model.asMap().get("originUrl");
String suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
String decodedUrl=fileAttribute.getDecodedUrl();
boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx");
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
String outFilePath = fileDir + pdfName;
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
if (!fileUtils.listConvertedFiles().containsKey(pdfName)) {
String filePath = fileDir + fileName;
if (!new File(filePath).exists()) {
ReturnResponse<String> response = downloadUtils.downLoad(decodedUrl, suffix, null);
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
filePath = response.getContent();
}
String outFilePath = fileDir + pdfName;
if (StringUtils.hasText(outFilePath)) {
officeToPdf.openOfficeToPDF(filePath, outFilePath);
File f = new File(filePath);
@@ -67,6 +77,21 @@ public class OfficeFilePreviewImpl implements FilePreview {
fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
}
}
if (!isHtml && originUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALLIMAGES.equals(officePreviewType))) {
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, originUrl);
if (imageUrls == null || imageUrls.size() < 1) {
model.addAttribute("msg", "office转图片异常请联系管理员");
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("imgurls", imageUrls);
model.addAttribute("currentUrl", imageUrls.get(0));
if (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
return "officePicture";
} else {
return "picture";
}
}
model.addAttribute("pdfUrl", pdfName);
return isHtml ? "html" : "pdf";
}

View File

@@ -1,6 +1,9 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import cn.keking.utils.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
@@ -10,8 +13,12 @@ import org.springframework.ui.Model;
*/
@Service
public class OtherFilePreviewImpl implements FilePreview {
@Autowired
FileUtils fileUtils;
@Override
public String filePreviewHandle(String url, Model model) {
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
model.addAttribute("fileType",fileAttribute.getSuffix());
model.addAttribute("msg", "系统还不支持该格式文件的在线预览," +
"如有需要请按下方显示的邮箱地址联系系统维护人员");
return "fileNotSupported";

View File

@@ -1,9 +1,19 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.PdfUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.io.File;
import java.util.List;
/**
* Created by kl on 2018/1/17.
* Content :处理pdf文件
@@ -11,9 +21,52 @@ import org.springframework.ui.Model;
@Service
public class PdfFilePreviewImpl implements FilePreview{
@Autowired
FileUtils fileUtils;
@Autowired
PdfUtils pdfUtils;
@Autowired
DownloadUtils downloadUtils;
String fileDir = ConfigConstants.getFileDir();
@Override
public String filePreviewHandle(String url, Model model) {
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
String originUrl = model.asMap().get("originUrl").toString();
model.addAttribute("pdfUrl", url);
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
String outFilePath = fileDir + pdfName;
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALLIMAGES.equals(officePreviewType)) {
//当文件不存在时,就去下载
if (!new File(outFilePath).exists()) {
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
outFilePath = response.getContent();
}
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, originUrl);
if (imageUrls == null || imageUrls.size() < 1) {
model.addAttribute("msg", "pdf转图片异常请联系管理员");
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("imgurls", imageUrls);
model.addAttribute("currentUrl", imageUrls.get(0));
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
return "officePicture";
} else {
return "picture";
}
}
return "pdf";
}
}

View File

@@ -1,5 +1,6 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import cn.keking.utils.FileUtils;
import com.google.common.collect.Lists;
@@ -21,7 +22,7 @@ public class PictureFilePreviewImpl implements FilePreview {
FileUtils fileUtils;
@Override
public String filePreviewHandle(String url, Model model) {
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileKey=(String) RequestContextHolder.currentRequestAttributes().getAttribute("fileKey",0);
List imgUrls = Lists.newArrayList(url);
try{

View File

@@ -1,8 +1,7 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.param.ReturnResponse;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.FileUtils;
import cn.keking.utils.SimTextUtil;
@@ -10,8 +9,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.net.URLDecoder;
/**
* Created by kl on 2018/1/17.
* Content :处理文本文件
@@ -26,13 +23,13 @@ public class SimTextFilePreviewImpl implements FilePreview{
FileUtils fileUtils;
@Override
public String filePreviewHandle(String url, Model model){
FileAttribute fileAttribute=fileUtils.getFileAttribute(url);
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute){
String decodedUrl=fileAttribute.getDecodedUrl();
String fileName=fileAttribute.getName();
ReturnResponse<String> response = simTextUtil.readSimText(decodedUrl, fileName);
if (0 != response.getCode()) {
model.addAttribute("msg", response.getMsg());
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("ordinaryUrl", response.getMsg());

View File

@@ -5,6 +5,7 @@ import cn.keking.extend.ControlDocumentFormatRegistry;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -23,8 +24,8 @@ import java.util.Map;
@Component
public class ConverterUtils {
@Value("${office.home}")
String officeHome;
// @Value("${office.home}")
// String officeHome;
// OpenOfficeConnection connection;
OfficeManager officeManager;
@@ -32,6 +33,7 @@ public class ConverterUtils {
public void initOfficeManager() {
//// connection = new SocketOpenOfficeConnection(host,8100);
//// connection.connect();
String officeHome = OfficeUtils.getDefaultOfficeHome().getAbsolutePath();
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
configuration.setOfficeHome(officeHome);
configuration.setPortNumber(8100);

View File

@@ -1,8 +1,14 @@
package cn.keking.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
public class DeleteFileUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(DeleteFileUtil.class);
/**
* 删除单个文件
*
@@ -15,14 +21,14 @@ public class DeleteFileUtil {
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删除单个文件" + fileName + "成功!");
LOGGER.info("删除单个文件" + fileName + "成功!");
return true;
} else {
System.out.println("删除单个文件" + fileName + "失败!");
LOGGER.info("删除单个文件" + fileName + "失败!");
return false;
}
} else {
System.out.println("删除单个文件失败:" + fileName + "不存在!");
LOGGER.info("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
@@ -43,7 +49,7 @@ public class DeleteFileUtil {
File dirFile = new File(dir);
// 如果dir对应的文件不存在或者不是一个目录则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
System.out.println("删除目录失败:" + dir + "不存在!");
LOGGER.info("删除目录失败:" + dir + "不存在!");
return false;
}
boolean flag = true;
@@ -65,7 +71,7 @@ public class DeleteFileUtil {
}
}
if (!flag) {
System.out.println("删除目录失败!");
LOGGER.info("删除目录失败!");
return false;
}
return true;

View File

@@ -1,11 +1,14 @@
package cn.keking.utils;
import cn.keking.param.ReturnResponse;
import org.springframework.beans.factory.annotation.Value;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.util.UUID;
/**
@@ -14,8 +17,16 @@ import java.util.UUID;
@Component
public class DownloadUtils {
@Value("${file.dir}")
String fileDir;
private static final Logger LOGGER = LoggerFactory.getLogger(DownloadUtils.class);
private String fileDir = ConfigConstants.getFileDir();
@Autowired
private FileUtils fileUtils;
private static final String URL_PARAM_FTP_USERNAME = "ftp.username";
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
/**
* 一开始测试的时候发现有些文件没有下载下来,而有些可以;当时也是郁闷了好一阵,但是最终还是不得解
@@ -23,11 +34,12 @@ public class DownloadUtils {
* 应该是转义出了问题url转义中会把+号当成空格来计算所以才会出现这种情况遂想要通过整体替换空格为加号因为url
* 中的参数部分是不会出现空格的但是文件名中就不好确定了所以只对url参数部分做替换
* 注: 针对URLEncoder.encode(s,charset)会将空格转成+的情况需要做下面的替换工作
* @param urlAddress
* @param type
* @param fileAttribute
* @return
*/
public ReturnResponse<String> downLoad(String urlAddress, String type, String fileName){
public ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
String urlAddress = fileAttribute.getDecodedUrl();
String type = fileAttribute.getSuffix();
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
URL url = null;
try {
@@ -42,7 +54,7 @@ public class DownloadUtils {
UUID uuid = UUID.randomUUID();
if (null == fileName) {
fileName = uuid+ "."+type;
}else { // 文件后缀不一致时以type为准(针对simText【将类txt文件转为txt】)
} else { // 文件后缀不一致时以type为准(针对simText【将类txt文件转为txt】)
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
}
String realPath = fileDir + fileName;
@@ -51,17 +63,24 @@ public class DownloadUtils {
dirFile.mkdirs();
}
try {
URLConnection connection = url.openConnection();
InputStream in = connection.getInputStream();
if ("ftp".equals(url.getProtocol())) {
String ftpUsername = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
String ftpPassword = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
String ftpControlEncoding = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
} else {
URLConnection connection = url.openConnection();
InputStream in = connection.getInputStream();
FileOutputStream os = new FileOutputStream(realPath);
byte[] buffer = new byte[4 * 1024];
int read;
while ((read = in.read(buffer)) > 0) {
os.write(buffer, 0, read);
FileOutputStream os = new FileOutputStream(realPath);
byte[] buffer = new byte[4 * 1024];
int read;
while ((read = in.read(buffer)) > 0) {
os.write(buffer, 0, read);
}
os.close();
in.close();
}
os.close();
in.close();
response.setContent(realPath);
// 同样针对类txt文件如果成功msg包含的是转换后的文件名
response.setMsg(fileName);
@@ -70,15 +89,14 @@ public class DownloadUtils {
if("txt".equals(type)){
convertTextPlainFileCharsetToUtf8(realPath);
}
return response;
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("文件下载失败", e);
response.setCode(1);
response.setContent(null);
if (e instanceof FileNotFoundException) {
response.setMsg("文件不存在!!!");
}else {
} else {
response.setMsg(e.getMessage());
}
return response;

View File

@@ -1,20 +1,21 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.service.cache.CacheService;
import com.google.common.collect.Lists;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -27,26 +28,17 @@ import java.util.Map;
public class FileUtils {
Logger log= LoggerFactory.getLogger(getClass());
final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
final String REDIS_FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
@Autowired
RedissonClient redissonClient;
@Value("${file.dir}")
String fileDir;
CacheService cacheService;
@Value("${converted.file.charset}")
String charset;
String fileDir = ConfigConstants.getFileDir();
@Value("${simText}")
String[] simText;
/**
* 已转换过的文件集合(redis缓存)
* @return
*/
public Map<String, String> listConvertedFiles() {
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
return convertedList;
return cacheService.getPDFCache();
}
/**
@@ -54,8 +46,16 @@ public class FileUtils {
* @return
*/
public String getConvertedFile(String key) {
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
return convertedList.get(key);
return cacheService.getPDFCache(key);
}
/**
* 已将pdf转换成图片的图片本地路径
* @param key pdf本地路径
* @return
*/
public Integer getConvertedPdfImage(String key) {
return cacheService.getPdfImageCache(key);
}
/**
@@ -67,9 +67,15 @@ public class FileUtils {
public FileType typeFromUrl(String url) {
String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
return typeFromFileName(fileName);
}
private FileType typeFromFileName(String fileName) {
String[] simText = ConfigConstants.getSimText();
String[] media = ConfigConstants.getMedia();
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
if (listPictureTypes().contains(fileType.toLowerCase())) {
return FileType.picture;
return FileType.picture;
}
if (listArchiveTypes().contains(fileType.toLowerCase())) {
return FileType.compress;
@@ -80,6 +86,9 @@ public class FileUtils {
if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
return FileType.simText;
}
if (Arrays.asList(media).contains(fileType.toLowerCase())) {
return FileType.media;
}
if("pdf".equalsIgnoreCase(fileType)){
return FileType.pdf;
}
@@ -164,8 +173,16 @@ public class FileUtils {
}
public void addConvertedFile(String fileName, String value){
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
convertedList.fastPut(fileName, value);
cacheService.putPDFCache(fileName, value);
}
/**
*
* @param pdfFilePath
* @param num
*/
public void addConvertedPdfImage(String pdfFilePath, int num){
cacheService.putPdfImageCache(pdfFilePath, num);
}
/**
@@ -174,8 +191,7 @@ public class FileUtils {
* @return
*/
public List getRedisImgUrls(String fileKey){
RMapCache<String, List> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
return convertedList.get(fileKey);
return cacheService.getImgCache(fileKey);
}
/**
@@ -184,8 +200,7 @@ public class FileUtils {
* @param imgs
*/
public void setRedisImgUrls(String fileKey,List imgs){
RMapCache<String, List> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
convertedList.fastPut(fileKey,imgs);
cacheService.putImgCache(fileKey, imgs);
}
/**
* 判断文件编码格式
@@ -219,6 +234,7 @@ public class FileUtils {
*/
public void doActionConvertedFile(String outFilePath) {
StringBuffer sb = new StringBuffer();
String charset = ConfigConstants.getConvertedFileCharset();
try (InputStream inputStream = new FileInputStream(outFilePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset))){
String line;
@@ -239,7 +255,7 @@ public class FileUtils {
}
// 重新写入文件
try(FileOutputStream fos = new FileOutputStream(outFilePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos))){
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"))) {
writer.write(sb.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
@@ -255,22 +271,83 @@ public class FileUtils {
private String suffixFromUrl(String url) {
String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
return suffixFromFileName(fileName);
}
private String suffixFromFileName(String fileName) {
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
return fileType;
}
/**
* 获取url中的参数
* @param url
* @param name
* @return
*/
public String getUrlParameterReg(String url, String name) {
Map<String, String> mapRequest = new HashMap();
String strUrlParam = truncateUrlPage(url);
if (strUrlParam == null) {
return "";
}
//每个键值为一组
String[] arrSplit=strUrlParam.split("[&]");
for(String strSplit:arrSplit) {
String[] arrSplitEqual= strSplit.split("[=]");
//解析出键值
if(arrSplitEqual.length > 1) {
//正确解析
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
} else if (!arrSplitEqual[0].equals("")) {
//只有参数没有值,不加入
mapRequest.put(arrSplitEqual[0], "");
}
}
return mapRequest.get(name);
}
/**
* 去掉url中的路径留下请求参数部分
* @param strURL url地址
* @return url请求参数部分
*/
private String truncateUrlPage(String strURL) {
String strAllParam = null;
strURL = strURL.trim();
String[] arrSplit = strURL.split("[?]");
if(strURL.length() > 1) {
if(arrSplit.length > 1) {
if(arrSplit[1] != null) {
strAllParam=arrSplit[1];
}
}
}
return strAllParam;
}
public FileAttribute getFileAttribute(String url) {
String decodedUrl=null;
String decodedUrl = null;
try {
decodedUrl = URLDecoder.decode(url, "utf-8");
}catch (UnsupportedEncodingException e){
log.debug("url解码失败");
} catch (UnsupportedEncodingException e){
log.error("url解码失败");
}
String fileName;
FileType type;
String suffix;
String fullFileName = getUrlParameterReg(decodedUrl, "fullfilename");
if (!StringUtils.isEmpty(fullFileName)) {
fileName = fullFileName;
type = typeFromFileName(fileName);
suffix = suffixFromFileName(fileName);
} else {
fileName = getFileNameFromURL(decodedUrl);
type = typeFromUrl(url);
suffix = suffixFromUrl(url);
}
// 路径转码
FileType type = typeFromUrl(url);
String suffix = suffixFromUrl(url);
// 抽取文件并返回文件列表
String fileName = getFileNameFromURL(decodedUrl);
return new FileAttribute(type,suffix,fileName,url,decodedUrl);
}
}

View File

@@ -0,0 +1,57 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
/**
* @auther: chenjh
* @since: 2019/6/18 14:36
*/
public class FtpUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(FtpUtils.class);
public static FTPClient connect(String host, int port, String username, String password, String controlEncoding) throws IOException {
FTPClient ftpClient = new FTPClient();
ftpClient.connect(host, port);
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
ftpClient.login(username, password);
}
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
}
ftpClient.setControlEncoding(controlEncoding);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
return ftpClient;
}
public static void download(String ftpUrl, String localFilePath, String ftpUsername, String ftpPassword, String ftpControlEncoding) throws IOException {
String username = StringUtils.isEmpty(ftpUsername) ? ConfigConstants.getFtpUsername() : ftpUsername;
String password = StringUtils.isEmpty(ftpPassword) ? ConfigConstants.getFtpPassword() : ftpPassword;
String controlEncoding = StringUtils.isEmpty(ftpControlEncoding) ? ConfigConstants.getFtpControlEncoding() : ftpControlEncoding;
URL url = new URL(ftpUrl);
String host = url.getHost();
int port = (url.getPort() == -1) ? url.getDefaultPort() : url.getPort();
String remoteFilePath = url.getPath();
LOGGER.debug("FTP connection url:{}, username:{}, password:{}, controlEncoding:{}, localFilePath:{}", ftpUrl, username, password, controlEncoding, localFilePath);
FTPClient ftpClient = connect(host, port, username, password, controlEncoding);
OutputStream outputStream = new FileOutputStream(localFilePath);
ftpClient.enterLocalPassiveMode();
boolean downloadResult = ftpClient.retrieveFile(new String(remoteFilePath.getBytes(controlEncoding), "ISO-8859-1"), outputStream);
LOGGER.debug("FTP download result {}", downloadResult);
outputStream.flush();
outputStream.close();
ftpClient.logout();
ftpClient.disconnect();
}
}

View File

@@ -0,0 +1,66 @@
package cn.keking.utils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Component
public class PdfUtils {
private final Logger LOGGER = LoggerFactory.getLogger(PdfUtils.class);
@Autowired
FileUtils fileUtils;
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String url) {
List<String> imageUrls = new ArrayList<>();
Integer imageCount = fileUtils.getConvertedPdfImage(pdfFilePath);
String imageFileSuffix = ".jpg";
// https://8个字符 http://7个字符 从这后面开始出现的第一个/就是当前file.Dir下的根目录
int index1 = url.indexOf("/", 8);
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
String urlPrefix = url.substring(0, index1 + 1) + pdfFolder;
if (imageCount != null && imageCount.intValue() > 0) {
for (int i = 0; i < imageCount ; i++)
imageUrls.add(urlPrefix + "/" + i + imageFileSuffix);
return imageUrls;
}
try {
File pdfFile = new File(pdfFilePath);
PDDocument doc = PDDocument.load(pdfFile);
int pageCount = doc.getNumberOfPages();
PDFRenderer pdfRenderer = new PDFRenderer(doc);
int index = pdfFilePath.lastIndexOf(".");
String folder = pdfFilePath.substring(0, index);
File path = new File(folder);
if (!path.exists()) {
path.mkdirs();
}
String imageFilePath;
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
imageFilePath = folder + File.separator + pageIndex + imageFileSuffix;
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 105, ImageType.RGB);
ImageIOUtil.writeImage(image, imageFilePath, 105);
imageUrls.add(urlPrefix + "/" + pageIndex + imageFileSuffix);
}
doc.close();
fileUtils.addConvertedPdfImage(pdfFilePath, pageCount);
} catch (IOException e) {
LOGGER.error("Convert pdf to jpg exception", e);
}
return imageUrls;
}
}

View File

@@ -1,16 +1,34 @@
package cn.keking.utils;
import org.springframework.beans.factory.annotation.Value;
import cn.keking.config.ConfigConstants;
import cn.keking.service.cache.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @auther: chenjh
* @since: 2019/6/11 7:45
*/
@Component
@ConditionalOnExpression("'${cache.clean:false}'.equals('true')")
public class ShedulerClean {
@Value("${file.dir}")
String fileDir;
// @Scheduled(cron = "0 0 23 * * ?") //每晚23点执行一次
public void clean(){
System.out.println("执行一次清空文件夹");
private static final Logger LOGGER = LoggerFactory.getLogger(ShedulerClean.class);
@Autowired
private CacheService cacheService;
private String fileDir = ConfigConstants.getFileDir();
@Scheduled(cron = "0 0 3 * * ?") //每晚3点执行一次
public void clean() {
LOGGER.info("Cache clean start");
cacheService.cleanCache();
DeleteFileUtil.deleteDirectory(fileDir);
LOGGER.info("Cache clean end");
}
}

View File

@@ -1,8 +1,9 @@
package cn.keking.utils;
import cn.keking.param.ReturnResponse;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
@@ -12,13 +13,14 @@ import org.springframework.stereotype.Component;
*/
@Component
public class SimTextUtil {
@Value("${file.dir}")
String fileDir;
@Autowired
DownloadUtils downloadUtils;
private FileUtils fileUtils;
@Autowired
private DownloadUtils downloadUtils;
public ReturnResponse<String> readSimText(String url, String fileName){
ReturnResponse<String> response = downloadUtils.downLoad(url, "txt", fileName);
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
return response;
}
}

View File

@@ -1,5 +1,6 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileType;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -8,10 +9,11 @@ import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
@@ -36,8 +38,7 @@ public class ZipReader {
@Autowired
FileUtils fileUtils;
@Value("${file.dir}")
String fileDir;
String fileDir = ConfigConstants.getFileDir();
ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
@@ -121,7 +122,7 @@ public class ZipReader {
List imgUrls=Lists.newArrayList();
String baseUrl= (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
try {
Archive archive = new Archive(new File(filePath));
Archive archive = new Archive(new FileInputStream(new File(filePath)));
List<FileHeader> headers = archive.getFileHeaders();
headers = sortedHeaders(headers);
String archiveFileName = fileUtils.getFileNameFromPath(filePath);
@@ -161,6 +162,71 @@ public class ZipReader {
return null;
}
/**
* 解压7z文件
* @param filePath
* @param fileKey
* @return
*/
public String read7zFile(String filePath,String fileKey) {
String archiveSeparator = "/";
Map<String, FileNode> appender = Maps.newHashMap();
List imgUrls=Lists.newArrayList();
String baseUrl= (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
String archiveFileName = fileUtils.getFileNameFromPath(filePath);
try {
SevenZFile zipFile = new SevenZFile(new File(filePath));
Iterable<SevenZArchiveEntry> entries = zipFile.getEntries();
// 排序
Enumeration<SevenZArchiveEntry> newEntries = sortSevenZEntries(entries);
List<Map<String, SevenZArchiveEntry>> entriesToBeExtracted = Lists.newArrayList();
while (newEntries.hasMoreElements()){
SevenZArchiveEntry entry = newEntries.nextElement();
String fullName = entry.getName();
int level = fullName.split(archiveSeparator).length;
// 展示名
String originName = getLastFileName(fullName, archiveSeparator);
String childName = level + "_" + originName;
boolean directory = entry.isDirectory();
if (!directory) {
childName = archiveFileName + "_" + originName;
entriesToBeExtracted.add(Collections.singletonMap(childName, entry));
}
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level-1) + "_" + parentName;
FileType type=fileUtils.typeFromUrl(childName);
if (type.equals(FileType.picture)){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory,fileKey);
addNodes(appender, parentName, node);
appender.put(childName, node);
}
// 开启新的线程处理文件解压
executors.submit(new SevenZExtractorWorker(entriesToBeExtracted, filePath));
fileUtils.setRedisImgUrls(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 排序7ZEntries(对原来列表倒序)
* @param entries
*/
private Enumeration<SevenZArchiveEntry> sortSevenZEntries(Iterable<SevenZArchiveEntry> entries) {
List<SevenZArchiveEntry> sortedEntries = Lists.newArrayList();
Iterator<SevenZArchiveEntry> iterator = entries.iterator();
while(iterator.hasNext()){
sortedEntries.add(iterator.next());
}
// Collections.sort(sortedEntries, Comparator.comparingInt(o -> o.getName().length()));
return Collections.enumeration(sortedEntries);
}
private void addNodes(Map<String, FileNode> appender, String parentName, FileNode node) {
if (appender.containsKey(parentName)) {
appender.get(parentName).getChildList().add(node);
@@ -177,10 +243,10 @@ public class ZipReader {
private List<FileHeader> sortedHeaders(List<FileHeader> headers) {
List<FileHeader> sortedHeaders = new ArrayList<>();
Map<Integer, FileHeader> mapHeaders = new TreeMap<>();
headers.forEach(header -> mapHeaders.put(header.getFileNameW().length(), header));
headers.forEach(header -> mapHeaders.put(new Integer(0).equals(header.getFileNameW().length()) ? header.getFileNameString().length() : header.getFileNameW().length(), header));
for (Map.Entry<Integer, FileHeader> entry : mapHeaders.entrySet()){
for (FileHeader header : headers) {
if (entry.getKey().intValue() == header.getFileNameW().length()) {
if (entry.getKey().equals(new Integer(0).equals(header.getFileNameW().length()) ? header.getFileNameString().length() : header.getFileNameW().length())) {
sortedHeaders.add(header);
}
}
@@ -403,6 +469,60 @@ public class ZipReader {
}
}
/**
* 7z文件抽取线程
*/
class SevenZExtractorWorker implements Runnable {
private List<Map<String, SevenZArchiveEntry>> entriesToBeExtracted;
private String filePath;
public SevenZExtractorWorker(List<Map<String, SevenZArchiveEntry>> entriesToBeExtracted, String filePath) {
this.entriesToBeExtracted = entriesToBeExtracted;
this.filePath = filePath;
}
@Override
public void run() {
System.out.println("解析压缩文件开始《《《《《《《《《《《《《《《《《《《《《《《");
try {
SevenZFile sevenZFile = new SevenZFile(new File(filePath));
SevenZArchiveEntry entry = sevenZFile.getNextEntry();
while (entry != null) {
if (entry.isDirectory()) {
entry = sevenZFile.getNextEntry();
continue;
}
String childName = "default_file";
SevenZArchiveEntry entry1 = null;
for (Map<String, SevenZArchiveEntry> entryMap : entriesToBeExtracted) {
childName = entryMap.keySet().iterator().next();
entry1 = entryMap.values().iterator().next();
if (entry.getName().equals(entry1.getName())) {
break;
}
}
FileOutputStream out = new FileOutputStream(fileDir + childName);
byte[] content = new byte[(int) entry.getSize()];
sevenZFile.read(content, 0, content.length);
out.write(content);
out.close();
entry = sevenZFile.getNextEntry();
}
sevenZFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (new File(filePath).exists()) {
new File(filePath).delete();
}
System.out.println("解析压缩文件结束《《《《《《《《《《《《《《《《《《《《《《《");
}
}
/**
* Rar文件抽取
*/

View File

@@ -1,13 +1,13 @@
package cn.keking.web.controller;
import cn.keking.config.ConfigConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import cn.keking.param.ReturnResponse;
import cn.keking.model.ReturnResponse;
import cn.keking.utils.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@@ -28,8 +28,7 @@ import java.util.UUID;
*/
@RestController
public class FileController {
@Value("${file.dir}")
String fileDir;
String fileDir = ConfigConstants.getFileDir();
@Autowired
FileUtils fileUtils;
String demoDir = "demo";

View File

@@ -1,26 +1,28 @@
package cn.keking.web.controller;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import cn.keking.service.FilePreviewFactory;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @author yudian-it
@@ -28,9 +30,17 @@ import java.util.Map;
@Controller
public class OnlinePreviewController {
private static final Logger LOGGER = LoggerFactory.getLogger(OnlinePreviewController.class);
@Autowired
FilePreviewFactory previewFactory;
@Autowired
CacheService cacheService;
@Autowired
private FileUtils fileUtils;
/**
* @param url
* @param model
@@ -38,9 +48,12 @@ public class OnlinePreviewController {
*/
@RequestMapping(value = "onlinePreview", method = RequestMethod.GET)
public String onlinePreview(String url, Model model, HttpServletRequest req) {
req.setAttribute("fileKey",req.getParameter("fileKey"));
FilePreview filePreview=previewFactory.get(url);
return filePreview.filePreviewHandle(url,model);
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
req.setAttribute("fileKey", req.getParameter("fileKey"));
model.addAttribute("officePreviewType", req.getParameter("officePreviewType"));
model.addAttribute("originUrl", req.getRequestURL().toString());
FilePreview filePreview = previewFactory.get(fileAttribute);
return filePreview.filePreviewHandle(url, model, fileAttribute);
}
/**
@@ -52,17 +65,32 @@ public class OnlinePreviewController {
* @throws UnsupportedEncodingException
*/
@RequestMapping(value = "picturesPreview", method = RequestMethod.GET)
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
public String picturesPreview(String urls, String currentUrl, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
// 路径转码
String decodedUrl = URLDecoder.decode(urls, "utf-8");
String decodedCurrentUrl = URLDecoder.decode(currentUrl, "utf-8");
// 抽取文件并返回文件列表
String[] imgs = decodedUrl.split("|");
String[] imgs = decodedUrl.split("\\|");
List imgurls = Arrays.asList(imgs);
model.addAttribute("imgurls", imgurls);
model.addAttribute("currentUrl",decodedCurrentUrl);
return "picture";
}
@RequestMapping(value = "picturesPreview", method = RequestMethod.POST)
public String picturesPreview(Model model, HttpServletRequest req) throws UnsupportedEncodingException {
String urls = req.getParameter("urls");
String currentUrl = req.getParameter("currentUrl");
// 路径转码
String decodedUrl = URLDecoder.decode(urls, "utf-8");
String decodedCurrentUrl = URLDecoder.decode(currentUrl, "utf-8");
// 抽取文件并返回文件列表
String[] imgs = decodedUrl.split("\\|");
List imgurls = Arrays.asList(imgs);
model.addAttribute("imgurls", imgurls);
model.addAttribute("currentUrl",decodedCurrentUrl);
return "picture";
}
/**
* 根据url获取文件内容
* 当pdfjs读取存在跨域问题的文件时将通过此接口读取
@@ -75,7 +103,7 @@ public class OnlinePreviewController {
InputStream inputStream = null;
try {
String strUrl = urlPath.trim();
URL url = new URL(strUrl);
URL url = new URL(new URI(strUrl).toASCIIString());
//打开请求连接
URLConnection connection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
@@ -86,8 +114,8 @@ public class OnlinePreviewController {
while (-1 != (len = inputStream.read(bs))) {
resp.getOutputStream().write(bs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} catch (IOException | URISyntaxException e) {
LOGGER.error("下载pdf文件失败", e);
} finally {
if (inputStream != null) {
IOUtils.closeQuietly(inputStream);
@@ -95,4 +123,15 @@ public class OnlinePreviewController {
}
}
/**
* 通过api接口入队
* @param url 请编码后在入队
*/
@GetMapping("/addTask")
@ResponseBody
public String addQueueTask(String url) {
cacheService.addQueueTask(url);
return "success";
}
}

View File

View File

@@ -0,0 +1,54 @@
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
***********************************************************-->
<xsl:stylesheet version="1.0" encoding="UTF-8"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:office="http://openoffice.org/2000/office"
xmlns:style="http://openoffice.org/2000/style"
xmlns:table="http://openoffice.org/2000/table"
xmlns:draw="http://openoffice.org/2000/drawing"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:meta="http://openoffice.org/2000/meta"
xmlns:number="http://openoffice.org/2000/datastyle"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:chart="http://openoffice.org/2000/chart"
xmlns:help="http://openoffice.org/2000/help"
xmlns:index="http://sun.com/2000/XMLSearch"
xmlns:text="http://openoffice.org/2000/text">
<xsl:param name="Language" select="'en-US'"/>
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates select="//title" mode="include"/>
<xsl:apply-templates select="//paragraph[@role='heading']" mode="include"/>
</xsl:template>
<xsl:template match="*" mode="include">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>

View File

@@ -0,0 +1,124 @@
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
***********************************************************-->
<xsl:stylesheet version="1.0" encoding="UTF-8"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:office="http://openoffice.org/2000/office"
xmlns:style="http://openoffice.org/2000/style"
xmlns:table="http://openoffice.org/2000/table"
xmlns:draw="http://openoffice.org/2000/drawing"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:meta="http://openoffice.org/2000/meta"
xmlns:number="http://openoffice.org/2000/datastyle"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:chart="http://openoffice.org/2000/chart"
xmlns:help="http://openoffice.org/2000/help"
xmlns:index="http://sun.com/2000/XMLSearch"
xmlns:text="http://openoffice.org/2000/text">
<xsl:param name="Language" select="'en-US'"/>
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="helpdocument|body">
<xsl:choose>
<xsl:when test="meta/topic[@indexer='exclude']"/>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="title">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="table">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="tablecell">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="tablerow">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="list">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="listitem">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="item">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="emph">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="paragraph">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="section">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="bookmark">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="bookmark_value">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="link">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="ahelp[@visibility='visible']">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ DEFAULT STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; border: 1px solid #999999; background: #FFFFFF; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.howtoget
{ background:#EEEEEE;}
.howtogetbody
{ background:#EEEEEE;}
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
***********************************************************-->
<helpdocument version="1.0">
<meta>
<topic id="textshared05err_htmlxml" indexer="exclude" status="PUBLISH">
<title id="tit" xml-lang="zh-CN">未找到帮助页面</title>
<filename>/text/shared/05/err_html.xhp</filename>
</topic>
<history>
<created date="2003-10-31T00:00:00">Sun Microsystems, Inc.</created>
<lastedited date="2005-01-11T11:07:13">converted from old format - fpe
FPE: Updated</lastedited>
</history>
</meta>
<body>
<paragraph role="heading" id="hd_id3146957" xml-lang="zh-CN" level="1" l10n="U" oldref="1">帮助页面未能找到。</paragraph>
<paragraph role="paragraph" id="par_id3147088" xml-lang="zh-CN" l10n="U" oldref="2">很遗憾,您所选择的帮助页面未能找到。以下数据可能对界定错误有所帮助:</paragraph>
<paragraph role="paragraph" id="par_id3143268" xml-lang="zh-CN" l10n="U" oldref="3">帮助 ID<emph><help-id-missing/></emph></paragraph>
<paragraph role="paragraph" id="par_idN10681" xml-lang="zh-CN" l10n="NEW">可以使用安装应用程序来安装缺少的帮助模块。</paragraph>
<paragraph role="paragraph" id="par_id3150541" xml-lang="zh-CN" l10n="U" oldref="16">单击<image id="img_id3148946" src="res/sc06301.png" width="0.222inch" height="0.222inch"><alt id="alt_id3148946">图标</alt></image><emph>上一步</emph>可返回上一页面。</paragraph>
</body>
</helpdocument>

View File

@@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST #1 STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #000000; color: #FFFF00;}
.related
{ border-top: 1px solid #FFFF00; }
.howtogetheader
{border: 1px solid #EFEFEF; background: #000000;}
h1
{ border-bottom: 1px solid #FFFF00; ]
.howtoget
{ background:#000000;}
.howtogetbody
{ background:#000000;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #FFFF00; }

View File

@@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST #2 STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #000000; color: #00FF00;}
.related
{ border-top: 1px solid #00FF00; }
.howtogetheader
{border: 1px solid #EFEFEF; background: #000000;}
h1
{ border-bottom: 1px solid #00FF00; ]
.howtoget
{ background:#000000;}
.howtogetbody
{ background:#000000;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #00FF00; }

Some files were not shown because too many files have changed in this diff Show More