Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e86de1e8e | ||
|
|
106036d989 | ||
|
|
026656711d | ||
|
|
35a8c4a5a6 | ||
|
|
86960e3813 | ||
|
|
b099d52520 | ||
|
|
6efe15788c | ||
|
|
3e43c2f9d0 | ||
|
|
f1b949865f | ||
|
|
ab439a17a3 | ||
|
|
dd65564af6 | ||
|
|
acffcbfe98 | ||
|
|
04703aa03c | ||
|
|
584e6b2c77 | ||
|
|
82f6d3565f | ||
|
|
8c68834e17 | ||
|
|
ba7b6eed4a | ||
|
|
051ad0f4ea | ||
|
|
05935c29e1 | ||
|
|
6a2735ec3d | ||
|
|
8bc53f76eb | ||
|
|
48f6a507dc | ||
|
|
20f328906c | ||
|
|
4d1e2eb9c6 | ||
|
|
97542b06fa | ||
|
|
0c93c7e4b6 | ||
|
|
56d9906c74 | ||
|
|
5cfe37433f | ||
|
|
45ebef3b74 | ||
|
|
2ed294bd65 | ||
|
|
91f3348a2f | ||
|
|
d424de5e9a | ||
|
|
6387ac21c9 | ||
|
|
6dce47e47f | ||
|
|
b7760ab42a | ||
|
|
e0405bc5f6 | ||
|
|
14151a6c46 | ||
|
|
00555d3544 | ||
|
|
7b2adc3979 | ||
|
|
0a5fc1e4a8 | ||
|
|
304d974b38 | ||
|
|
6792a7afa7 | ||
|
|
ded297de59 | ||
|
|
f616678d83 | ||
|
|
e10273dcdd | ||
|
|
343269670c | ||
|
|
8af157b848 | ||
|
|
9d65c999e5 | ||
|
|
4fe0d0edc9 | ||
|
|
b1aab27338 | ||
|
|
727e9ae9ed | ||
|
|
dc9df5d760 | ||
|
|
b7de791658 | ||
|
|
82c7b59650 | ||
|
|
e0b9d8f476 | ||
|
|
db2ed3a555 | ||
|
|
6efc375066 | ||
|
|
9a4c864490 | ||
|
|
a3081ef4a9 | ||
|
|
43374e02bd | ||
|
|
fb8a19469b | ||
|
|
f2d5f4a86c | ||
|
|
2177aed64f | ||
|
|
d20ac8fafc | ||
|
|
2395a489a3 | ||
|
|
0b8eedf935 |
24
.github/workflows/maven.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Java CI with Maven
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'adopt'
|
||||
cache: maven
|
||||
- name: Build with Maven
|
||||
run: mvn -B package --file pom.xml
|
||||
53
.workflow/BranchPipeline.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: '1.0'
|
||||
name: branch-pipeline
|
||||
displayName: BranchPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@maven
|
||||
name: build_maven
|
||||
displayName: Maven 构建
|
||||
# 支持6、7、8、9、10、11六个版本
|
||||
jdkVersion: 8
|
||||
# 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本
|
||||
mavenVersion: 3.3.9
|
||||
# 构建命令
|
||||
commands:
|
||||
- mvn -B clean package -Dmaven.test.skip=true
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录
|
||||
path:
|
||||
- ./server/target
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_maven
|
||||
- stage:
|
||||
name: release
|
||||
displayName: 发布
|
||||
steps:
|
||||
- step: publish@release_artifacts
|
||||
name: publish_release_artifacts
|
||||
displayName: '发布'
|
||||
# 上游上传制品任务的产出
|
||||
dependArtifact: output
|
||||
# 发布制品版本号
|
||||
version: '1.0.0.0'
|
||||
# 是否开启版本号自增,默认开启
|
||||
autoIncrement: true
|
||||
triggers:
|
||||
push:
|
||||
branches:
|
||||
exclude:
|
||||
- master
|
||||
include:
|
||||
- .*
|
||||
51
.workflow/MasterPipeline.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
version: '1.0'
|
||||
name: master-pipeline
|
||||
displayName: MasterPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@maven
|
||||
name: build_maven
|
||||
displayName: Maven 构建
|
||||
# 支持6、7、8、9、10、11六个版本
|
||||
jdkVersion: 8
|
||||
# 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本
|
||||
mavenVersion: 3.3.9
|
||||
# 构建命令
|
||||
commands:
|
||||
- mvn -B clean package -Dmaven.test.skip=true
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录
|
||||
path:
|
||||
- ./server/target
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_maven
|
||||
- stage:
|
||||
name: release
|
||||
displayName: 发布
|
||||
steps:
|
||||
- step: publish@release_artifacts
|
||||
name: publish_release_artifacts
|
||||
displayName: '发布'
|
||||
# 上游上传制品任务的产出
|
||||
dependArtifact: output
|
||||
# 发布制品版本号
|
||||
version: '1.0.0.0'
|
||||
# 是否开启版本号自增,默认开启
|
||||
autoIncrement: true
|
||||
triggers:
|
||||
push:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
40
.workflow/PRPipeline.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
version: '1.0'
|
||||
name: pr-pipeline
|
||||
displayName: PRPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@maven
|
||||
name: build_maven
|
||||
displayName: Maven 构建
|
||||
# 支持6、7、8、9、10、11六个版本
|
||||
jdkVersion: 8
|
||||
# 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本
|
||||
mavenVersion: 3.3.9
|
||||
# 构建命令
|
||||
commands:
|
||||
- mvn -B clean package -Dmaven.test.skip=true
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录
|
||||
path:
|
||||
- ./server/target
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 构建产物制品库,默认default,系统默认创建
|
||||
artifactRepository: default
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_maven
|
||||
triggers:
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
36
.workflow/pipeline-20220716.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
version: '1.0'
|
||||
name: pipeline-20220716
|
||||
displayName: pipeline-20220716
|
||||
triggers:
|
||||
trigger: manual
|
||||
push:
|
||||
branches:
|
||||
prefix:
|
||||
- ''
|
||||
stages:
|
||||
- name: stage-8b46aafe
|
||||
displayName: 未命名
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: build@maven
|
||||
name: build_maven
|
||||
displayName: Maven 构建
|
||||
jdkVersion: '8'
|
||||
mavenVersion: 3.3.9
|
||||
commands:
|
||||
- mvn -B clean package -Dmaven.test.skip=true
|
||||
artifacts:
|
||||
- name: BUILD_ARTIFACT
|
||||
path:
|
||||
- ./server/target
|
||||
settings: []
|
||||
caches:
|
||||
- ~/.m2
|
||||
notify: []
|
||||
strategy:
|
||||
retry: '0'
|
||||
permissions:
|
||||
- role: admin
|
||||
members: []
|
||||
42
Dockerfile
@@ -1,41 +1,5 @@
|
||||
FROM ubuntu:20.04
|
||||
FROM keking/kkfileview-jdk:4.1.1
|
||||
MAINTAINER chenjh "842761733@qq.com"
|
||||
ADD server/target/kkFileView-*.tar.gz /opt/
|
||||
COPY fonts/* /usr/share/fonts/chinese/
|
||||
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" > /etc/apt/sources.list &&\
|
||||
apt-get clean && apt-get update &&\
|
||||
apt-get install -y locales && apt-get install -y language-pack-zh-hans &&\
|
||||
localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8 && locale-gen zh_CN.UTF-8 &&\
|
||||
apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
|
||||
apt-get install -y libxrender1 && apt-get install -y libxt6 && apt-get install -y libxext-dev && apt-get install -y libfreetype6-dev &&\
|
||||
apt-get install -y wget && apt-get install -y ttf-mscorefonts-installer && apt-get install -y fontconfig &&\
|
||||
apt-get install ttf-wqy-microhei &&\
|
||||
apt-get install ttf-wqy-zenhei &&\
|
||||
apt-get install xfonts-wqy &&\
|
||||
cd /tmp &&\
|
||||
wget https://kkfileview.keking.cn/server-jre-8u251-linux-x64.tar.gz &&\
|
||||
tar -zxf /tmp/server-jre-8u251-linux-x64.tar.gz && mv /tmp/jdk1.8.0_251 /usr/local/ &&\
|
||||
|
||||
# 安装 OpenOffice
|
||||
# wget https://kkfileview.keking.cn/Apache_OpenOffice_4.1.6_Linux_x86-64_install-deb_zh-CN.tar.gz -cO openoffice_deb.tar.gz &&\
|
||||
# tar -zxf /tmp/openoffice_deb.tar.gz && cd /tmp/zh-CN/DEBS &&\
|
||||
# dpkg -i *.deb && dpkg -i desktop-integration/openoffice4.1-debian-menus_4.1.6-9790_all.deb &&\
|
||||
|
||||
# 安装 libreoffice
|
||||
apt-get install -y libxinerama1 libcairo2 libcups2 libx11-xcb1 &&\
|
||||
wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_deb.tar.gz -cO libreoffice_deb.tar.gz &&\
|
||||
tar -zxf /tmp/libreoffice_deb.tar.gz && cd /tmp/LibreOffice_7.1.4.2_Linux_x86-64_deb/DEBS &&\
|
||||
dpkg -i *.deb &&\
|
||||
|
||||
rm -rf /tmp/* && rm -rf /var/lib/apt/lists/* &&\
|
||||
cd /usr/share/fonts/chinese &&\
|
||||
mkfontscale &&\
|
||||
mkfontdir &&\
|
||||
fc-cache -fv
|
||||
ENV JAVA_HOME /usr/local/jdk1.8.0_251
|
||||
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||
ENV PATH $PATH:$JAVA_HOME/bin
|
||||
ENV LANG zh_CN.UTF-8
|
||||
ENV LC_ALL zh_CN.UTF-8
|
||||
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.0.0/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.0.0/config/application.properties","-jar","/opt/kkFileView-4.0.0/bin/kkFileView-4.0.0.jar"]
|
||||
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-4.1.0-SNAPSHOT/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=/opt/kkFileView-4.1.0-SNAPSHOT/config/application.properties","-jar","/opt/kkFileView-4.1.0-SNAPSHOT/bin/kkFileView-4.1.0-SNAPSHOT.jar"]
|
||||
@@ -1,4 +1,4 @@
|
||||
# file-online-preview
|
||||
# kkFileView
|
||||
|
||||
[](https://github.com/kekingcn/kkFileView/blob/master/LICENSE)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# file-online-preview
|
||||
# kkFileView
|
||||
此项目为文件文档在线预览项目解决方案,对标业内付费产品有【[永中office](http://dcs.yozosoft.com/)】【[office365](http://www.officeweb365.com/)】【[idocv](https://www.idocv.com/)】等,在取得公司高层同意后以Apache协议开源出来反哺社区,在此特别感谢@唐老大的支持以及@端木详笑的贡献。该项目使用流行的spring boot搭建,易上手和部署,基本支持主流办公文档的在线预览,如doc,docx,Excel,pdf,txt,zip,rar,图片等等
|
||||
### 项目特性
|
||||
|
||||
|
||||
38
docker/kkfileview-jdk/Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
||||
FROM ubuntu:20.04
|
||||
MAINTAINER chenjh "842761733@qq.com"
|
||||
# 内置一些常用的中文字体,避免普遍性乱码
|
||||
COPY fonts/* /usr/share/fonts/chinese/
|
||||
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" > /etc/apt/sources.list &&\
|
||||
apt-get clean && apt-get update &&\
|
||||
apt-get install -y locales && apt-get install -y language-pack-zh-hans &&\
|
||||
localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8 && locale-gen zh_CN.UTF-8 &&\
|
||||
export DEBIAN_FRONTEND=noninteractive &&\
|
||||
apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
|
||||
apt-get install -y libxrender1 && apt-get install -y libxt6 && apt-get install -y libxext-dev && apt-get install -y libfreetype6-dev &&\
|
||||
apt-get install -y wget && apt-get install -y ttf-mscorefonts-installer && apt-get install -y fontconfig &&\
|
||||
apt-get install ttf-wqy-microhei &&\
|
||||
apt-get install ttf-wqy-zenhei &&\
|
||||
apt-get install xfonts-wqy &&\
|
||||
cd /tmp &&\
|
||||
wget https://kkfileview.keking.cn/server-jre-8u251-linux-x64.tar.gz &&\
|
||||
tar -zxf /tmp/server-jre-8u251-linux-x64.tar.gz && mv /tmp/jdk1.8.0_251 /usr/local/ &&\
|
||||
|
||||
# 安装 libreoffice
|
||||
apt-get install -y libxinerama1 libcairo2 libcups2 libx11-xcb1 &&\
|
||||
wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_deb.tar.gz -cO libreoffice_deb.tar.gz &&\
|
||||
tar -zxf /tmp/libreoffice_deb.tar.gz && cd /tmp/LibreOffice_7.1.4.2_Linux_x86-64_deb/DEBS &&\
|
||||
dpkg -i *.deb &&\
|
||||
|
||||
# 清理临时文件
|
||||
rm -rf /tmp/* && rm -rf /var/lib/apt/lists/* &&\
|
||||
cd /usr/share/fonts/chinese &&\
|
||||
mkfontscale &&\
|
||||
mkfontdir &&\
|
||||
fc-cache -fv
|
||||
|
||||
ENV JAVA_HOME /usr/local/jdk1.8.0_251
|
||||
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||
ENV PATH $PATH:$JAVA_HOME/bin
|
||||
ENV LANG zh_CN.UTF-8
|
||||
ENV LC_ALL zh_CN.UTF-8
|
||||
ENTRYPOINT ["java","-version"]
|
||||
2
docker/kkfileview-jdk/docker build.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# 执行如下命令构建基础镜像,加快kkfileview docker镜像构建与发布
|
||||
docker build --tag keking/kkfileview-jdk:4.1.1 .
|
||||
@@ -3,11 +3,10 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>filepreview</artifactId>
|
||||
<artifactId>kkFileView-parent</artifactId>
|
||||
<groupId>cn.keking</groupId>
|
||||
<version>4.0.0</version>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>office-plugin</artifactId>
|
||||
@@ -27,19 +26,9 @@
|
||||
<version>2.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openoffice</groupId>
|
||||
<artifactId>juh</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openoffice</groupId>
|
||||
<artifactId>ridl</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openoffice</groupId>
|
||||
<artifactId>unoil</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<groupId>org.libreoffice</groupId>
|
||||
<artifactId>libreoffice</artifactId>
|
||||
<version>7.1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- for the command line tool -->
|
||||
@@ -86,16 +75,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
|
||||
@@ -12,18 +12,6 @@
|
||||
//
|
||||
package org.artofsolving.jodconverter;
|
||||
|
||||
import static org.artofsolving.jodconverter.office.OfficeUtils.SERVICE_DESKTOP;
|
||||
import static org.artofsolving.jodconverter.office.OfficeUtils.cast;
|
||||
import static org.artofsolving.jodconverter.office.OfficeUtils.toUnoProperties;
|
||||
import static org.artofsolving.jodconverter.office.OfficeUtils.toUrl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import org.artofsolving.jodconverter.office.OfficeContext;
|
||||
import org.artofsolving.jodconverter.office.OfficeException;
|
||||
import org.artofsolving.jodconverter.office.OfficeTask;
|
||||
|
||||
import com.sun.star.frame.XComponentLoader;
|
||||
import com.sun.star.frame.XStorable;
|
||||
import com.sun.star.io.IOException;
|
||||
@@ -32,6 +20,14 @@ import com.sun.star.lang.XComponent;
|
||||
import com.sun.star.task.ErrorCodeIOException;
|
||||
import com.sun.star.util.CloseVetoException;
|
||||
import com.sun.star.util.XCloseable;
|
||||
import org.artofsolving.jodconverter.office.OfficeContext;
|
||||
import org.artofsolving.jodconverter.office.OfficeException;
|
||||
import org.artofsolving.jodconverter.office.OfficeTask;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.artofsolving.jodconverter.office.OfficeUtils.*;
|
||||
|
||||
public abstract class AbstractConversionTask implements OfficeTask {
|
||||
|
||||
@@ -47,6 +43,7 @@ public abstract class AbstractConversionTask implements OfficeTask {
|
||||
|
||||
protected abstract Map<String,?> getStoreProperties(File outputFile, XComponent document);
|
||||
|
||||
@Override
|
||||
public void execute(OfficeContext context) throws OfficeException {
|
||||
XComponent document = null;
|
||||
try {
|
||||
@@ -79,6 +76,7 @@ public abstract class AbstractConversionTask implements OfficeTask {
|
||||
}
|
||||
XComponentLoader loader = cast(XComponentLoader.class, context.getService(SERVICE_DESKTOP));
|
||||
Map<String,?> loadProperties = getLoadProperties(inputFile);
|
||||
|
||||
XComponent document = null;
|
||||
try {
|
||||
document = loader.loadComponentFromURL(toUrl(inputFile), "_blank", 0, toUnoProperties(loadProperties));
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
//
|
||||
package org.artofsolving.jodconverter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.star.document.UpdateDocMode;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.artofsolving.jodconverter.document.DefaultDocumentFormatRegistry;
|
||||
import org.artofsolving.jodconverter.document.DocumentFormat;
|
||||
import org.artofsolving.jodconverter.document.DocumentFormatRegistry;
|
||||
import org.artofsolving.jodconverter.model.FileProperties;
|
||||
import org.artofsolving.jodconverter.office.OfficeException;
|
||||
import org.artofsolving.jodconverter.office.OfficeManager;
|
||||
|
||||
import com.sun.star.document.UpdateDocMode;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class OfficeDocumentConverter {
|
||||
|
||||
@@ -60,14 +60,22 @@ public class OfficeDocumentConverter {
|
||||
public void convert(File inputFile, File outputFile) throws OfficeException {
|
||||
String outputExtension = FilenameUtils.getExtension(outputFile.getName());
|
||||
DocumentFormat outputFormat = formatRegistry.getFormatByExtension(outputExtension);
|
||||
convert(inputFile, outputFile, outputFormat);
|
||||
convert(inputFile, outputFile, outputFormat, null);
|
||||
}
|
||||
|
||||
public void convert(File inputFile, File outputFile, DocumentFormat outputFormat) throws OfficeException {
|
||||
public void convert(File inputFile, File outputFile, FileProperties fileProperties) throws OfficeException {
|
||||
String outputExtension = FilenameUtils.getExtension(outputFile.getName());
|
||||
DocumentFormat outputFormat = formatRegistry.getFormatByExtension(outputExtension);
|
||||
convert(inputFile, outputFile, outputFormat, fileProperties);
|
||||
}
|
||||
|
||||
public void convert(File inputFile, File outputFile, DocumentFormat outputFormat, FileProperties fileProperties) throws OfficeException {
|
||||
String inputExtension = FilenameUtils.getExtension(inputFile.getName());
|
||||
DocumentFormat inputFormat = formatRegistry.getFormatByExtension(inputExtension);
|
||||
Map<String, Object> properties = fileProperties.toMap();
|
||||
properties.putAll(defaultLoadProperties);
|
||||
StandardConversionTask conversionTask = new StandardConversionTask(inputFile, outputFile, outputFormat);
|
||||
conversionTask.setDefaultLoadProperties(defaultLoadProperties);
|
||||
conversionTask.setDefaultLoadProperties(properties);
|
||||
conversionTask.setInputFormat(inputFormat);
|
||||
officeManager.execute(conversionTask);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.artofsolving.jodconverter.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :
|
||||
*/
|
||||
public class FileProperties {
|
||||
|
||||
private String filePassword;
|
||||
|
||||
public FileProperties() {
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new HashMap();
|
||||
if (filePassword != null) {
|
||||
map.put("Password", filePassword);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getFilePassword() {
|
||||
return filePassword;
|
||||
}
|
||||
|
||||
public void setFilePassword(String filePassword) {
|
||||
this.filePassword = filePassword;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,9 +104,14 @@ public class OfficeUtils {
|
||||
"/opt/openoffice.org3",
|
||||
"/opt/openoffice",
|
||||
"/opt/libreoffice",
|
||||
"/opt/libreoffice6.0",
|
||||
"/opt/libreoffice6.1",
|
||||
"/opt/libreoffice6.2",
|
||||
"/opt/libreoffice6.3",
|
||||
"/opt/libreoffice6.4",
|
||||
"/opt/libreoffice7.0",
|
||||
"/opt/libreoffice7.1",
|
||||
"/opt/libreoffice7.2",
|
||||
"/opt/openoffice4",
|
||||
"/usr/lib/openoffice",
|
||||
"/usr/lib/libreoffice"
|
||||
|
||||
@@ -29,23 +29,45 @@ public class ConfigUtils {
|
||||
return userDir;
|
||||
}
|
||||
|
||||
// 获取环境变量,如果找不到则返回默认值
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static String getEnvOrDefault(String key, String def) {
|
||||
String value = System.getenv(key);
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public static String getOfficePluginPath() {
|
||||
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(OFFICE_PLUGIN_NAME)) {
|
||||
userDir = userDir + separator + OFFICE_PLUGIN_NAME;
|
||||
// 返回参数列表中第一个真实存在的路径,或者 null
|
||||
private static String firstExists(File... paths) {
|
||||
for (File path : paths) {
|
||||
if (path.exists()) {
|
||||
return path.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
return userDir;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getOfficePluginPath() {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String binFolder = getEnvOrDefault("KKFILEVIEW_BIN_FOLDER", userDir);
|
||||
|
||||
File pluginPath = new File(binFolder);
|
||||
|
||||
// 如果指定了 bin 或其父目录,则返回父目录
|
||||
// 否则在当前目录和父目录中寻找 office-plugin
|
||||
if (new File(pluginPath, "bin").exists()) {
|
||||
return pluginPath.getAbsolutePath();
|
||||
|
||||
} else if (pluginPath.exists() && pluginPath.getName().equals("bin")) {
|
||||
return pluginPath.getParentFile().getAbsolutePath();
|
||||
|
||||
} else {
|
||||
return firstExists(
|
||||
new File(pluginPath, OFFICE_PLUGIN_NAME),
|
||||
new File(pluginPath.getParentFile(), OFFICE_PLUGIN_NAME)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCustomizedConfigPath() {
|
||||
String homePath = getHomePath();
|
||||
String separator = java.io.File.separator;
|
||||
|
||||
31
pom.xml
@@ -5,14 +5,39 @@
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>filepreview</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<artifactId>kkFileView-parent</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
|
||||
<spring.boot.version>2.4.2</spring.boot.version>
|
||||
<poi.version>5.2.2</poi.version>
|
||||
<xdocreport.version>1.0.6</xdocreport.version>
|
||||
<xstream.version>1.4.19</xstream.version>
|
||||
<junrar.version>7.4.1</junrar.version>
|
||||
<redisson.version>3.2.0</redisson.version>
|
||||
<sevenzipjbinding.version>16.02-2.01</sevenzipjbinding.version>
|
||||
<tukaani.version>1.8</tukaani.version>
|
||||
<jchardet.version>1.0</jchardet.version>
|
||||
<antlr.version>2.7.7</antlr.version>
|
||||
<concurrentlinkedhashmap.version>1.4.2</concurrentlinkedhashmap.version>
|
||||
<rocksdb.version>5.17.2</rocksdb.version>
|
||||
<pdfbox.version>2.0.26</pdfbox.version>
|
||||
<galimatias.version>0.2.1</galimatias.version>
|
||||
<bytedeco.version>1.5.2</bytedeco.version>
|
||||
<opencv.version>4.1.2-1.5.2</opencv.version>
|
||||
<openblas.version>0.3.6-1.5.1</openblas.version>
|
||||
<ffmpeg.version>4.2.1-1.5.2</ffmpeg.version>
|
||||
<itext.version>2.1.7</itext.version>
|
||||
<commons-cli.version>1.2</commons-cli.version>
|
||||
<commons-net.version>3.6</commons-net.version>
|
||||
<commons-lang3.version>3.7</commons-lang3.version>
|
||||
<commons-compress.version>1.21</commons-compress.version>
|
||||
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
@@ -22,7 +47,7 @@
|
||||
<module>server</module>
|
||||
</modules>
|
||||
|
||||
<name>file-online-preview</name>
|
||||
<name>kkFileView-parent</name>
|
||||
<description>专注文件在线预览服务</description>
|
||||
<url>https://github.com/kekingcn/kkFileView</url>
|
||||
|
||||
|
||||
BIN
server/lib/jai_codec-1.1.3.jar
Normal file
BIN
server/lib/jai_core-1.1.3.jar
Normal file
174
server/pom.xml
@@ -4,9 +4,9 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>filepreview</artifactId>
|
||||
<artifactId>kkFileView-parent</artifactId>
|
||||
<groupId>cn.keking</groupId>
|
||||
<version>4.0.0</version>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>kkFileView</artifactId>
|
||||
@@ -25,9 +25,12 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>office-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- web start -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
@@ -42,42 +45,32 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>office-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.7</version>
|
||||
</dependency>
|
||||
<!-- REDISSON -->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<!-- web end -->
|
||||
|
||||
<!-- poi start -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>3.17</version>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-scratchpad</artifactId>
|
||||
<version>3.12</version>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.opensagres.xdocreport</groupId>
|
||||
<artifactId>org.apache.poi.xwpf.converter.core</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>${xdocreport.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>poi</artifactId>
|
||||
@@ -88,88 +81,102 @@
|
||||
<dependency>
|
||||
<groupId>fr.opensagres.xdocreport</groupId>
|
||||
<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>${xdocreport.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.opensagres.xdocreport</groupId>
|
||||
<artifactId>fr.opensagres.xdocreport.document</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>${xdocreport.version}</version>
|
||||
</dependency>
|
||||
<!-- poi start -->
|
||||
|
||||
<!-- 对 rar5 的支持 和其他众多压缩支持 可参考 package net.sf.sevenzipjbinding.ArchiveFormat; -->
|
||||
<dependency>
|
||||
<groupId>net.sf.sevenzipjbinding</groupId>
|
||||
<artifactId>sevenzipjbinding</artifactId>
|
||||
<version>${sevenzipjbinding.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.sevenzipjbinding</groupId>
|
||||
<artifactId>sevenzipjbinding-all-platforms</artifactId>
|
||||
<version>${sevenzipjbinding.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>${redisson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 解压(apache) -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.19</version>
|
||||
<version>${commons-compress.version}</version>
|
||||
</dependency>
|
||||
<!-- 解压(rar)-->
|
||||
<dependency>
|
||||
<groupId>com.github.junrar</groupId>
|
||||
<artifactId>junrar</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<version>${junrar.version}</version>
|
||||
</dependency>
|
||||
<!-- 解压(7z)-->
|
||||
<dependency>
|
||||
<groupId>org.tukaani</groupId>
|
||||
<artifactId>xz</artifactId>
|
||||
<version>1.8</version>
|
||||
<version>${tukaani.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.jchardet</groupId>
|
||||
<artifactId>jchardet</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>${jchardet.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
<version>2.7.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-httpclient</groupId>
|
||||
<artifactId>commons-httpclient</artifactId>
|
||||
<version>3.1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>${antlr.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>${commons-cli.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- FTP -->
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>${commons-net.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.4.17</version>
|
||||
<version>${xstream.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
|
||||
<artifactId>concurrentlinkedhashmap-lru</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<version>${concurrentlinkedhashmap.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.rocksdb</groupId>
|
||||
<artifactId>rocksdbjni</artifactId>
|
||||
<version>5.17.2</version>
|
||||
<version>${rocksdb.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.24</version>
|
||||
<version>${pdfbox.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox-tools</artifactId>
|
||||
<version>2.0.15</version>
|
||||
<version>${pdfbox.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aspose</groupId>
|
||||
@@ -190,66 +197,98 @@
|
||||
<dependency>
|
||||
<groupId>io.mola.galimatias</groupId>
|
||||
<artifactId>galimatias</artifactId>
|
||||
<version>0.2.1</version>
|
||||
<version>${galimatias.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 以下是bytedeco 基于opencv ffmpeg封装的javacv,用于视频处理 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>${bytedeco.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>${bytedeco.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 此版本中主要兼容linux和windows系统,如需兼容其他系统平台,请引入对应依赖即可 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.1.2-1.5.2</version>
|
||||
<version>${opencv.version}</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.1.2-1.5.2</version>
|
||||
<version>${opencv.version}</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.6-1.5.1</version>
|
||||
<version>${openblas.version}</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.6-1.5.1</version>
|
||||
<version>${openblas.version}</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.2.1-1.5.2</version>
|
||||
<version>${ffmpeg.version}</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.2.1-1.5.2</version>
|
||||
<version>${ffmpeg.version}</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lowagie</groupId>
|
||||
<artifactId>itext</artifactId>
|
||||
<version>${itext.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.media</groupId>
|
||||
<artifactId>jai_core</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/lib/jai_core-1.1.3.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.media</groupId>
|
||||
<artifactId>jai_codec</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/lib/jai_codec-1.1.3.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependency - start -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-httpclient</groupId>
|
||||
<artifactId>commons-httpclient</artifactId>
|
||||
<version>3.1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- test dependency - end -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -303,5 +342,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -7,7 +7,7 @@ install_redhat() {
|
||||
if [ $? -eq 0 ];then
|
||||
yum install -y libXext.x86_64
|
||||
yum groupinstall -y "X Window System"
|
||||
yum installlocalho
|
||||
yum localinstall *.rpm
|
||||
echo 'install finshed...'
|
||||
else
|
||||
echo 'download package error...'
|
||||
@@ -15,7 +15,7 @@ install_redhat() {
|
||||
}
|
||||
|
||||
install_ubuntu() {
|
||||
wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_deb.tar.gz -cO LibreOffice_7_deb.gz && tar -zxf /tmp/LibreOffice_7_deb.tar.gz && cd /tmp/LibreOffice_7.1.4.2_Linux_x86-deb/RPMS
|
||||
wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_deb.tar.gz -cO LibreOffice_7_deb.tar.gz && tar -zxf /tmp/LibreOffice_7_deb.tar.gz && cd /tmp/LibreOffice_7.1.4.2_Linux_x86-64_deb/DEBS
|
||||
echo $?
|
||||
if [ $? -eq 0 ];then
|
||||
apt-get install -y libxinerama1 libcairo2 libcups2 libx11-xcb1
|
||||
|
||||
@@ -1,2 +1,36 @@
|
||||
#!/bin/bash
|
||||
kill -15 `ps -ef|grep kkFileView|awk 'NR==1{print $2}'`
|
||||
#
|
||||
#
|
||||
#############################
|
||||
# Author: sanxi
|
||||
# Version: 1.0
|
||||
# Date: 2021/09/17
|
||||
# Description: v1.0:修改kkFileView关闭进程机制
|
||||
#############################
|
||||
#
|
||||
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")" || exit 1 ;pwd)
|
||||
PID_FILE_NAME="kkFileView.pid"
|
||||
PID_FILE="${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
export KKFILEVIEW_BIN_FOLDER=$KKFILEVIEW_BIN_FOLDER
|
||||
#
|
||||
## pid文件是否存在
|
||||
if [ ! -e "$PID_FILE" ]; then
|
||||
echo "kkFileView.pid文件不存在!"
|
||||
exit 1
|
||||
else
|
||||
## 文件不为空代表程序正在运行,则循环关闭进程。
|
||||
if [ -s "$PID_FILE" ]; then
|
||||
# 读取pid文件内容,开启while循环读取每一行文本赋予给变量PID_FILE。
|
||||
cat "${PID_FILE}" | while read PID;do
|
||||
## 如已读取完毕,则退出脚本。
|
||||
[ -z "$PID" ] && exit 2
|
||||
echo "正在停止进程:${PID}..."
|
||||
## 正常停止进程
|
||||
kill -15 "${PID}" && echo "进程:${PID}停止成功!"
|
||||
done
|
||||
# 关闭所有进程后,重置pid。
|
||||
cat /dev/null > "$PID_FILE"
|
||||
else
|
||||
echo "kkFileView进程尚未运行!"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6,4 +6,4 @@ echo Starting kkFileView...
|
||||
echo Please check log file in ../log/kkFileView.log for more information
|
||||
echo You can get help in our official homesite: https://kkFileView.keking.cn
|
||||
echo If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers
|
||||
java -Dspring.config.location=..\config\application.properties -jar kkFileView-4.0.0.jar -> ..\log\kkFileView.log
|
||||
java -Dspring.config.location=..\config\application.properties -jar kkFileView-4.1.0-SNAPSHOT.jar -> ..\log\kkFileView.log
|
||||
@@ -1,32 +1,61 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
#############################
|
||||
# First_Author: 凯京科技
|
||||
# Second_Author: sanxi
|
||||
# Version: 1.1
|
||||
# Date: 2021/09/17
|
||||
# Description: v1.1:修改进程启动机制为pid形式。
|
||||
#############################
|
||||
#
|
||||
DIR_HOME=("/opt/openoffice.org3" "/opt/libreoffice" "/opt/libreoffice6.1" "/opt/libreoffice7.0" "/opt/libreoffice7.1" "/opt/openoffice4" "/usr/lib/openoffice" "/usr/lib/libreoffice")
|
||||
FLAG=
|
||||
OFFICE_HOME=
|
||||
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")" || exit 1 ;pwd)
|
||||
PID_FILE_NAME="kkFileView.pid"
|
||||
PID_FILE="${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
export KKFILEVIEW_BIN_FOLDER=$KKFILEVIEW_BIN_FOLDER
|
||||
cd $KKFILEVIEW_BIN_FOLDER
|
||||
echo "Using KKFILEVIEW_BIN_FOLDER $KKFILEVIEW_BIN_FOLDER"
|
||||
grep 'office\.home' ../config/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 ./install.sh
|
||||
else
|
||||
echo "Detected office component has been installed in $OFFICE_HOME"
|
||||
fi
|
||||
#
|
||||
## 如pid文件不存在则自动创建
|
||||
if [ ! -f ${PID_FILE_NAME} ]; then
|
||||
touch "${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
fi
|
||||
## 判断当前是否有进程处于运行状态
|
||||
if [ -s "${PID_FILE}" ]; then
|
||||
PID=$(cat "${PID_FILE}")
|
||||
echo "进程已处于运行状态,进程号为:${PID}"
|
||||
exit 1
|
||||
else
|
||||
cd "$KKFILEVIEW_BIN_FOLDER" || exit 1
|
||||
echo "Using KKFILEVIEW_BIN_FOLDER $KKFILEVIEW_BIN_FOLDER"
|
||||
grep 'office\.home' ../config/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 ./install.sh
|
||||
else
|
||||
echo "Detected office component has been installed in $OFFICE_HOME"
|
||||
fi
|
||||
fi
|
||||
|
||||
## 启动kkFileView
|
||||
echo "Starting kkFileView..."
|
||||
nohup java -Dfile.encoding=UTF-8 -Dspring.config.location=../config/application.properties -jar kkFileView-4.1.0-SNAPSHOT.jar > ../log/kkFileView.log 2>&1 &
|
||||
echo "Please execute ./showlog.sh to check log for more information"
|
||||
echo "You can get help in our official homesite: https://kkFileView.keking.cn"
|
||||
echo "If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers"
|
||||
PROCESS=$(ps -ef | grep kkFileView | awk 'NR==1{print $2}')
|
||||
# 启动成功后将进程号写入pid文件
|
||||
echo "$PROCESS" > "$PID_FILE"
|
||||
fi
|
||||
echo "Starting kkFileView..."
|
||||
echo "Please execute ./showlog.sh to check log for more information"
|
||||
echo "You can get help in our official homesite: https://kkFileView.keking.cn"
|
||||
echo "If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers"
|
||||
nohup java -Dfile.encoding=UTF-8 -Dspring.config.location=../config/application.properties -jar kkFileView-4.0.0.jar > ../log/kkFileView.log 2>&1 &
|
||||
|
||||
@@ -22,9 +22,15 @@ office.plugin.server.ports = 2001,2002
|
||||
## office 转换服务 task 超时时间,默认五分钟
|
||||
office.plugin.task.timeout = 5m
|
||||
|
||||
#文件资源路径(默认为打包根路径下的file目录下)
|
||||
#预览生成资源路径(默认为打包根路径下的file目录下)
|
||||
#file.dir = D:\\kkFileview\\
|
||||
file.dir = ${KK_FILE_DIR:default}
|
||||
|
||||
#允许预览的本地文件夹 默认不允许任何本地文件被预览
|
||||
#file.dir = D:\\kkFileview\\
|
||||
local.preview.dir = ${KK_LOCAL_PREVIEW_DIR:default}
|
||||
|
||||
|
||||
#openoffice home路径
|
||||
#office.home = C:\\Program Files (x86)\\OpenOffice 4
|
||||
office.home = ${KK_OFFICE_HOME:default}
|
||||
@@ -65,8 +71,16 @@ office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image}
|
||||
#是否关闭office预览切换开关,默认为false,可配置为true关闭
|
||||
office.preview.switch.disabled = ${KK_OFFICE_PREVIEW_SWITCH_DISABLED:false}
|
||||
|
||||
#是否禁止演示模式
|
||||
pdf.presentationMode.disable = ${KK_PDF_PRESENTATION_MODE_DISABLE:true}
|
||||
#是否禁止打开文件
|
||||
pdf.openFile.disable = ${KK_PDF_OPEN_FILE_DISABLE:true}
|
||||
#是否禁止打印转换生成的pdf文件
|
||||
pdf.print.disable = ${KK_PDF_PRINT_DISABLE:true}
|
||||
#是否禁止下载转换生成的pdf文件
|
||||
pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:true}
|
||||
#是否禁止bookmark
|
||||
pdf.bookmark.disable = ${KK_PDF_BOOKMARK_DISABLE:true}
|
||||
#是否禁用首页文件上传
|
||||
file.upload.disable = ${KK_FILE_UPLOAD_ENABLED:false}
|
||||
|
||||
@@ -100,3 +114,6 @@ watermark.height = ${WATERMARK_HEIGHT:80}
|
||||
#水印倾斜度数,要求设置在大于等于0,小于90
|
||||
watermark.angle = ${WATERMARK_ANGLE:10}
|
||||
|
||||
#Tif类型图片浏览模式:tif(利用前端js插件浏览);jpg(转换为jpg后前端显示);pdf(转换为pdf后显示,便于打印)
|
||||
tif.preview.type = ${KK_TIF_PREVIEW_TYPE:tif}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
[#-- @ftlvariable name="file" type="cn.keking.model.FileAttribute" --]
|
||||
[#-- @ftlvariable name="fileName" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="fileTree" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="needFilePassword" type="java.lang.Boolean" --]
|
||||
[#-- @ftlvariable name="filePasswordError" type="java.lang.Boolean" --]
|
||||
[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="imgUrls" type="String" --]
|
||||
[#-- @ftlvariable name="textData" type="java.lang.String" --]
|
||||
|
||||
@@ -20,8 +20,8 @@ public class AppBanner implements Banner {
|
||||
" | < | < | | | | | | | __/ \\ / | | | __/ \\ V V / \n" +
|
||||
" |_|\\_\\ |_|\\_\\ |_| |_| |_| \\___| \\/ |_| \\___| \\_/\\_/ \n" +
|
||||
" \n" +
|
||||
" => Spring Boot :: (v2.4.2) QQ1 :: 613025121\n" +
|
||||
" => kkFileView :: (v4.0.0) QQ2 :: 484680571\n" +
|
||||
" => Spring Boot :: (v2.4.2) QQ1 :: 613025121\n" +
|
||||
" => kkFileView :: (v4.1.0-SNAPSHOT) QQ2 :: 484680571\n" +
|
||||
" => github :: https://github.com/kekingcn/kkFileView\n" +
|
||||
" => gitee :: https://gitee.com/kekingcn/file-online-preview\n");
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* @author: chenjh
|
||||
@@ -33,9 +33,15 @@ public class ConfigConstants {
|
||||
private static String ftpControlEncoding;
|
||||
private static String baseUrl;
|
||||
private static String fileDir = ConfigUtils.getHomePath() + File.separator + "file" + File.separator;
|
||||
private static String localPreviewDir;
|
||||
private static CopyOnWriteArraySet<String> trustHostSet;
|
||||
private static String pdfPresentationModeDisable;
|
||||
private static String pdfOpenFileDisable;
|
||||
private static String pdfPrintDisable;
|
||||
private static String pdfDownloadDisable;
|
||||
private static String pdfBookmarkDisable;
|
||||
private static Boolean fileUploadDisable;
|
||||
private static String tifPreviewType;
|
||||
|
||||
public static final String DEFAULT_CACHE_ENABLED = "true";
|
||||
public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd";
|
||||
@@ -47,10 +53,15 @@ public class ConfigConstants {
|
||||
public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8";
|
||||
public static final String DEFAULT_BASE_URL = "default";
|
||||
public static final String DEFAULT_FILE_DIR_VALUE = "default";
|
||||
public static final String DEFAULT_LOCAL_PREVIEW_DIR_VALUE = "default";
|
||||
public static final String DEFAULT_TRUST_HOST = "default";
|
||||
public static final String DEFAULT_PDF_PRESENTATION_MODE_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_OPEN_FILE_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_PRINT_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_DOWNLOAD_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_BOOKMARK_DISABLE = "true";
|
||||
public static final String DEFAULT_FILE_UPLOAD_DISABLE = "false";
|
||||
|
||||
public static final String DEFAULT_TIF_PREVIEW_TYPE = "tif";
|
||||
|
||||
public static Boolean isCacheEnabled() {
|
||||
return cacheEnabled;
|
||||
@@ -203,6 +214,24 @@ public class ConfigConstants {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLocalPreviewDir() {
|
||||
return localPreviewDir;
|
||||
}
|
||||
|
||||
@Value("${local.preview.dir:default}")
|
||||
public void setLocalPreviewDir(String localPreviewDir) {
|
||||
setLocalPreviewDirValue(localPreviewDir);
|
||||
}
|
||||
|
||||
public static void setLocalPreviewDirValue(String localPreviewDir) {
|
||||
if (!DEFAULT_LOCAL_PREVIEW_DIR_VALUE.equals(localPreviewDir)) {
|
||||
if (!localPreviewDir.endsWith(File.separator)) {
|
||||
localPreviewDir = localPreviewDir + File.separator;
|
||||
}
|
||||
}
|
||||
ConfigConstants.localPreviewDir = localPreviewDir;
|
||||
}
|
||||
|
||||
@Value("${trust.host:default}")
|
||||
public void setTrustHost(String trustHost) {
|
||||
setTrustHostValue(trustHost);
|
||||
@@ -228,11 +257,46 @@ public class ConfigConstants {
|
||||
ConfigConstants.trustHostSet = trustHostSet;
|
||||
}
|
||||
|
||||
public static String getPdfPresentationModeDisable() {
|
||||
return pdfPresentationModeDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.presentationMode.disable:true}")
|
||||
public void setPdfPresentationModeDisable(String pdfPresentationModeDisable) {
|
||||
setPdfPresentationModeDisableValue(pdfPresentationModeDisable);
|
||||
}
|
||||
|
||||
public static void setPdfPresentationModeDisableValue(String pdfPresentationModeDisable) {
|
||||
ConfigConstants.pdfPresentationModeDisable = pdfPresentationModeDisable;
|
||||
}
|
||||
|
||||
public static String getPdfOpenFileDisable() {
|
||||
return pdfOpenFileDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.openFile.disable:true}")
|
||||
public static void setPdfOpenFileDisable(String pdfOpenFileDisable) {
|
||||
setPdfOpenFileDisableValue(pdfOpenFileDisable);
|
||||
}
|
||||
public static void setPdfOpenFileDisableValue(String pdfOpenFileDisable) {
|
||||
ConfigConstants.pdfOpenFileDisable = pdfOpenFileDisable;
|
||||
}
|
||||
|
||||
public static String getPdfPrintDisable() {
|
||||
return pdfPrintDisable;
|
||||
}
|
||||
@Value("${pdf.print.disable:true}")
|
||||
public void setPdfPrintDisable(String pdfPrintDisable) {
|
||||
setPdfPrintDisableValue(pdfPrintDisable);
|
||||
}
|
||||
public static void setPdfPrintDisableValue(String pdfPrintDisable) {
|
||||
ConfigConstants.pdfPrintDisable = pdfPrintDisable;
|
||||
}
|
||||
|
||||
public static String getPdfDownloadDisable() {
|
||||
return pdfDownloadDisable;
|
||||
}
|
||||
|
||||
|
||||
@Value("${pdf.download.disable:true}")
|
||||
public void setPdfDownloadDisable(String pdfDownloadDisable) {
|
||||
setPdfDownloadDisableValue(pdfDownloadDisable);
|
||||
@@ -241,6 +305,17 @@ public class ConfigConstants {
|
||||
ConfigConstants.pdfDownloadDisable = pdfDownloadDisable;
|
||||
}
|
||||
|
||||
public static String getPdfBookmarkDisable() {
|
||||
return pdfBookmarkDisable;
|
||||
}
|
||||
@Value("${pdf.bookmark.disable:true}")
|
||||
public void setPdfBookmarkDisable(String pdfBookmarkDisable) {
|
||||
setPdfBookmarkDisableValue(pdfBookmarkDisable);
|
||||
}
|
||||
public static void setPdfBookmarkDisableValue(String pdfBookmarkDisable) {
|
||||
ConfigConstants.pdfBookmarkDisable = pdfBookmarkDisable;
|
||||
}
|
||||
|
||||
public static String getOfficePreviewSwitchDisabled() {
|
||||
return officePreviewSwitchDisabled;
|
||||
}
|
||||
@@ -264,4 +339,18 @@ public class ConfigConstants {
|
||||
public static void setFileUploadDisableValue(Boolean fileUploadDisable) {
|
||||
ConfigConstants.fileUploadDisable = fileUploadDisable;
|
||||
}
|
||||
|
||||
|
||||
public static String getTifPreviewType() {
|
||||
return tifPreviewType;
|
||||
}
|
||||
|
||||
@Value("${tif.preview.type:tif}")
|
||||
public void setTifPreviewType(String tifPreviewType) {
|
||||
setTifPreviewTypeValue(tifPreviewType);
|
||||
}
|
||||
|
||||
public static void setTifPreviewTypeValue(String tifPreviewType) {
|
||||
ConfigConstants.tifPreviewType = tifPreviewType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,14 @@ public class ConfigRefreshComponent {
|
||||
String configFilePath = ConfigUtils.getCustomizedConfigPath();
|
||||
String baseUrl;
|
||||
String trustHost;
|
||||
String pdfPresentationModeDisable;
|
||||
String pdfOpenFileDisable;
|
||||
String pdfPrintDisable;
|
||||
String pdfDownloadDisable;
|
||||
String pdfBookmarkDisable;
|
||||
boolean fileUploadDisable;
|
||||
String tifPreviewType;
|
||||
|
||||
while (true) {
|
||||
FileReader fileReader = new FileReader(configFilePath);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
@@ -66,8 +72,14 @@ public class ConfigRefreshComponent {
|
||||
mediaArray = media.split(",");
|
||||
baseUrl = properties.getProperty("base.url", ConfigConstants.DEFAULT_BASE_URL);
|
||||
trustHost = properties.getProperty("trust.host", ConfigConstants.DEFAULT_TRUST_HOST);
|
||||
pdfPresentationModeDisable = properties.getProperty("pdf.presentationMode.disable", ConfigConstants.DEFAULT_PDF_PRESENTATION_MODE_DISABLE);
|
||||
pdfOpenFileDisable = properties.getProperty("pdf.openFile.disable", ConfigConstants.DEFAULT_PDF_OPEN_FILE_DISABLE);
|
||||
pdfPrintDisable = properties.getProperty("pdf.print.disable", ConfigConstants.DEFAULT_PDF_PRINT_DISABLE);
|
||||
pdfDownloadDisable = properties.getProperty("pdf.download.disable", ConfigConstants.DEFAULT_PDF_DOWNLOAD_DISABLE);
|
||||
pdfBookmarkDisable = properties.getProperty("pdf.bookmark.disable", ConfigConstants.DEFAULT_PDF_BOOKMARK_DISABLE);
|
||||
fileUploadDisable = Boolean.parseBoolean(properties.getProperty("file.upload.disable", ConfigConstants.DEFAULT_FILE_UPLOAD_DISABLE));
|
||||
tifPreviewType = properties.getProperty("tif.preview.type", ConfigConstants.DEFAULT_TIF_PREVIEW_TYPE);
|
||||
|
||||
ConfigConstants.setCacheEnabledValueValue(cacheEnabled);
|
||||
ConfigConstants.setSimTextValue(textArray);
|
||||
ConfigConstants.setMediaValue(mediaArray);
|
||||
@@ -78,8 +90,13 @@ public class ConfigRefreshComponent {
|
||||
ConfigConstants.setBaseUrlValue(baseUrl);
|
||||
ConfigConstants.setTrustHostValue(trustHost);
|
||||
ConfigConstants.setOfficePreviewSwitchDisabledValue(officePreviewSwitchDisabled);
|
||||
ConfigConstants.setPdfPresentationModeDisableValue(pdfPresentationModeDisable);
|
||||
ConfigConstants.setPdfOpenFileDisableValue(pdfOpenFileDisable);
|
||||
ConfigConstants.setPdfPrintDisableValue(pdfPrintDisable);
|
||||
ConfigConstants.setPdfDownloadDisableValue(pdfDownloadDisable);
|
||||
ConfigConstants.setPdfBookmarkDisableValue(pdfBookmarkDisable);
|
||||
ConfigConstants.setFileUploadDisableValue(fileUploadDisable);
|
||||
ConfigConstants.setTifPreviewTypeValue(tifPreviewType);
|
||||
setWatermarkConfig(properties);
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.web.filter.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: chenjh
|
||||
* @since: 2019/4/16 20:04
|
||||
@@ -23,4 +29,63 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
LOGGER.info("Add resource locations: {}", filePath);
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<ChinesePathFilter> getChinesePathFilter() {
|
||||
ChinesePathFilter filter = new ChinesePathFilter();
|
||||
FilterRegistrationBean<ChinesePathFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TrustHostFilter> getTrustHostFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
TrustHostFilter filter = new TrustHostFilter();
|
||||
FilterRegistrationBean<TrustHostFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TrustDirFilter> getTrustDirFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
filterUri.add("/getCorsFile");
|
||||
TrustDirFilter filter = new TrustDirFilter();
|
||||
FilterRegistrationBean<TrustDirFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<BaseUrlFilter> getBaseUrlFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/index");
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
BaseUrlFilter filter = new BaseUrlFilter();
|
||||
FilterRegistrationBean<BaseUrlFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<AttributeSetFilter> getWatermarkConfigFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/index");
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
AttributeSetFilter filter = new AttributeSetFilter();
|
||||
FilterRegistrationBean<AttributeSetFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.keking.model;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.artofsolving.jodconverter.model.FileProperties;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
@@ -13,7 +14,11 @@ public class FileAttribute {
|
||||
private String name;
|
||||
private String url;
|
||||
private String fileKey;
|
||||
private String filePassword;
|
||||
private String userToken;
|
||||
private String officePreviewType = ConfigConstants.getOfficePreviewType();
|
||||
private String tifPreviewType;
|
||||
private Boolean skipDownLoad = false;
|
||||
|
||||
public FileAttribute() {
|
||||
}
|
||||
@@ -33,6 +38,12 @@ public class FileAttribute {
|
||||
this.officePreviewType = officePreviewType;
|
||||
}
|
||||
|
||||
public FileProperties toFileProperties() {
|
||||
FileProperties fileProperties = new FileProperties();
|
||||
fileProperties.setFilePassword(filePassword);
|
||||
return fileProperties;
|
||||
}
|
||||
|
||||
public String getFileKey() {
|
||||
return fileKey;
|
||||
}
|
||||
@@ -41,6 +52,22 @@ public class FileAttribute {
|
||||
this.fileKey = fileKey;
|
||||
}
|
||||
|
||||
public String getFilePassword() {
|
||||
return filePassword;
|
||||
}
|
||||
|
||||
public void setFilePassword(String filePassword) {
|
||||
this.filePassword = filePassword;
|
||||
}
|
||||
|
||||
public String getUserToken() {
|
||||
return userToken;
|
||||
}
|
||||
|
||||
public void setUserToken(String userToken) {
|
||||
this.userToken = userToken;
|
||||
}
|
||||
|
||||
public String getOfficePreviewType() {
|
||||
return officePreviewType;
|
||||
}
|
||||
@@ -80,4 +107,21 @@ public class FileAttribute {
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Boolean getSkipDownLoad() {
|
||||
return skipDownLoad;
|
||||
}
|
||||
|
||||
public void setSkipDownLoad(Boolean skipDownLoad) {
|
||||
this.skipDownLoad = skipDownLoad;
|
||||
}
|
||||
|
||||
public String getTifPreviewType() {
|
||||
return tifPreviewType;
|
||||
}
|
||||
|
||||
public void setTifPreviewType(String previewType) {
|
||||
this.tifPreviewType = previewType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public enum FileType {
|
||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
||||
private static final String[] TIFF_TYPES = {"tif", "tiff"};
|
||||
private static final String[] OFD_TYPES = {"ofd"};
|
||||
private static final String[] CAD_TYPES = {"dwg", "dxf"};
|
||||
private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yaml", "yml", "json", "h", "cpp", "cs", "aspx", "jsp"};
|
||||
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
|
||||
@@ -66,10 +67,12 @@ public enum FileType {
|
||||
for (String ofd : OFD_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(ofd, FileType.OFD);
|
||||
}
|
||||
for (String cad : CAD_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(cad, FileType.CAD);
|
||||
}
|
||||
FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN);
|
||||
FILE_TYPE_MAPPER.put("xml", FileType.XML);
|
||||
FILE_TYPE_MAPPER.put("pdf", FileType.PDF);
|
||||
FILE_TYPE_MAPPER.put("dwg", FileType.CAD);
|
||||
FILE_TYPE_MAPPER.put("flv", FileType.FLV);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.keking.service;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.utils.FileHeaderRar;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@@ -9,10 +10,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.junrar.Archive;
|
||||
import com.github.junrar.exception.RarException;
|
||||
import com.github.junrar.rarfile.FileHeader;
|
||||
import net.sf.sevenzipjbinding.*;
|
||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
||||
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.apache.commons.io.FileUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.*;
|
||||
@@ -24,6 +29,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
@@ -99,44 +105,84 @@ public class CompressFileReader {
|
||||
List<String> imgUrls = new ArrayList<>();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
try {
|
||||
Archive archive = new Archive(new FileInputStream(filePath));
|
||||
List<FileHeader> headers = archive.getFileHeaders();
|
||||
headers = sortedHeaders(headers);
|
||||
List<FileHeaderRar> items = getRar4Paths(filePath);
|
||||
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
|
||||
List<Map<String, FileHeader>> headersToBeExtracted = new ArrayList<>();
|
||||
for (FileHeader header : headers) {
|
||||
String fullName;
|
||||
if (header.isUnicode()) {
|
||||
fullName = header.getFileNameW();
|
||||
} else {
|
||||
fullName = header.getFileNameString();
|
||||
}
|
||||
// 展示名
|
||||
String originName = getLastFileName(fullName, "\\");
|
||||
List<Map<String, FileHeaderRar>> headersToBeExtract = new ArrayList<>();
|
||||
for (FileHeaderRar header : items) {
|
||||
String fullName = header.getFileNameW();
|
||||
String originName = getLastFileName(fullName, File.separator);
|
||||
String childName = originName;
|
||||
boolean directory = header.isDirectory();
|
||||
boolean directory = header.getDirectory();
|
||||
if (!directory) {
|
||||
childName = archiveFileName + "_" + originName;
|
||||
headersToBeExtracted.add(Collections.singletonMap(childName, header));
|
||||
headersToBeExtract.add(Collections.singletonMap(childName, header));
|
||||
}
|
||||
String parentName = getLast2FileName(fullName, "\\", archiveFileName);
|
||||
String parentName = getLast2FileName(fullName, File.separator, archiveFileName);
|
||||
FileType type = FileType.typeFromUrl(childName);
|
||||
if (type.equals(FileType.PICTURE)) {//添加图片文件到图片列表
|
||||
if (type.equals(FileType.PICTURE)) {
|
||||
imgUrls.add(baseUrl + childName);
|
||||
}
|
||||
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
|
||||
FileNode node =
|
||||
new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
|
||||
addNodes(appender, parentName, node);
|
||||
appender.put(childName, node);
|
||||
}
|
||||
executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath));
|
||||
fileHandlerService.putImgCache(fileKey, imgUrls);
|
||||
executors.submit(new RarExtractorWorker(headersToBeExtract, filePath));
|
||||
return new ObjectMapper().writeValueAsString(appender.get(""));
|
||||
} catch (RarException | IOException e) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<FileHeaderRar> getRar4Paths(String paths) {
|
||||
RandomAccessFile randomAccessFile = null;
|
||||
IInArchive inArchive = null;
|
||||
List<FileHeaderRar> itemPath = null;
|
||||
try {
|
||||
randomAccessFile = new RandomAccessFile(paths, "r");
|
||||
inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
|
||||
String folderName = paths.substring(paths.lastIndexOf(File.separator) + 1);
|
||||
String extractPath = paths.substring(0, paths.lastIndexOf(folderName));
|
||||
inArchive.extract(null, false, new ExtractCallback(inArchive, extractPath, folderName + "_"));
|
||||
ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();
|
||||
itemPath =
|
||||
Arrays.stream(simpleInArchive.getArchiveItems())
|
||||
.map(
|
||||
o -> {
|
||||
try {
|
||||
return new FileHeaderRar(o.getPath(), o.isFolder());
|
||||
} catch (SevenZipException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(FileHeaderRar::getFileNameW))
|
||||
.collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error occurs: " + e);
|
||||
} finally {
|
||||
if (inArchive != null) {
|
||||
try {
|
||||
inArchive.close();
|
||||
} catch (SevenZipException e) {
|
||||
System.err.println("Error closing archive: " + e);
|
||||
}
|
||||
}
|
||||
if (randomAccessFile != null) {
|
||||
try {
|
||||
randomAccessFile.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error closing file: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemPath;
|
||||
}
|
||||
|
||||
public String read7zFile(String filePath, String fileKey) {
|
||||
String archiveSeparator = "/";
|
||||
Map<String, FileNode> appender = new HashMap<>();
|
||||
@@ -206,10 +252,21 @@ public class CompressFileReader {
|
||||
private List<FileHeader> sortedHeaders(List<FileHeader> headers) {
|
||||
List<FileHeader> sortedHeaders = new ArrayList<>();
|
||||
Map<Integer, FileHeader> mapHeaders = new TreeMap<>();
|
||||
headers.forEach(header -> mapHeaders.put(new Integer(0).equals(header.getFileNameW().length()) ? header.getFileNameString().length() : 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().equals(new Integer(0).equals(header.getFileNameW().length()) ? header.getFileNameString().length() : header.getFileNameW().length())) {
|
||||
if (entry
|
||||
.getKey()
|
||||
.equals(
|
||||
new Integer(0).equals(header.getFileNameW().length())
|
||||
? header.getFileNameString().length()
|
||||
: header.getFileNameW().length())) {
|
||||
sortedHeaders.add(header);
|
||||
}
|
||||
}
|
||||
@@ -445,16 +502,29 @@ public class CompressFileReader {
|
||||
|
||||
class RarExtractorWorker implements Runnable {
|
||||
private final List<Map<String, FileHeader>> headersToBeExtracted;
|
||||
|
||||
private final List<Map<String, FileHeaderRar>> headersToBeExtract;
|
||||
|
||||
private final Archive archive;
|
||||
/**
|
||||
* 用以删除源文件
|
||||
*/
|
||||
private final String filePath;
|
||||
|
||||
public RarExtractorWorker(List<Map<String, FileHeader>> headersToBeExtracted, Archive archive, String filePath) {
|
||||
public RarExtractorWorker(
|
||||
List<Map<String, FileHeader>> headersToBeExtracted, Archive archive, String filePath) {
|
||||
this.headersToBeExtracted = headersToBeExtracted;
|
||||
this.archive = archive;
|
||||
this.filePath = filePath;
|
||||
headersToBeExtract = null;
|
||||
}
|
||||
|
||||
public RarExtractorWorker(
|
||||
List<Map<String, FileHeaderRar>> headersToBeExtract, String filePath) {
|
||||
this.headersToBeExtract = headersToBeExtract;
|
||||
this.filePath = filePath;
|
||||
archive = null;
|
||||
headersToBeExtracted = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -480,4 +550,74 @@ public class CompressFileReader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExtractCallback implements IArchiveExtractCallback {
|
||||
private final IInArchive inArchive;
|
||||
|
||||
private final String extractPath;
|
||||
private final String folderName;
|
||||
|
||||
public ExtractCallback(IInArchive inArchive, String extractPath, String folderName) {
|
||||
this.inArchive = inArchive;
|
||||
if (!extractPath.endsWith("/") && !extractPath.endsWith("\\")) {
|
||||
extractPath += File.separator;
|
||||
}
|
||||
this.extractPath = extractPath;
|
||||
this.folderName = folderName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTotal(long total) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompleted(long complete) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
|
||||
String filePath = inArchive.getStringProperty(index, PropID.PATH);
|
||||
String real = folderName + filePath.substring(filePath.lastIndexOf(File.separator) + 1);
|
||||
File f = new File(extractPath + real);
|
||||
f.delete();
|
||||
return data -> {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
File path = new File(extractPath + real);
|
||||
if (!path.getParentFile().exists()) {
|
||||
path.getParentFile().mkdirs();
|
||||
}
|
||||
if (!path.exists()) {
|
||||
path.createNewFile();
|
||||
}
|
||||
fos = new FileOutputStream(path, true);
|
||||
fos.write(data);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
fos.flush();
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return data.length;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareOperation(ExtractAskMode extractAskMode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOperationResult(ExtractOperationResult extractOperationResult) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,9 +270,13 @@ public class FileHandlerService {
|
||||
type = FileType.typeFromUrl(url);
|
||||
suffix = WebUtils.suffixFromUrl(url);
|
||||
}
|
||||
if (url.contains("?fileKey=")) {
|
||||
attribute.setSkipDownLoad(true);
|
||||
}
|
||||
attribute.setType(type);
|
||||
attribute.setName(fileName);
|
||||
attribute.setSuffix(suffix);
|
||||
url = WebUtils.encodeUrlFileName(url);
|
||||
attribute.setUrl(url);
|
||||
if (req != null) {
|
||||
String officePreviewType = req.getParameter("officePreviewType");
|
||||
@@ -283,7 +287,23 @@ public class FileHandlerService {
|
||||
if (StringUtils.hasText(fileKey)) {
|
||||
attribute.setFileKey(fileKey);
|
||||
}
|
||||
|
||||
String tifPreviewType = req.getParameter("tifPreviewType");
|
||||
if (StringUtils.hasText(tifPreviewType)) {
|
||||
attribute.setTifPreviewType(tifPreviewType);
|
||||
}
|
||||
|
||||
String filePassword = req.getParameter("filePassword");
|
||||
if (StringUtils.hasText(filePassword)) {
|
||||
attribute.setFilePassword(filePassword);
|
||||
}
|
||||
|
||||
String userToken = req.getParameter("userToken");
|
||||
if (StringUtils.hasText(userToken)) {
|
||||
attribute.setUserToken(userToken);
|
||||
}
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ 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.artofsolving.jodconverter.util.PlatformUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -24,7 +25,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 创建文件转换器
|
||||
@@ -50,7 +50,7 @@ public class OfficePluginManager {
|
||||
* 启动Office组件进程
|
||||
*/
|
||||
@PostConstruct
|
||||
public void startOfficeManager(){
|
||||
public void startOfficeManager() {
|
||||
File officeHome = OfficeUtils.getDefaultOfficeHome();
|
||||
if (officeHome == null) {
|
||||
throw new RuntimeException("找不到office组件,请确认'office.home'配置是否有误");
|
||||
@@ -62,7 +62,7 @@ public class OfficePluginManager {
|
||||
try {
|
||||
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
|
||||
configuration.setOfficeHome(officeHome);
|
||||
String []portsString = serverPorts.split(",");
|
||||
String[] portsString = serverPorts.split(",");
|
||||
|
||||
int[] ports = Arrays.stream(portsString).mapToInt(Integer::parseInt).toArray();
|
||||
|
||||
@@ -86,8 +86,8 @@ public class OfficePluginManager {
|
||||
return converter;
|
||||
}
|
||||
|
||||
private Map<String,?> getLoadProperties() {
|
||||
Map<String,Object> loadProperties = new HashMap<>(10);
|
||||
private Map<String, ?> getLoadProperties() {
|
||||
Map<String, Object> loadProperties = new HashMap<>(10);
|
||||
loadProperties.put("Hidden", true);
|
||||
loadProperties.put("ReadOnly", true);
|
||||
loadProperties.put("UpdateDocMode", UpdateDocMode.QUIET_UPDATE);
|
||||
@@ -97,9 +97,8 @@ public class OfficePluginManager {
|
||||
|
||||
private boolean killProcess() {
|
||||
boolean flag = false;
|
||||
Properties props = System.getProperties();
|
||||
try {
|
||||
if (props.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
if (PlatformUtils.isWindows()) {
|
||||
Process p = Runtime.getRuntime().exec("cmd /c tasklist ");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
@@ -112,8 +111,22 @@ public class OfficePluginManager {
|
||||
Runtime.getRuntime().exec("taskkill /im " + "soffice.bin" + " /f");
|
||||
flag = true;
|
||||
}
|
||||
} else if (PlatformUtils.isLinux()) {
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ps -ef | grep " + "soffice.bin" + " |grep -v grep | wc -l"});
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
byte[] b = new byte[256];
|
||||
while (os.read(b) > 0) {
|
||||
baos.write(b);
|
||||
}
|
||||
String s = baos.toString();
|
||||
if (!"0".equals(s)) {
|
||||
String[] cmd = {"sh", "-c", "ps -ef | grep soffice.bin | grep -v grep | awk '{print \"kill -9 \"$2}' | sh"};
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"sh","-c","ps -ef | grep " + "soffice.bin"});
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ps -ef | grep " + "soffice.bin"});
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
byte[] b = new byte[256];
|
||||
@@ -122,7 +135,7 @@ public class OfficePluginManager {
|
||||
}
|
||||
String s = baos.toString();
|
||||
if (StringUtils.ordinalIndexOf(s, "soffice.bin", 3) > 0) {
|
||||
String[] cmd ={"sh","-c","kill -15 `ps -ef|grep " + "soffice.bin" + "|awk 'NR==1{print $2}'`"};
|
||||
String[] cmd = {"sh", "-c", "kill -15 `ps -ef|grep " + "soffice.bin" + "|awk 'NR==1{print $2}'`"};
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
flag = true;
|
||||
}
|
||||
@@ -134,7 +147,7 @@ public class OfficePluginManager {
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroyOfficeManager(){
|
||||
public void destroyOfficeManager() {
|
||||
if (null != officeManager && officeManager.isRunning()) {
|
||||
logger.info("Shutting down office process");
|
||||
officeManager.stop();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import org.artofsolving.jodconverter.OfficeDocumentConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -20,22 +21,23 @@ public class OfficeToPdfService {
|
||||
this.officePluginManager = officePluginManager;
|
||||
}
|
||||
|
||||
public void openOfficeToPDF(String inputFilePath, String outputFilePath) {
|
||||
office2pdf(inputFilePath, outputFilePath);
|
||||
public void openOfficeToPDF(String inputFilePath, String outputFilePath, FileAttribute fileAttribute) {
|
||||
office2pdf(inputFilePath, outputFilePath, fileAttribute);
|
||||
}
|
||||
|
||||
|
||||
public static void converterFile(File inputFile, String outputFilePath_end, OfficeDocumentConverter converter) {
|
||||
public static void converterFile(File inputFile, String outputFilePath_end, OfficeDocumentConverter converter, FileAttribute fileAttribute) {
|
||||
File outputFile = new File(outputFilePath_end);
|
||||
// 假如目标路径不存在,则新建该路径
|
||||
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end);
|
||||
}
|
||||
converter.convert(inputFile, outputFile);
|
||||
|
||||
converter.convert(inputFile, outputFile, fileAttribute.toFileProperties());
|
||||
}
|
||||
|
||||
|
||||
public void office2pdf(String inputFilePath, String outputFilePath) {
|
||||
public void office2pdf(String inputFilePath, String outputFilePath, FileAttribute fileAttribute) {
|
||||
OfficeDocumentConverter converter = officePluginManager.getDocumentConverter();
|
||||
if (null != inputFilePath) {
|
||||
File inputFile = new File(inputFilePath);
|
||||
@@ -45,12 +47,12 @@ public class OfficeToPdfService {
|
||||
String outputFilePath_end = getOutputFilePath(inputFilePath);
|
||||
if (inputFile.exists()) {
|
||||
// 找不到源文件, 则返回
|
||||
converterFile(inputFile, outputFilePath_end,converter);
|
||||
converterFile(inputFile, outputFilePath_end, converter, fileAttribute);
|
||||
}
|
||||
} else {
|
||||
if (inputFile.exists()) {
|
||||
// 找不到源文件, 则返回
|
||||
converterFile(inputFile, outputFilePath, converter);
|
||||
converterFile(inputFile, outputFilePath, converter, fileAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,16 +40,7 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
if ("zip".equalsIgnoreCase(suffix) || "jar".equalsIgnoreCase(suffix) || "gzip".equalsIgnoreCase(suffix)) {
|
||||
fileTree = compressFileReader.readZipFile(filePath, fileName);
|
||||
} else if ("rar".equalsIgnoreCase(suffix)) {
|
||||
fileTree = compressFileReader.unRar(filePath, fileName);
|
||||
} else if ("7z".equalsIgnoreCase(suffix)) {
|
||||
fileTree = compressFileReader.read7zFile(filePath, fileName);
|
||||
}
|
||||
if (fileTree != null && !"null".equals(fileTree) && ConfigConstants.isCacheEnabled()) {
|
||||
fileHandlerService.addConvertedFile(fileName, fileTree);
|
||||
}
|
||||
fileTree = compressFileReader.unRar(filePath, fileName);
|
||||
} else {
|
||||
fileTree = fileHandlerService.getConvertedFile(fileName);
|
||||
}
|
||||
@@ -57,7 +48,7 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
model.addAttribute("fileTree", fileTree);
|
||||
return COMPRESS_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "压缩文件类型不受支持");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ 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.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.OfficeToPdfService;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.OfficeUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.artofsolving.jodconverter.office.OfficeException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -42,33 +44,83 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
String fileName = fileAttribute.getName();
|
||||
String filePassword = fileAttribute.getFilePassword();
|
||||
String userToken = fileAttribute.getUserToken();
|
||||
boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx");
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
|
||||
String outFilePath = FILE_DIR + pdfName;
|
||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
String filePath;
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
String cacheFileName = userToken == null ? pdfName : userToken + "_" + pdfName;
|
||||
String outFilePath = FILE_DIR + cacheFileName;
|
||||
|
||||
// 下载远程文件到本地,如果文件在本地已存在不会重复下载
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
|
||||
/*
|
||||
* 1. 缓存判断-如果文件已经进行转换过,就直接返回,否则执行转换
|
||||
* 2. 缓存判断-加密文件基于userToken进行缓存,如果没有就不缓存
|
||||
*/
|
||||
boolean isCached = false;
|
||||
boolean isUseCached = false;
|
||||
boolean isPwdProtectedOffice = false;
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 全局开启缓存
|
||||
isUseCached = true;
|
||||
if (fileHandlerService.listConvertedFiles().containsKey(cacheFileName)) {
|
||||
// 存在缓存
|
||||
isCached = true;
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
officeToPdfService.openOfficeToPDF(filePath, outFilePath);
|
||||
if (isHtml) {
|
||||
// 对转换后的文件进行操作(改变编码方式)
|
||||
fileHandlerService.doActionConvertedFile(outFilePath);
|
||||
if (OfficeUtils.isPwdProtected(filePath)) {
|
||||
isPwdProtectedOffice = true;
|
||||
if (!StringUtils.hasLength(userToken)) {
|
||||
// 不缓存没有userToken的加密文件
|
||||
isUseCached = false;
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
} else {
|
||||
isPwdProtectedOffice = OfficeUtils.isPwdProtected(filePath);
|
||||
}
|
||||
|
||||
if (isCached == false) {
|
||||
// 没有缓存执行转换逻辑
|
||||
if (isPwdProtectedOffice && !StringUtils.hasLength(filePassword)) {
|
||||
// 加密文件需要密码
|
||||
model.addAttribute("needFilePassword", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
try {
|
||||
officeToPdfService.openOfficeToPDF(filePath, outFilePath, fileAttribute);
|
||||
} catch (OfficeException e) {
|
||||
if (isPwdProtectedOffice && OfficeUtils.isCompatible(filePath, filePassword) == false) {
|
||||
// 加密文件密码错误,提示重新输入
|
||||
model.addAttribute("needFilePassword", true);
|
||||
model.addAttribute("filePasswordError", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "抱歉,该文件版本不兼容,文件版本错误。");
|
||||
}
|
||||
|
||||
if (isHtml) {
|
||||
// 对转换后的文件进行操作(改变编码方式)
|
||||
fileHandlerService.doActionConvertedFile(outFilePath);
|
||||
}
|
||||
if (isUseCached) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(cacheFileName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isHtml && baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, cacheFileName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", pdfName);
|
||||
|
||||
model.addAttribute("pdfUrl", cacheFileName);
|
||||
return isHtml ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
@@ -88,4 +140,5 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,8 +48,7 @@ public class SimTextFilePreviewImpl implements FilePreview {
|
||||
private String textData(String baseUrll) throws IOException {
|
||||
File file = new File(baseUrll);
|
||||
if(!file.exists() || file.length() == 0) {
|
||||
String line="";
|
||||
return line;
|
||||
return "";
|
||||
}else {
|
||||
String charset = EncodingDetects.getJavaEncode(baseUrll);
|
||||
System.out.println(charset);
|
||||
|
||||
@@ -1,38 +1,119 @@
|
||||
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.ConvertPicUtil;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* tiff 图片文件处理
|
||||
*
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class TiffFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(TiffFilePreviewImpl.class);
|
||||
|
||||
private final PictureFilePreviewImpl pictureFilePreview;
|
||||
private static final String INITIALIZE_MEMORY_SIZE = "initializeMemorySize";
|
||||
//默认初始化 50MB 内存
|
||||
private static final long INITIALIZE_MEMORY_SIZE_VALUE_DEFAULT = 1024L * 1024 * 50;
|
||||
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
|
||||
public TiffFilePreviewImpl(PictureFilePreviewImpl pictureFilePreview) {
|
||||
this.pictureFilePreview = pictureFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
pictureFilePreview.filePreviewHandle(url,model,fileAttribute);
|
||||
String fileSize = WebUtils.getUrlParameterReg(url,INITIALIZE_MEMORY_SIZE);
|
||||
if(StringUtils.hasText(fileSize)){
|
||||
model.addAttribute(INITIALIZE_MEMORY_SIZE,fileSize);
|
||||
}else {
|
||||
model.addAttribute(INITIALIZE_MEMORY_SIZE,Long.toString(INITIALIZE_MEMORY_SIZE_VALUE_DEFAULT));
|
||||
}
|
||||
return TIFF_FILE_PREVIEW_PAGE;
|
||||
String tifPreviewType = ConfigConstants.getTifPreviewType();
|
||||
String tifOnLinePreviewType = fileAttribute.getTifPreviewType();
|
||||
if (StringUtils.hasText(tifOnLinePreviewType)) {
|
||||
tifPreviewType = tifOnLinePreviewType;
|
||||
}
|
||||
|
||||
if ("tif".equalsIgnoreCase(tifPreviewType)) {
|
||||
|
||||
pictureFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
String fileSize = WebUtils.getUrlParameterReg(url, INITIALIZE_MEMORY_SIZE);
|
||||
if (StringUtils.hasText(fileSize)) {
|
||||
model.addAttribute(INITIALIZE_MEMORY_SIZE, fileSize);
|
||||
} else {
|
||||
model.addAttribute(INITIALIZE_MEMORY_SIZE, Long.toString(INITIALIZE_MEMORY_SIZE_VALUE_DEFAULT));
|
||||
}
|
||||
return TIFF_FILE_PREVIEW_PAGE;
|
||||
|
||||
} else if ("jpg".equalsIgnoreCase(tifPreviewType) || "pdf".equalsIgnoreCase(tifPreviewType)) {
|
||||
String inputFileName = url.substring(url.lastIndexOf("/") + 1);
|
||||
String inputFileNamePrefix = inputFileName.substring(0, inputFileName.lastIndexOf("."));
|
||||
|
||||
String strLocalTif = fileDir + inputFileName;
|
||||
File fileTiff = new File(strLocalTif);
|
||||
// 如果本地不存在这个tif文件,则下载
|
||||
if (!fileTiff.exists()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, inputFileName);
|
||||
if (response.isFailure()) {
|
||||
return NOT_SUPPORTED_FILE_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
if ("pdf".equalsIgnoreCase(tifPreviewType)) {
|
||||
// 以PDF模式预览的过程
|
||||
File filePdf = new File(fileDir + inputFileNamePrefix + ".pdf");
|
||||
// 如果本地不存在对应的pdf,则调用转换过程。否则直接用现有的pdf文件
|
||||
if (!filePdf.exists()) {
|
||||
filePdf = ConvertPicUtil.convertTif2Pdf(strLocalTif, fileDir + inputFileNamePrefix + ".pdf");
|
||||
}
|
||||
|
||||
// 如果pdf已经存在,则将url路径加入到对象中,返回给页面
|
||||
assert filePdf != null;
|
||||
if (filePdf.exists()) {
|
||||
String pdfUrl = baseUrl + inputFileNamePrefix + ".pdf";
|
||||
model.addAttribute("pdfUrl", pdfUrl);
|
||||
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
} else {
|
||||
// 以JPG模式预览的过程
|
||||
String strJpgFilePathName = fileDir + inputFileNamePrefix + ".jpg";
|
||||
// 将tif转换为jpg,返回转换后的文件路径、文件名的list
|
||||
List<String> listPic2Jpg = ConvertPicUtil.convertTif2Jpg(strLocalTif, strJpgFilePathName);
|
||||
// 将返回页面的图片url的list对象
|
||||
List<String> listImageUrls = new ArrayList<>();
|
||||
// 循环,拼装url的list对象
|
||||
for (String strJpg : listPic2Jpg) {
|
||||
listImageUrls.add(baseUrl + strJpg);
|
||||
}
|
||||
|
||||
model.addAttribute("imgUrls", listImageUrls);
|
||||
model.addAttribute("currentUrl", listImageUrls.get(0));
|
||||
}
|
||||
|
||||
// 转换后的tif没用了,可以删掉了
|
||||
if (fileTiff.exists() && !fileTiff.delete()) {
|
||||
logger.error("{} 清理失败", strLocalTif);
|
||||
}
|
||||
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
return NOT_SUPPORTED_FILE_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
231
server/src/main/java/cn/keking/utils/ConvertPicUtil.java
Normal file
@@ -0,0 +1,231 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
|
||||
import com.lowagie.text.Document;
|
||||
import com.lowagie.text.Image;
|
||||
import com.lowagie.text.Rectangle;
|
||||
import com.lowagie.text.pdf.PdfWriter;
|
||||
import com.lowagie.text.pdf.RandomAccessFileOrArray;
|
||||
import com.lowagie.text.pdf.codec.TiffImage;
|
||||
import com.sun.media.jai.codec.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.media.jai.JAI;
|
||||
import javax.media.jai.RenderedOp;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.ParameterBlock;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConvertPicUtil {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ConvertPicUtil.class);
|
||||
|
||||
/**
|
||||
* Tif 转 JPG。
|
||||
*
|
||||
* @param strInputFile 输入文件的路径和文件名
|
||||
* @param strOutputFile 输出文件的路径和文件名
|
||||
* @return boolean 是否转换成功
|
||||
*/
|
||||
public static List<String> convertTif2Jpg(String strInputFile, String strOutputFile) {
|
||||
List<String> listImageFiles = new ArrayList<>();
|
||||
|
||||
if (strInputFile == null || "".equals(strInputFile.trim())) {
|
||||
return null;
|
||||
}
|
||||
if (!new File(strInputFile).exists()) {
|
||||
logger.info("找不到文件【" + strInputFile + "】");
|
||||
return null;
|
||||
}
|
||||
|
||||
strInputFile = strInputFile.replaceAll("\\\\", "/");
|
||||
strOutputFile = strOutputFile.replaceAll("\\\\", "/");
|
||||
|
||||
FileSeekableStream fileSeekStream = null;
|
||||
try {
|
||||
JPEGEncodeParam jpegEncodeParam = new JPEGEncodeParam();
|
||||
|
||||
TIFFEncodeParam tiffEncodeParam = new TIFFEncodeParam();
|
||||
tiffEncodeParam.setCompression(TIFFEncodeParam.COMPRESSION_GROUP4);
|
||||
tiffEncodeParam.setLittleEndian(false);
|
||||
|
||||
String strFilePrefix = strInputFile.substring(strInputFile.lastIndexOf("/") + 1, strInputFile.lastIndexOf("."));
|
||||
|
||||
fileSeekStream = new FileSeekableStream(strInputFile);
|
||||
ImageDecoder imageDecoder = ImageCodec.createImageDecoder("TIFF", fileSeekStream, null);
|
||||
int intTifCount = imageDecoder.getNumPages();
|
||||
logger.info("该tif文件共有【" + intTifCount + "】页");
|
||||
|
||||
String strJpgPath;
|
||||
String strJpgUrl;
|
||||
if (intTifCount == 1) {
|
||||
// 如果是单页tif文件,则转换的目标文件夹就在指定的位置
|
||||
strJpgPath = strOutputFile.substring(0, strOutputFile.lastIndexOf("/"));
|
||||
} else {
|
||||
// 如果是多页tif文件,则在目标文件夹下,按照文件名再创建子目录,将转换后的文件放入此新建的子目录中
|
||||
strJpgPath = strOutputFile.substring(0, strOutputFile.lastIndexOf("."));
|
||||
}
|
||||
|
||||
// 处理目标文件夹,如果不存在则自动创建
|
||||
File fileJpgPath = new File(strJpgPath);
|
||||
if (!fileJpgPath.exists() && !fileJpgPath.mkdirs()) {
|
||||
logger.error("{} 创建失败", strJpgPath);
|
||||
}
|
||||
|
||||
// 循环,处理每页tif文件,转换为jpg
|
||||
for (int i = 0; i < intTifCount; i++) {
|
||||
String strJpg;
|
||||
if (intTifCount == 1) {
|
||||
strJpg = strJpgPath + "/" + strFilePrefix + ".jpg";
|
||||
strJpgUrl = strFilePrefix + ".jpg";
|
||||
} else {
|
||||
strJpg = strJpgPath + "/" + i + ".jpg";
|
||||
strJpgUrl = strFilePrefix + "/" + i + ".jpg";
|
||||
}
|
||||
|
||||
File fileJpg = new File(strJpg);
|
||||
|
||||
// 如果文件不存在,则生成
|
||||
if (!fileJpg.exists()) {
|
||||
RenderedImage renderedImage = imageDecoder.decodeAsRenderedImage(i);
|
||||
ParameterBlock pb = new ParameterBlock();
|
||||
pb.addSource(renderedImage);
|
||||
pb.add(fileJpg.toString());
|
||||
pb.add("JPEG");
|
||||
pb.add(jpegEncodeParam);
|
||||
|
||||
RenderedOp renderedOp = JAI.create("filestore", pb);
|
||||
renderedOp.dispose();
|
||||
|
||||
logger.info("每页分别保存至: " + fileJpg.getCanonicalPath());
|
||||
} else {
|
||||
logger.info("JPG文件已存在: " + fileJpg.getCanonicalPath());
|
||||
}
|
||||
|
||||
listImageFiles.add(strJpgUrl);
|
||||
}
|
||||
|
||||
return listImageFiles;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (fileSeekStream != null) {
|
||||
try {
|
||||
fileSeekStream.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Jpg图片转换为Pdf文件
|
||||
*
|
||||
* @param strJpgFile 输入的jpg的路径和文件名
|
||||
* @param strPdfFile 输出的pdf的路径和文件名
|
||||
*/
|
||||
public static void convertJpg2Pdf(String strJpgFile, String strPdfFile) {
|
||||
Document document = new Document();
|
||||
// 设置文档页边距
|
||||
document.setMargins(0, 0, 0, 0);
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(strPdfFile);
|
||||
PdfWriter.getInstance(document, fos);
|
||||
// 打开文档
|
||||
document.open();
|
||||
// 获取图片的宽高
|
||||
Image image = Image.getInstance(strJpgFile);
|
||||
float floatImageHeight = image.getScaledHeight();
|
||||
float floatImageWidth = image.getScaledWidth();
|
||||
// 设置页面宽高与图片一致
|
||||
Rectangle rectangle = new Rectangle(floatImageWidth, floatImageHeight);
|
||||
document.setPageSize(rectangle);
|
||||
// 图片居中
|
||||
image.setAlignment(Image.ALIGN_CENTER);
|
||||
//新建一页添加图片
|
||||
document.newPage();
|
||||
document.add(image);
|
||||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
//关闭文档
|
||||
document.close();
|
||||
try {
|
||||
assert fos != null;
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将Tif图片转换为Pdf文件(支持多页Tif)
|
||||
*
|
||||
* @param strTifFile 输入的tif的路径和文件名
|
||||
* @param strPdfFile 输出的pdf的路径和文件名
|
||||
* @return File
|
||||
*/
|
||||
public static File convertTif2Pdf(String strTifFile, String strPdfFile) {
|
||||
try {
|
||||
RandomAccessFileOrArray rafa = new RandomAccessFileOrArray(strTifFile);
|
||||
|
||||
Document document = new Document();
|
||||
// 设置文档页边距
|
||||
document.setMargins(0, 0, 0, 0);
|
||||
|
||||
PdfWriter.getInstance(document, new FileOutputStream(strPdfFile));
|
||||
document.open();
|
||||
int intPages = TiffImage.getNumberOfPages(rafa);
|
||||
Image image;
|
||||
File filePDF;
|
||||
|
||||
if (intPages == 1) {
|
||||
String strJpg = strTifFile.substring(0, strTifFile.lastIndexOf(".")) + ".jpg";
|
||||
File fileJpg = new File(strJpg);
|
||||
List<String> listPic2Jpg = convertTif2Jpg(strTifFile, strJpg);
|
||||
|
||||
if (listPic2Jpg != null && fileJpg.exists()) {
|
||||
convertJpg2Pdf(strJpg, strPdfFile);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 1; i <= intPages; i++) {
|
||||
image = TiffImage.getTiffImage(rafa, i);
|
||||
// 设置页面宽高与图片一致
|
||||
Rectangle pageSize = new Rectangle(image.getScaledWidth(), image.getScaledHeight());
|
||||
document.setPageSize(pageSize);
|
||||
// 图片居中
|
||||
image.setAlignment(Image.ALIGN_CENTER);
|
||||
//新建一页添加图片
|
||||
document.newPage();
|
||||
document.add(image);
|
||||
}
|
||||
|
||||
document.close();
|
||||
}
|
||||
|
||||
rafa.close();
|
||||
|
||||
filePDF = new File(strPdfFile);
|
||||
|
||||
return filePDF;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,22 +32,24 @@ public class DownloadUtils {
|
||||
* @return 本地文件绝对路径
|
||||
*/
|
||||
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
String urlStr = fileAttribute.getUrl();
|
||||
String urlStr = fileAttribute.getUrl().replaceAll("\\+", "%20");
|
||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||
String realPath = DownloadUtils.getRelFilePath(fileName, fileAttribute);
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlStr);
|
||||
if (isHttpUrl(url)) {
|
||||
File realFile = new File(realPath);
|
||||
FileUtils.copyURLToFile(url,realFile);
|
||||
} else if (isFtpUrl(url)) {
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||
} else {
|
||||
response.setCode(1);
|
||||
response.setMsg("url不能识别url" + urlStr);
|
||||
if (!fileAttribute.getSkipDownLoad()) {
|
||||
if (isHttpUrl(url)) {
|
||||
File realFile = new File(realPath);
|
||||
FileUtils.copyURLToFile(url, realFile);
|
||||
} else if (isFtpUrl(url)) {
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||
} else {
|
||||
response.setCode(1);
|
||||
response.setMsg("url不能识别url" + urlStr);
|
||||
}
|
||||
}
|
||||
response.setContent(realPath);
|
||||
response.setMsg(fileName);
|
||||
@@ -85,6 +87,13 @@ public class DownloadUtils {
|
||||
if (!dirFile.exists() && !dirFile.mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
|
||||
}
|
||||
|
||||
// 文件已在本地存在,跳过文件下载
|
||||
File realFile = new File(realPath);
|
||||
if (realFile.exists()) {
|
||||
fileAttribute.setSkipDownLoad(true);
|
||||
}
|
||||
|
||||
return realPath;
|
||||
}
|
||||
|
||||
|
||||
28
server/src/main/java/cn/keking/utils/FileHeaderRar.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
public class FileHeaderRar {
|
||||
|
||||
private String fileNameW;
|
||||
private Boolean isDirectory;
|
||||
|
||||
public FileHeaderRar(String fileNameW, Boolean isDirectory) {
|
||||
this.fileNameW = fileNameW;
|
||||
this.isDirectory = isDirectory;
|
||||
}
|
||||
|
||||
public String getFileNameW() {
|
||||
return fileNameW;
|
||||
}
|
||||
|
||||
public void setFileNameW(String fileNameW) {
|
||||
this.fileNameW = fileNameW;
|
||||
}
|
||||
|
||||
public Boolean getDirectory() {
|
||||
return isDirectory;
|
||||
}
|
||||
|
||||
public void setDirectory(Boolean directory) {
|
||||
isDirectory = directory;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class KkFileUtils {
|
||||
@@ -15,6 +17,33 @@ public class KkFileUtils {
|
||||
|
||||
public static final String DEFAULT_FILE_ENCODING = "UTF-8";
|
||||
|
||||
private static final List<String> illegalFileStrList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
illegalFileStrList.add("../");
|
||||
illegalFileStrList.add("./");
|
||||
illegalFileStrList.add("..\\");
|
||||
illegalFileStrList.add(".\\");
|
||||
illegalFileStrList.add("\\..");
|
||||
illegalFileStrList.add("\\.");
|
||||
illegalFileStrList.add("..");
|
||||
illegalFileStrList.add("...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件名是否合规
|
||||
* @param fileName 文件名
|
||||
* @return 合规结果,true:不合规,false:合规
|
||||
*/
|
||||
public static boolean isIllegalFileName(String fileName){
|
||||
for (String str: illegalFileStrList){
|
||||
if(fileName.contains(str)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否是http资源
|
||||
*
|
||||
|
||||
62
server/src/main/java/cn/keking/utils/OfficeUtils.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.apache.poi.extractor.ExtractorFactory;
|
||||
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* Office工具类
|
||||
*
|
||||
* @author ylyue
|
||||
* @since 2022/7/5
|
||||
*/
|
||||
public class OfficeUtils {
|
||||
|
||||
/**
|
||||
* 判断office(word,excel,ppt)文件是否受密码保护
|
||||
*
|
||||
* @param path office文件路径
|
||||
* @return 是否受密码保护
|
||||
*/
|
||||
public static boolean isPwdProtected(String path) {
|
||||
try {
|
||||
ExtractorFactory.createExtractor(new FileInputStream(path));
|
||||
} catch (EncryptedDocumentException e) {
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Throwable[] throwables = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwables) {
|
||||
if (throwable instanceof EncryptedDocumentException) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断office文件是否可打开(兼容)
|
||||
*
|
||||
* @param path office文件路径
|
||||
* @param password 文件密码
|
||||
* @return 是否可打开(兼容)
|
||||
*/
|
||||
public static synchronized boolean isCompatible(String path, @Nullable String password) {
|
||||
try {
|
||||
Biff8EncryptionKey.setCurrentUserPassword(password);
|
||||
ExtractorFactory.createExtractor(new FileInputStream(path));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
} finally {
|
||||
Biff8EncryptionKey.setCurrentUserPassword(null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -15,6 +22,7 @@ public class WebUtils {
|
||||
|
||||
/**
|
||||
* 获取标准的URL
|
||||
*
|
||||
* @param urlStr url
|
||||
* @return 标准的URL
|
||||
*/
|
||||
@@ -79,6 +87,14 @@ public class WebUtils {
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getFileNameFromURL(String url) {
|
||||
if (url.toLowerCase().startsWith("file:")) {
|
||||
try {
|
||||
URL urlObj = new URL(url);
|
||||
url = urlObj.getPath().substring(1);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题
|
||||
// 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名
|
||||
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
@@ -97,4 +113,103 @@ public class WebUtils {
|
||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
||||
return KkFileUtils.suffixFromFileName(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对url中的文件名进行UTF-8编码
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件名编码后的url
|
||||
*/
|
||||
public static String encodeUrlFileName(String url) {
|
||||
String encodedFileName;
|
||||
String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
|
||||
if (fullFileName != null && fullFileName.length() > 0) {
|
||||
try {
|
||||
encodedFileName = URLEncoder.encode(fullFileName, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
String noQueryUrl = url.substring(0, url.indexOf("?"));
|
||||
String parameterStr = url.substring(url.indexOf("?"));
|
||||
parameterStr = parameterStr.replaceFirst(fullFileName, encodedFileName);
|
||||
return noQueryUrl + parameterStr;
|
||||
}
|
||||
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
int fileNameStartIndex = noQueryUrl.lastIndexOf('/') + 1;
|
||||
int fileNameEndIndex = noQueryUrl.lastIndexOf('.');
|
||||
try {
|
||||
encodedFileName = URLEncoder.encode(noQueryUrl.substring(fileNameStartIndex, fileNameEndIndex), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
return url.substring(0, fileNameStartIndex) + encodedFileName + url.substring(fileNameEndIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 ServletRequest 获取预览的源 url , 已 base64 解码
|
||||
*
|
||||
* @param request 请求 request
|
||||
* @return url
|
||||
*/
|
||||
public static String getSourceUrl(ServletRequest request) {
|
||||
String url = request.getParameter("url");
|
||||
String urls = request.getParameter("urls");
|
||||
String currentUrl = request.getParameter("currentUrl");
|
||||
String urlPath = request.getParameter("urlPath");
|
||||
if (StringUtils.isNotBlank(url)) {
|
||||
return decodeBase64String(url);
|
||||
}
|
||||
if (StringUtils.isNotBlank(currentUrl)) {
|
||||
return decodeBase64String(currentUrl);
|
||||
}
|
||||
if (StringUtils.isNotBlank(urlPath)) {
|
||||
return decodeBase64String(urlPath);
|
||||
}
|
||||
if (StringUtils.isNotBlank(urls)) {
|
||||
urls = decodeBase64String(urls);
|
||||
String[] images = urls.split("\\|");
|
||||
return images[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Base64 字符串解码,默认使用 UTF-8
|
||||
* @param source 原始 Base64 字符串
|
||||
* @return decoded string
|
||||
*/
|
||||
public static String decodeBase64String(String source) {
|
||||
return decodeBase64String(source, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Base64 字符串使用指定字符集解码
|
||||
* @param source 原始 Base64 字符串
|
||||
* @param charsets 字符集
|
||||
* @return decoded string
|
||||
*/
|
||||
public static String decodeBase64String(String source, Charset charsets) {
|
||||
/*
|
||||
* url 传入的参数里加号会被替换成空格,导致解析出错,这里需要把空格替换回加号
|
||||
* 有些 Base64 实现可能每 76 个字符插入换行符,也一并去掉
|
||||
* https://github.com/kekingcn/kkFileView/pull/340
|
||||
*/
|
||||
return new String(Base64Utils.decodeFromString(
|
||||
source.replaceAll(" ", "+").replaceAll("\n", "")
|
||||
), charsets);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 url 的 host
|
||||
* @param urlStr url
|
||||
* @return host
|
||||
*/
|
||||
public static String getHost(String urlStr) {
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
return url.getHost().toLowerCase();
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author yudian-it
|
||||
* @date 2017/12/1
|
||||
*/
|
||||
@@ -33,16 +40,17 @@ public class FileController {
|
||||
private final String demoDir = "demo";
|
||||
private final String demoPath = demoDir + File.separator;
|
||||
|
||||
@RequestMapping(value = "fileUpload", method = RequestMethod.POST)
|
||||
public String fileUpload(@RequestParam("file") MultipartFile file) throws JsonProcessingException {
|
||||
@PostMapping("/fileUpload")
|
||||
public ReturnResponse<Object> fileUpload(@RequestParam("file") MultipartFile file) throws JsonProcessingException {
|
||||
if (ConfigConstants.getFileUploadDisable()) {
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.failure("文件传接口已禁用"));
|
||||
return ReturnResponse.failure("文件传接口已禁用");
|
||||
}
|
||||
// 获取文件名
|
||||
String fileName = file.getOriginalFilename();
|
||||
//判断是否为IE浏览器的文件名,IE浏览器下文件名会带有盘符信息
|
||||
|
||||
|
||||
// escaping dangerous characters to prevent XSS
|
||||
assert fileName != null;
|
||||
fileName = HtmlUtils.htmlEscape(fileName, StandardCharsets.UTF_8.name());
|
||||
|
||||
// Check for Unix-style path
|
||||
@@ -51,42 +59,47 @@ public class FileController {
|
||||
int winSep = fileName.lastIndexOf('\\');
|
||||
// Cut off at latest possible point
|
||||
int pos = (Math.max(winSep, unixSep));
|
||||
if (pos != -1) {
|
||||
if (pos != -1) {
|
||||
fileName = fileName.substring(pos + 1);
|
||||
}
|
||||
// 判断是否存在同名文件
|
||||
if (existsFile(fileName)) {
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.failure("存在同名文件,请先删除原有文件再次上传"));
|
||||
return ReturnResponse.failure("存在同名文件,请先删除原有文件再次上传");
|
||||
}
|
||||
File outFile = new File(fileDir + demoPath);
|
||||
if (!outFile.exists() && !outFile.mkdirs()) {
|
||||
logger.error("创建文件夹【{}】失败,请检查目录权限!",fileDir + demoPath);
|
||||
logger.error("创建文件夹【{}】失败,请检查目录权限!", fileDir + demoPath);
|
||||
}
|
||||
logger.info("上传文件:{}", fileDir + demoPath + fileName);
|
||||
try(InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileDir + demoPath + fileName)) {
|
||||
try (InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileDir + demoPath + fileName)) {
|
||||
StreamUtils.copy(in, out);
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.success(null));
|
||||
return ReturnResponse.success(null);
|
||||
} catch (IOException e) {
|
||||
logger.error("文件上传失败", e);
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.failure());
|
||||
return ReturnResponse.failure();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "deleteFile", method = RequestMethod.GET)
|
||||
public String deleteFile(String fileName) throws JsonProcessingException {
|
||||
@GetMapping("/deleteFile")
|
||||
public ReturnResponse<Object> deleteFile(String fileName) throws JsonProcessingException {
|
||||
if (fileName.contains("/")) {
|
||||
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
|
||||
}
|
||||
if (KkFileUtils.isIllegalFileName(fileName)) {
|
||||
return ReturnResponse.failure("非法文件名,删除失败!");
|
||||
}
|
||||
File file = new File(fileDir + demoPath + fileName);
|
||||
logger.info("删除文件:{}", file.getAbsolutePath());
|
||||
if (file.exists() && !file.delete()) {
|
||||
logger.error("删除文件【{}】失败,请检查目录权限!",file.getPath());
|
||||
String msg = String.format("删除文件【%s】失败,请检查目录权限!", file.getPath());
|
||||
logger.error(msg);
|
||||
return ReturnResponse.failure(msg);
|
||||
}
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.success());
|
||||
return ReturnResponse.success();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "listFiles", method = RequestMethod.GET)
|
||||
public String getFiles() throws JsonProcessingException {
|
||||
@GetMapping("/listFiles")
|
||||
public List<Map<String, String>> getFiles() throws JsonProcessingException {
|
||||
List<Map<String, String>> list = new ArrayList<>();
|
||||
File file = new File(fileDir + demoPath);
|
||||
if (file.exists()) {
|
||||
@@ -96,7 +109,7 @@ public class FileController {
|
||||
list.add(fileName);
|
||||
});
|
||||
}
|
||||
return new ObjectMapper().writeValueAsString(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean existsFile(String fileName) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
/**
|
||||
* 页面跳转
|
||||
@@ -12,12 +11,12 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@Controller
|
||||
public class IndexController {
|
||||
|
||||
@RequestMapping(value = "/index", method = RequestMethod.GET)
|
||||
@GetMapping( "/index")
|
||||
public String go2Index(){
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
||||
@GetMapping( "/")
|
||||
public String root() {
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.FilePreviewFactory;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import fr.opensagres.xdocreport.core.io.IOUtils;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
@@ -17,13 +16,14 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
@@ -52,11 +52,11 @@ public class OnlinePreviewController {
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onlinePreview")
|
||||
@GetMapping( "/onlinePreview")
|
||||
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
||||
String fileUrl;
|
||||
try {
|
||||
fileUrl = new String(Base64.decodeBase64(url), StandardCharsets.UTF_8);
|
||||
fileUrl = WebUtils.decodeBase64String(url);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
@@ -68,15 +68,18 @@ public class OnlinePreviewController {
|
||||
return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/picturesPreview")
|
||||
@GetMapping( "/picturesPreview")
|
||||
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
|
||||
String fileUrls;
|
||||
try {
|
||||
fileUrls = new String(Base64.decodeBase64(urls));
|
||||
fileUrls = WebUtils.decodeBase64String(urls);
|
||||
// 防止XSS攻击
|
||||
fileUrls = HtmlUtils.htmlEscape(fileUrls);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "urls");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
|
||||
logger.info("预览文件url:{},urls:{}", fileUrls, urls);
|
||||
// 抽取文件并返回文件列表
|
||||
String[] images = fileUrls.split("\\|");
|
||||
@@ -100,8 +103,20 @@ public class OnlinePreviewController {
|
||||
* @param urlPath url
|
||||
* @param response response
|
||||
*/
|
||||
@RequestMapping(value = "/getCorsFile", method = RequestMethod.GET)
|
||||
@GetMapping("/getCorsFile")
|
||||
public void getCorsFile(String urlPath, HttpServletResponse response) {
|
||||
try {
|
||||
urlPath = WebUtils.decodeBase64String(urlPath);
|
||||
} catch (Exception ex) {
|
||||
logger.error(String.format(BASE64_DECODE_ERROR_MSG, urlPath),ex);
|
||||
return;
|
||||
}
|
||||
if (urlPath.toLowerCase().startsWith("file:") || urlPath.toLowerCase().startsWith("file%3")
|
||||
|| !urlPath.toLowerCase().startsWith("http")) {
|
||||
logger.info("读取跨域文件异常,可能存在非法访问,urlPath:{}", urlPath);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("下载跨域pdf文件url:{}", urlPath);
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlPath);
|
||||
@@ -117,7 +132,7 @@ public class OnlinePreviewController {
|
||||
*
|
||||
* @param url 请编码后在入队
|
||||
*/
|
||||
@RequestMapping("/addTask")
|
||||
@GetMapping("/addTask")
|
||||
@ResponseBody
|
||||
public String addQueueTask(String url) {
|
||||
logger.info("添加转码队列url:{}", url);
|
||||
|
||||
@@ -30,8 +30,12 @@ public class AttributeSetFilter implements Filter {
|
||||
* @param request request
|
||||
*/
|
||||
private void setFileAttribute(ServletRequest request){
|
||||
HttpServletRequest httpRequest = (HttpServletRequest)request;
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
request.setAttribute("pdfPresentationModeDisable", ConfigConstants.getPdfPresentationModeDisable());
|
||||
request.setAttribute("pdfOpenFileDisable", ConfigConstants.getPdfOpenFileDisable());
|
||||
request.setAttribute("pdfPrintDisable", ConfigConstants.getPdfPrintDisable());
|
||||
request.setAttribute("pdfDownloadDisable", ConfigConstants.getPdfDownloadDisable());
|
||||
request.setAttribute("pdfBookmarkDisable", ConfigConstants.getPdfBookmarkDisable());
|
||||
request.setAttribute("fileKey", httpRequest.getParameter("fileKey"));
|
||||
request.setAttribute("switchDisabled", ConfigConstants.getOfficePreviewSwitchDisabled());
|
||||
request.setAttribute("fileUploadDisable", ConfigConstants.getFileUploadDisable());
|
||||
@@ -44,15 +48,24 @@ public class AttributeSetFilter implements Filter {
|
||||
private void setWatermarkAttribute(ServletRequest request) {
|
||||
String watermarkTxt = request.getParameter("watermarkTxt");
|
||||
request.setAttribute("watermarkTxt", watermarkTxt != null ? watermarkTxt : WatermarkConfigConstants.getWatermarkTxt());
|
||||
request.setAttribute("watermarkXSpace", WatermarkConfigConstants.getWatermarkXSpace());
|
||||
request.setAttribute("watermarkYSpace", WatermarkConfigConstants.getWatermarkYSpace());
|
||||
request.setAttribute("watermarkFont", WatermarkConfigConstants.getWatermarkFont());
|
||||
request.setAttribute("watermarkFontsize", WatermarkConfigConstants.getWatermarkFontsize());
|
||||
request.setAttribute("watermarkColor", WatermarkConfigConstants.getWatermarkColor());
|
||||
request.setAttribute("watermarkAlpha", WatermarkConfigConstants.getWatermarkAlpha());
|
||||
request.setAttribute("watermarkWidth", WatermarkConfigConstants.getWatermarkWidth());
|
||||
request.setAttribute("watermarkHeight", WatermarkConfigConstants.getWatermarkHeight());
|
||||
request.setAttribute("watermarkAngle", WatermarkConfigConstants.getWatermarkAngle());
|
||||
String watermarkXSpace = request.getParameter("watermarkXSpace");
|
||||
request.setAttribute("watermarkXSpace", watermarkXSpace != null ? watermarkXSpace : WatermarkConfigConstants.getWatermarkXSpace());
|
||||
String watermarkYSpace = request.getParameter("watermarkYSpace");
|
||||
request.setAttribute("watermarkYSpace", watermarkYSpace != null ? watermarkYSpace : WatermarkConfigConstants.getWatermarkYSpace());
|
||||
String watermarkFont = request.getParameter("watermarkFont");
|
||||
request.setAttribute("watermarkFont", watermarkFont != null ? watermarkFont : WatermarkConfigConstants.getWatermarkFont());
|
||||
String watermarkFontsize = request.getParameter("watermarkFontsize");
|
||||
request.setAttribute("watermarkFontsize", watermarkFontsize != null ? watermarkFontsize : WatermarkConfigConstants.getWatermarkFontsize());
|
||||
String watermarkColor = request.getParameter("watermarkColor");
|
||||
request.setAttribute("watermarkColor", watermarkColor != null ? watermarkColor : WatermarkConfigConstants.getWatermarkColor());
|
||||
String watermarkAlpha = request.getParameter("watermarkAlpha");
|
||||
request.setAttribute("watermarkAlpha", watermarkAlpha != null ? watermarkAlpha : WatermarkConfigConstants.getWatermarkAlpha());
|
||||
String watermarkWidth = request.getParameter("watermarkWidth");
|
||||
request.setAttribute("watermarkWidth", watermarkWidth != null ? watermarkWidth : WatermarkConfigConstants.getWatermarkWidth());
|
||||
String watermarkHeight = request.getParameter("watermarkHeight");
|
||||
request.setAttribute("watermarkHeight", watermarkHeight != null ? watermarkHeight : WatermarkConfigConstants.getWatermarkHeight());
|
||||
String watermarkAngle = request.getParameter("watermarkAngle");
|
||||
request.setAttribute("watermarkAngle", watermarkAngle != null ? watermarkAngle : WatermarkConfigConstants.getWatermarkAngle());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import javax.servlet.*;
|
||||
@@ -18,7 +19,7 @@ public class BaseUrlFilter implements Filter {
|
||||
public static String getBaseUrl() {
|
||||
String baseUrl;
|
||||
try {
|
||||
baseUrl = (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
|
||||
baseUrl = (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl", 0);
|
||||
} catch (Exception e) {
|
||||
baseUrl = BASE_URL;
|
||||
}
|
||||
@@ -33,19 +34,28 @@ public class BaseUrlFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
|
||||
String baseUrl;
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
pathBuilder.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
|
||||
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
||||
String baseUrlTmp = ConfigConstants.getBaseUrl();
|
||||
if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equalsIgnoreCase(baseUrlTmp)) {
|
||||
if (!baseUrlTmp.endsWith("/")) {
|
||||
baseUrlTmp = baseUrlTmp.concat("/");
|
||||
}
|
||||
baseUrl = baseUrlTmp;
|
||||
String configBaseUrl = ConfigConstants.getBaseUrl();
|
||||
|
||||
final HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||
//1、支持通过 http header 中 X-Base-Url 来动态设置 baseUrl 以支持多个域名/项目的共享使用
|
||||
final String urlInHeader = servletRequest.getHeader("X-Base-Url");
|
||||
if (StringUtils.isNotEmpty(urlInHeader)) {
|
||||
baseUrl = urlInHeader;
|
||||
} else if (configBaseUrl != null && !ConfigConstants.DEFAULT_BASE_URL.equalsIgnoreCase(configBaseUrl)) {
|
||||
//2、如果配置文件中配置了 baseUrl 且不为 default 则以配置文件为准
|
||||
baseUrl = configBaseUrl;
|
||||
} else {
|
||||
baseUrl = pathBuilder.toString();
|
||||
//3、默认动态拼接 baseUrl
|
||||
baseUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
|
||||
+ servletRequest.getContextPath() + "/";
|
||||
}
|
||||
|
||||
if (!baseUrl.endsWith("/")) {
|
||||
baseUrl = baseUrl.concat("/");
|
||||
}
|
||||
|
||||
BASE_URL = baseUrl;
|
||||
request.setAttribute("baseUrl", baseUrl);
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author yudian-it
|
||||
* @date 2017/11/30
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean getChinesePathFilter() {
|
||||
ChinesePathFilter filter = new ChinesePathFilter();
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(filter);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean getTrustHostFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
TrustHostFilter filter = new TrustHostFilter();
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean getBaseUrlFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/index");
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
BaseUrlFilter filter = new BaseUrlFilter();
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean getWatermarkConfigFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/index");
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
AttributeSetFilter filter = new AttributeSetFilter();
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author : kl (http://kailing.pub)
|
||||
* @since : 2022-05-25 17:45
|
||||
*/
|
||||
public class TrustDirFilter implements Filter {
|
||||
|
||||
private String notTrustDirView;
|
||||
private final Logger logger = LoggerFactory.getLogger(TrustDirFilter.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
ClassPathResource classPathResource = new ClassPathResource("web/notTrustDir.html");
|
||||
try {
|
||||
classPathResource.getInputStream();
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
|
||||
this.notTrustDirView = new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String url = WebUtils.getSourceUrl(request);
|
||||
if (!allowPreview(url)) {
|
||||
response.getWriter().write(this.notTrustDirView);
|
||||
response.getWriter().close();
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
private boolean allowPreview(String urlPath) {
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlPath);
|
||||
if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) {
|
||||
String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
|
||||
if (PlatformUtils.isWindows()) {
|
||||
filePath = filePath.replaceAll("/", "\\\\");
|
||||
}
|
||||
return filePath.startsWith(ConfigConstants.getFileDir()) || filePath.startsWith(ConfigConstants.getLocalPreviewDir());
|
||||
}
|
||||
return true;
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
logger.error("解析URL异常,url:{}", urlPath, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
@@ -34,11 +35,8 @@ public class TrustHostFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String url = getSourceUrl(request);
|
||||
if(url != null){
|
||||
url = new String(Base64Utils.decodeFromString(url), StandardCharsets.UTF_8);
|
||||
}
|
||||
String host = getHost(url);
|
||||
String url = WebUtils.getSourceUrl(request);
|
||||
String host = WebUtils.getHost(url);
|
||||
if (host != null &&!ConfigConstants.getTrustHostSet().isEmpty() && !ConfigConstants.getTrustHostSet().contains(host)) {
|
||||
String html = this.notTrustHost.replace("${current_host}", host);
|
||||
response.getWriter().write(html);
|
||||
@@ -52,28 +50,4 @@ public class TrustHostFilter implements Filter {
|
||||
|
||||
}
|
||||
|
||||
private String getSourceUrl(ServletRequest request) {
|
||||
String url = request.getParameter("url");
|
||||
String currentUrl = request.getParameter("currentUrl");
|
||||
String urlPath = request.getParameter("urlPath");
|
||||
if (StringUtils.isNotBlank(url)) {
|
||||
return url;
|
||||
}
|
||||
if (StringUtils.isNotBlank(currentUrl)) {
|
||||
return currentUrl;
|
||||
}
|
||||
if (StringUtils.isNotBlank(urlPath)) {
|
||||
return urlPath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getHost(String urlStr) {
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
return url.getHost().toLowerCase();
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
0
server/src/main/resources/static/favicon.ico
Normal file
6
server/src/main/resources/static/js/bootbox.min.js
vendored
Normal file
@@ -19,8 +19,12 @@ function checkImgs() {
|
||||
}
|
||||
|
||||
function loadImg(el) {
|
||||
var source = el.getAttribute("data-src");
|
||||
el.src = source;
|
||||
var loaded = el.getAttribute("loaded");
|
||||
if (!Boolean(loaded)) {
|
||||
var source = el.getAttribute("data-src");
|
||||
el.setAttribute("loaded", true);
|
||||
el.src = source;
|
||||
}
|
||||
}
|
||||
// var mustRun = 500
|
||||
// function throttle(fn, mustRun) {
|
||||
|
||||
309
server/src/main/resources/static/pdfjs/build/pdf.sandbox.js
Normal file
114945
server/src/main/resources/static/pdfjs/build/pdf.worker.js
vendored
@@ -12,14 +12,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-disable no-var */
|
||||
|
||||
"use strict";
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var FontInspector = (function FontInspectorClosure() {
|
||||
var fonts;
|
||||
var active = false;
|
||||
var fontAttribute = "data-font-name";
|
||||
let fonts;
|
||||
let active = false;
|
||||
const fontAttribute = "data-font-name";
|
||||
function removeSelection() {
|
||||
const divs = document.querySelectorAll(`span[${fontAttribute}]`);
|
||||
for (const div of divs) {
|
||||
@@ -47,10 +47,10 @@ var FontInspector = (function FontInspectorClosure() {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
var fontName = e.target.dataset.fontName;
|
||||
var selects = document.getElementsByTagName("input");
|
||||
for (var i = 0; i < selects.length; ++i) {
|
||||
var select = selects[i];
|
||||
const fontName = e.target.dataset.fontName;
|
||||
const selects = document.getElementsByTagName("input");
|
||||
for (let i = 0; i < selects.length; ++i) {
|
||||
const select = selects[i];
|
||||
if (select.dataset.fontName !== fontName) {
|
||||
continue;
|
||||
}
|
||||
@@ -66,8 +66,8 @@ var FontInspector = (function FontInspectorClosure() {
|
||||
panel: null,
|
||||
manager: null,
|
||||
init: function init(pdfjsLib) {
|
||||
var panel = this.panel;
|
||||
var tmp = document.createElement("button");
|
||||
const panel = this.panel;
|
||||
const tmp = document.createElement("button");
|
||||
tmp.addEventListener("click", resetSelection);
|
||||
tmp.textContent = "Refresh";
|
||||
panel.appendChild(tmp);
|
||||
@@ -95,27 +95,27 @@ var FontInspector = (function FontInspectorClosure() {
|
||||
// FontInspector specific functions.
|
||||
fontAdded: function fontAdded(fontObj, url) {
|
||||
function properties(obj, list) {
|
||||
var moreInfo = document.createElement("table");
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var tr = document.createElement("tr");
|
||||
var td1 = document.createElement("td");
|
||||
const moreInfo = document.createElement("table");
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const tr = document.createElement("tr");
|
||||
const td1 = document.createElement("td");
|
||||
td1.textContent = list[i];
|
||||
tr.appendChild(td1);
|
||||
var td2 = document.createElement("td");
|
||||
const td2 = document.createElement("td");
|
||||
td2.textContent = obj[list[i]].toString();
|
||||
tr.appendChild(td2);
|
||||
moreInfo.appendChild(tr);
|
||||
}
|
||||
return moreInfo;
|
||||
}
|
||||
var moreInfo = properties(fontObj, ["name", "type"]);
|
||||
const moreInfo = properties(fontObj, ["name", "type"]);
|
||||
const fontName = fontObj.loadedName;
|
||||
var font = document.createElement("div");
|
||||
var name = document.createElement("span");
|
||||
const font = document.createElement("div");
|
||||
const name = document.createElement("span");
|
||||
name.textContent = fontName;
|
||||
var download = document.createElement("a");
|
||||
const download = document.createElement("a");
|
||||
if (url) {
|
||||
url = /url\(['"]?([^\)"']+)/.exec(url);
|
||||
url = /url\(['"]?([^)"']+)/.exec(url);
|
||||
download.href = url[1];
|
||||
} else if (fontObj.data) {
|
||||
download.href = URL.createObjectURL(
|
||||
@@ -123,17 +123,17 @@ var FontInspector = (function FontInspectorClosure() {
|
||||
);
|
||||
}
|
||||
download.textContent = "Download";
|
||||
var logIt = document.createElement("a");
|
||||
const logIt = document.createElement("a");
|
||||
logIt.href = "";
|
||||
logIt.textContent = "Log";
|
||||
logIt.addEventListener("click", function(event) {
|
||||
logIt.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
console.log(fontObj);
|
||||
});
|
||||
const select = document.createElement("input");
|
||||
select.setAttribute("type", "checkbox");
|
||||
select.dataset.fontName = fontName;
|
||||
select.addEventListener("click", function() {
|
||||
select.addEventListener("click", function () {
|
||||
selectFont(fontName, select.checked);
|
||||
});
|
||||
font.appendChild(select);
|
||||
@@ -155,15 +155,17 @@ var FontInspector = (function FontInspectorClosure() {
|
||||
};
|
||||
})();
|
||||
|
||||
var opMap;
|
||||
let opMap;
|
||||
|
||||
// Manages all the page steppers.
|
||||
//
|
||||
// eslint-disable-next-line no-var
|
||||
var StepperManager = (function StepperManagerClosure() {
|
||||
var steppers = [];
|
||||
var stepperDiv = null;
|
||||
var stepperControls = null;
|
||||
var stepperChooser = null;
|
||||
var breakPoints = Object.create(null);
|
||||
let steppers = [];
|
||||
let stepperDiv = null;
|
||||
let stepperControls = null;
|
||||
let stepperChooser = null;
|
||||
let breakPoints = Object.create(null);
|
||||
return {
|
||||
// Properties/functions needed by PDFBug.
|
||||
id: "Stepper",
|
||||
@@ -171,10 +173,10 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
panel: null,
|
||||
manager: null,
|
||||
init: function init(pdfjsLib) {
|
||||
var self = this;
|
||||
const self = this;
|
||||
stepperControls = document.createElement("div");
|
||||
stepperChooser = document.createElement("select");
|
||||
stepperChooser.addEventListener("change", function(event) {
|
||||
stepperChooser.addEventListener("change", function (event) {
|
||||
self.selectStepper(this.value);
|
||||
});
|
||||
stepperControls.appendChild(stepperChooser);
|
||||
@@ -186,7 +188,7 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
}
|
||||
|
||||
opMap = Object.create(null);
|
||||
for (var key in pdfjsLib.OPS) {
|
||||
for (const key in pdfjsLib.OPS) {
|
||||
opMap[pdfjsLib.OPS[key]] = key;
|
||||
}
|
||||
},
|
||||
@@ -199,17 +201,17 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
active: false,
|
||||
// Stepper specific functions.
|
||||
create: function create(pageIndex) {
|
||||
var debug = document.createElement("div");
|
||||
const debug = document.createElement("div");
|
||||
debug.id = "stepper" + pageIndex;
|
||||
debug.setAttribute("hidden", true);
|
||||
debug.hidden = true;
|
||||
debug.className = "stepper";
|
||||
stepperDiv.appendChild(debug);
|
||||
var b = document.createElement("option");
|
||||
const b = document.createElement("option");
|
||||
b.textContent = "Page " + (pageIndex + 1);
|
||||
b.value = pageIndex;
|
||||
stepperChooser.appendChild(b);
|
||||
var initBreakPoints = breakPoints[pageIndex] || [];
|
||||
var stepper = new Stepper(debug, pageIndex, initBreakPoints);
|
||||
const initBreakPoints = breakPoints[pageIndex] || [];
|
||||
const stepper = new Stepper(debug, pageIndex, initBreakPoints);
|
||||
steppers.push(stepper);
|
||||
if (steppers.length === 1) {
|
||||
this.selectStepper(pageIndex, false);
|
||||
@@ -217,22 +219,18 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
return stepper;
|
||||
},
|
||||
selectStepper: function selectStepper(pageIndex, selectPanel) {
|
||||
var i;
|
||||
pageIndex = pageIndex | 0;
|
||||
let i;
|
||||
pageIndex |= 0;
|
||||
if (selectPanel) {
|
||||
this.manager.selectPanel(this);
|
||||
}
|
||||
for (i = 0; i < steppers.length; ++i) {
|
||||
var stepper = steppers[i];
|
||||
if (stepper.pageIndex === pageIndex) {
|
||||
stepper.panel.removeAttribute("hidden");
|
||||
} else {
|
||||
stepper.panel.setAttribute("hidden", true);
|
||||
}
|
||||
const stepper = steppers[i];
|
||||
stepper.panel.hidden = stepper.pageIndex !== pageIndex;
|
||||
}
|
||||
var options = stepperChooser.options;
|
||||
const options = stepperChooser.options;
|
||||
for (i = 0; i < options.length; ++i) {
|
||||
var option = options[i];
|
||||
const option = options[i];
|
||||
option.selected = (option.value | 0) === pageIndex;
|
||||
}
|
||||
},
|
||||
@@ -243,11 +241,11 @@ var StepperManager = (function StepperManagerClosure() {
|
||||
};
|
||||
})();
|
||||
|
||||
// The stepper for each page's IRQueue.
|
||||
var Stepper = (function StepperClosure() {
|
||||
// The stepper for each page's operatorList.
|
||||
const Stepper = (function StepperClosure() {
|
||||
// Shorter way to create element and optionally set textContent.
|
||||
function c(tag, textContent) {
|
||||
var d = document.createElement(tag);
|
||||
const d = document.createElement(tag);
|
||||
if (textContent) {
|
||||
d.textContent = textContent;
|
||||
}
|
||||
@@ -256,7 +254,7 @@ var Stepper = (function StepperClosure() {
|
||||
|
||||
function simplifyArgs(args) {
|
||||
if (typeof args === "string") {
|
||||
var MAX_STRING_LENGTH = 75;
|
||||
const MAX_STRING_LENGTH = 75;
|
||||
return args.length <= MAX_STRING_LENGTH
|
||||
? args
|
||||
: args.substring(0, MAX_STRING_LENGTH) + "...";
|
||||
@@ -266,10 +264,9 @@ var Stepper = (function StepperClosure() {
|
||||
}
|
||||
if ("length" in args) {
|
||||
// array
|
||||
var simpleArgs = [],
|
||||
i,
|
||||
ii;
|
||||
var MAX_ITEMS = 10;
|
||||
const MAX_ITEMS = 10,
|
||||
simpleArgs = [];
|
||||
let i, ii;
|
||||
for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) {
|
||||
simpleArgs.push(simplifyArgs(args[i]));
|
||||
}
|
||||
@@ -278,30 +275,32 @@ var Stepper = (function StepperClosure() {
|
||||
}
|
||||
return simpleArgs;
|
||||
}
|
||||
var simpleObj = {};
|
||||
for (var key in args) {
|
||||
const simpleObj = {};
|
||||
for (const key in args) {
|
||||
simpleObj[key] = simplifyArgs(args[key]);
|
||||
}
|
||||
return simpleObj;
|
||||
}
|
||||
|
||||
function Stepper(panel, pageIndex, initialBreakPoints) {
|
||||
this.panel = panel;
|
||||
this.breakPoint = 0;
|
||||
this.nextBreakPoint = null;
|
||||
this.pageIndex = pageIndex;
|
||||
this.breakPoints = initialBreakPoints;
|
||||
this.currentIdx = -1;
|
||||
this.operatorListIdx = 0;
|
||||
}
|
||||
Stepper.prototype = {
|
||||
init: function init(operatorList) {
|
||||
var panel = this.panel;
|
||||
var content = c("div", "c=continue, s=step");
|
||||
var table = c("table");
|
||||
// eslint-disable-next-line no-shadow
|
||||
class Stepper {
|
||||
constructor(panel, pageIndex, initialBreakPoints) {
|
||||
this.panel = panel;
|
||||
this.breakPoint = 0;
|
||||
this.nextBreakPoint = null;
|
||||
this.pageIndex = pageIndex;
|
||||
this.breakPoints = initialBreakPoints;
|
||||
this.currentIdx = -1;
|
||||
this.operatorListIdx = 0;
|
||||
}
|
||||
|
||||
init(operatorList) {
|
||||
const panel = this.panel;
|
||||
const content = c("div", "c=continue, s=step");
|
||||
const table = c("table");
|
||||
content.appendChild(table);
|
||||
table.cellSpacing = 0;
|
||||
var headerRow = c("tr");
|
||||
const headerRow = c("tr");
|
||||
table.appendChild(headerRow);
|
||||
headerRow.appendChild(c("th", "Break"));
|
||||
headerRow.appendChild(c("th", "Idx"));
|
||||
@@ -310,12 +309,13 @@ var Stepper = (function StepperClosure() {
|
||||
panel.appendChild(content);
|
||||
this.table = table;
|
||||
this.updateOperatorList(operatorList);
|
||||
},
|
||||
updateOperatorList: function updateOperatorList(operatorList) {
|
||||
var self = this;
|
||||
}
|
||||
|
||||
updateOperatorList(operatorList) {
|
||||
const self = this;
|
||||
|
||||
function cboxOnClick() {
|
||||
var x = +this.dataset.idx;
|
||||
const x = +this.dataset.idx;
|
||||
if (this.checked) {
|
||||
self.breakPoints.push(x);
|
||||
} else {
|
||||
@@ -324,26 +324,26 @@ var Stepper = (function StepperClosure() {
|
||||
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
|
||||
}
|
||||
|
||||
var MAX_OPERATORS_COUNT = 15000;
|
||||
const MAX_OPERATORS_COUNT = 15000;
|
||||
if (this.operatorListIdx > MAX_OPERATORS_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chunk = document.createDocumentFragment();
|
||||
var operatorsToDisplay = Math.min(
|
||||
const chunk = document.createDocumentFragment();
|
||||
const operatorsToDisplay = Math.min(
|
||||
MAX_OPERATORS_COUNT,
|
||||
operatorList.fnArray.length
|
||||
);
|
||||
for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) {
|
||||
var line = c("tr");
|
||||
for (let i = this.operatorListIdx; i < operatorsToDisplay; i++) {
|
||||
const line = c("tr");
|
||||
line.className = "line";
|
||||
line.dataset.idx = i;
|
||||
chunk.appendChild(line);
|
||||
var checked = this.breakPoints.includes(i);
|
||||
var args = operatorList.argsArray[i] || [];
|
||||
const checked = this.breakPoints.includes(i);
|
||||
const args = operatorList.argsArray[i] || [];
|
||||
|
||||
var breakCell = c("td");
|
||||
var cbox = c("input");
|
||||
const breakCell = c("td");
|
||||
const cbox = c("input");
|
||||
cbox.type = "checkbox";
|
||||
cbox.className = "points";
|
||||
cbox.checked = checked;
|
||||
@@ -353,81 +353,92 @@ var Stepper = (function StepperClosure() {
|
||||
breakCell.appendChild(cbox);
|
||||
line.appendChild(breakCell);
|
||||
line.appendChild(c("td", i.toString()));
|
||||
var fn = opMap[operatorList.fnArray[i]];
|
||||
var decArgs = args;
|
||||
const fn = opMap[operatorList.fnArray[i]];
|
||||
let decArgs = args;
|
||||
if (fn === "showText") {
|
||||
var glyphs = args[0];
|
||||
var newArgs = [];
|
||||
var str = [];
|
||||
for (var j = 0; j < glyphs.length; j++) {
|
||||
var glyph = glyphs[j];
|
||||
const glyphs = args[0];
|
||||
const charCodeRow = c("tr");
|
||||
const fontCharRow = c("tr");
|
||||
const unicodeRow = c("tr");
|
||||
for (let j = 0; j < glyphs.length; j++) {
|
||||
const glyph = glyphs[j];
|
||||
if (typeof glyph === "object" && glyph !== null) {
|
||||
str.push(glyph.fontChar);
|
||||
charCodeRow.appendChild(c("td", glyph.originalCharCode));
|
||||
fontCharRow.appendChild(c("td", glyph.fontChar));
|
||||
unicodeRow.appendChild(c("td", glyph.unicode));
|
||||
} else {
|
||||
if (str.length > 0) {
|
||||
newArgs.push(str.join(""));
|
||||
str = [];
|
||||
}
|
||||
newArgs.push(glyph); // null or number
|
||||
// null or number
|
||||
const advanceEl = c("td", glyph);
|
||||
advanceEl.classList.add("advance");
|
||||
charCodeRow.appendChild(advanceEl);
|
||||
fontCharRow.appendChild(c("td"));
|
||||
unicodeRow.appendChild(c("td"));
|
||||
}
|
||||
}
|
||||
if (str.length > 0) {
|
||||
newArgs.push(str.join(""));
|
||||
}
|
||||
decArgs = [newArgs];
|
||||
decArgs = c("td");
|
||||
const table = c("table");
|
||||
table.classList.add("showText");
|
||||
decArgs.appendChild(table);
|
||||
table.appendChild(charCodeRow);
|
||||
table.appendChild(fontCharRow);
|
||||
table.appendChild(unicodeRow);
|
||||
}
|
||||
line.appendChild(c("td", fn));
|
||||
line.appendChild(c("td", JSON.stringify(simplifyArgs(decArgs))));
|
||||
if (decArgs instanceof HTMLElement) {
|
||||
line.appendChild(decArgs);
|
||||
} else {
|
||||
line.appendChild(c("td", JSON.stringify(simplifyArgs(decArgs))));
|
||||
}
|
||||
}
|
||||
if (operatorsToDisplay < operatorList.fnArray.length) {
|
||||
line = c("tr");
|
||||
var lastCell = c("td", "...");
|
||||
const lastCell = c("td", "...");
|
||||
lastCell.colspan = 4;
|
||||
chunk.appendChild(lastCell);
|
||||
}
|
||||
this.operatorListIdx = operatorList.fnArray.length;
|
||||
this.table.appendChild(chunk);
|
||||
},
|
||||
getNextBreakPoint: function getNextBreakPoint() {
|
||||
this.breakPoints.sort(function(a, b) {
|
||||
}
|
||||
|
||||
getNextBreakPoint() {
|
||||
this.breakPoints.sort(function (a, b) {
|
||||
return a - b;
|
||||
});
|
||||
for (var i = 0; i < this.breakPoints.length; i++) {
|
||||
for (let i = 0; i < this.breakPoints.length; i++) {
|
||||
if (this.breakPoints[i] > this.currentIdx) {
|
||||
return this.breakPoints[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
breakIt: function breakIt(idx, callback) {
|
||||
}
|
||||
|
||||
breakIt(idx, callback) {
|
||||
StepperManager.selectStepper(this.pageIndex, true);
|
||||
var self = this;
|
||||
var dom = document;
|
||||
self.currentIdx = idx;
|
||||
var listener = function(e) {
|
||||
switch (e.keyCode) {
|
||||
this.currentIdx = idx;
|
||||
|
||||
const listener = evt => {
|
||||
switch (evt.keyCode) {
|
||||
case 83: // step
|
||||
dom.removeEventListener("keydown", listener);
|
||||
self.nextBreakPoint = self.currentIdx + 1;
|
||||
self.goTo(-1);
|
||||
document.removeEventListener("keydown", listener);
|
||||
this.nextBreakPoint = this.currentIdx + 1;
|
||||
this.goTo(-1);
|
||||
callback();
|
||||
break;
|
||||
case 67: // continue
|
||||
dom.removeEventListener("keydown", listener);
|
||||
var breakPoint = self.getNextBreakPoint();
|
||||
self.nextBreakPoint = breakPoint;
|
||||
self.goTo(-1);
|
||||
document.removeEventListener("keydown", listener);
|
||||
this.nextBreakPoint = this.getNextBreakPoint();
|
||||
this.goTo(-1);
|
||||
callback();
|
||||
break;
|
||||
}
|
||||
};
|
||||
dom.addEventListener("keydown", listener);
|
||||
self.goTo(idx);
|
||||
},
|
||||
goTo: function goTo(idx) {
|
||||
var allRows = this.panel.getElementsByClassName("line");
|
||||
for (var x = 0, xx = allRows.length; x < xx; ++x) {
|
||||
var row = allRows[x];
|
||||
document.addEventListener("keydown", listener);
|
||||
this.goTo(idx);
|
||||
}
|
||||
|
||||
goTo(idx) {
|
||||
const allRows = this.panel.getElementsByClassName("line");
|
||||
for (let x = 0, xx = allRows.length; x < xx; ++x) {
|
||||
const row = allRows[x];
|
||||
if ((row.dataset.idx | 0) === idx) {
|
||||
row.style.backgroundColor = "rgb(251,250,207)";
|
||||
row.scrollIntoView();
|
||||
@@ -435,20 +446,21 @@ var Stepper = (function StepperClosure() {
|
||||
row.style.backgroundColor = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return Stepper;
|
||||
})();
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var Stats = (function Stats() {
|
||||
var stats = [];
|
||||
let stats = [];
|
||||
function clear(node) {
|
||||
while (node.hasChildNodes()) {
|
||||
node.removeChild(node.lastChild);
|
||||
}
|
||||
}
|
||||
function getStatIndex(pageNumber) {
|
||||
for (var i = 0, ii = stats.length; i < ii; ++i) {
|
||||
for (let i = 0, ii = stats.length; i < ii; ++i) {
|
||||
if (stats[i].pageNumber === pageNumber) {
|
||||
return i;
|
||||
}
|
||||
@@ -469,27 +481,27 @@ var Stats = (function Stats() {
|
||||
if (!stat) {
|
||||
return;
|
||||
}
|
||||
var statsIndex = getStatIndex(pageNumber);
|
||||
const statsIndex = getStatIndex(pageNumber);
|
||||
if (statsIndex !== false) {
|
||||
const b = stats[statsIndex];
|
||||
this.panel.removeChild(b.div);
|
||||
stats.splice(statsIndex, 1);
|
||||
}
|
||||
var wrapper = document.createElement("div");
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "stats";
|
||||
var title = document.createElement("div");
|
||||
const title = document.createElement("div");
|
||||
title.className = "title";
|
||||
title.textContent = "Page: " + pageNumber;
|
||||
var statsDiv = document.createElement("div");
|
||||
const statsDiv = document.createElement("div");
|
||||
statsDiv.textContent = stat.toString();
|
||||
wrapper.appendChild(title);
|
||||
wrapper.appendChild(statsDiv);
|
||||
stats.push({ pageNumber, div: wrapper });
|
||||
stats.sort(function(a, b) {
|
||||
stats.sort(function (a, b) {
|
||||
return a.pageNumber - b.pageNumber;
|
||||
});
|
||||
clear(this.panel);
|
||||
for (var i = 0, ii = stats.length; i < ii; ++i) {
|
||||
for (let i = 0, ii = stats.length; i < ii; ++i) {
|
||||
this.panel.appendChild(stats[i].div);
|
||||
}
|
||||
},
|
||||
@@ -502,30 +514,27 @@ var Stats = (function Stats() {
|
||||
|
||||
// Manages all the debugging tools.
|
||||
window.PDFBug = (function PDFBugClosure() {
|
||||
var panelWidth = 300;
|
||||
var buttons = [];
|
||||
var activePanel = null;
|
||||
const panelWidth = 300;
|
||||
const buttons = [];
|
||||
let activePanel = null;
|
||||
|
||||
return {
|
||||
tools: [FontInspector, StepperManager, Stats],
|
||||
enable(ids) {
|
||||
var all = false,
|
||||
tools = this.tools;
|
||||
if (ids.length === 1 && ids[0] === "all") {
|
||||
all = true;
|
||||
}
|
||||
for (var i = 0; i < tools.length; ++i) {
|
||||
var tool = tools[i];
|
||||
const all = ids.length === 1 && ids[0] === "all";
|
||||
const tools = this.tools;
|
||||
for (let i = 0; i < tools.length; ++i) {
|
||||
const tool = tools[i];
|
||||
if (all || ids.includes(tool.id)) {
|
||||
tool.enabled = true;
|
||||
}
|
||||
}
|
||||
if (!all) {
|
||||
// Sort the tools by the order they are enabled.
|
||||
tools.sort(function(a, b) {
|
||||
var indexA = ids.indexOf(a.id);
|
||||
tools.sort(function (a, b) {
|
||||
let indexA = ids.indexOf(a.id);
|
||||
indexA = indexA < 0 ? tools.length : indexA;
|
||||
var indexB = ids.indexOf(b.id);
|
||||
let indexB = ids.indexOf(b.id);
|
||||
indexB = indexB < 0 ? tools.length : indexB;
|
||||
return indexA - indexB;
|
||||
});
|
||||
@@ -541,14 +550,14 @@ window.PDFBug = (function PDFBugClosure() {
|
||||
* Panel
|
||||
* ...
|
||||
*/
|
||||
var ui = document.createElement("div");
|
||||
const ui = document.createElement("div");
|
||||
ui.id = "PDFBug";
|
||||
|
||||
var controls = document.createElement("div");
|
||||
const controls = document.createElement("div");
|
||||
controls.setAttribute("class", "controls");
|
||||
ui.appendChild(controls);
|
||||
|
||||
var panels = document.createElement("div");
|
||||
const panels = document.createElement("div");
|
||||
panels.setAttribute("class", "panels");
|
||||
ui.appendChild(panels);
|
||||
|
||||
@@ -556,17 +565,17 @@ window.PDFBug = (function PDFBugClosure() {
|
||||
container.style.right = panelWidth + "px";
|
||||
|
||||
// Initialize all the debugging tools.
|
||||
var tools = this.tools;
|
||||
var self = this;
|
||||
for (var i = 0; i < tools.length; ++i) {
|
||||
var tool = tools[i];
|
||||
var panel = document.createElement("div");
|
||||
var panelButton = document.createElement("button");
|
||||
const tools = this.tools;
|
||||
const self = this;
|
||||
for (let i = 0; i < tools.length; ++i) {
|
||||
const tool = tools[i];
|
||||
const panel = document.createElement("div");
|
||||
const panelButton = document.createElement("button");
|
||||
panelButton.textContent = tool.name;
|
||||
panelButton.addEventListener(
|
||||
"click",
|
||||
(function(selected) {
|
||||
return function(event) {
|
||||
(function (selected) {
|
||||
return function (event) {
|
||||
event.preventDefault();
|
||||
self.selectPanel(selected);
|
||||
};
|
||||
@@ -592,7 +601,7 @@ window.PDFBug = (function PDFBugClosure() {
|
||||
this.selectPanel(0);
|
||||
},
|
||||
cleanup() {
|
||||
for (var i = 0, ii = this.tools.length; i < ii; i++) {
|
||||
for (let i = 0, ii = this.tools.length; i < ii; i++) {
|
||||
if (this.tools[i].enabled) {
|
||||
this.tools[i].cleanup();
|
||||
}
|
||||
@@ -606,17 +615,12 @@ window.PDFBug = (function PDFBugClosure() {
|
||||
return;
|
||||
}
|
||||
activePanel = index;
|
||||
var tools = this.tools;
|
||||
for (var j = 0; j < tools.length; ++j) {
|
||||
if (j === index) {
|
||||
buttons[j].setAttribute("class", "active");
|
||||
tools[j].active = true;
|
||||
tools[j].panel.removeAttribute("hidden");
|
||||
} else {
|
||||
buttons[j].setAttribute("class", "");
|
||||
tools[j].active = false;
|
||||
tools[j].panel.setAttribute("hidden", "true");
|
||||
}
|
||||
const tools = this.tools;
|
||||
for (let j = 0; j < tools.length; ++j) {
|
||||
const isActive = j === index;
|
||||
buttons[j].classList.toggle("active", isActive);
|
||||
tools[j].active = isActive;
|
||||
tools[j].panel.hidden = !isActive;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 193 B |
@@ -0,0 +1,4 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8 12a1 1 0 0 1-.707-.293l-5-5a1 1 0 0 1 1.414-1.414L8 9.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-5 5A1 1 0 0 1 8 12z"></path></svg>
|
||||
|
After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 193 B |
|
Before Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 199 B |
@@ -0,0 +1,4 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M13 11a1 1 0 0 1-.707-.293L8 6.414l-4.293 4.293a1 1 0 0 1-1.414-1.414l5-5a1 1 0 0 1 1.414 0l5 5A1 1 0 0 1 13 11z"></path></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
|
Before Width: | Height: | Size: 304 B |
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"
|
||||
fill="rgba(255,255,255,1)" style="animation:spinLoadingIcon 1s steps(12,end)
|
||||
infinite"><style>@keyframes
|
||||
spinLoadingIcon{to{transform:rotate(360deg)}}</style><path
|
||||
d="M7 3V1s0-1 1-1 1 1 1 1v2s0 1-1 1-1-1-1-1z"/><path d="M4.63
|
||||
4.1l-1-1.73S3.13 1.5 4 1c.87-.5 1.37.37 1.37.37l1 1.73s.5.87-.37
|
||||
1.37c-.87.57-1.37-.37-1.37-.37z" fill-opacity=".93"/><path
|
||||
d="M3.1 6.37l-1.73-1S.5 4.87 1 4c.5-.87 1.37-.37 1.37-.37l1.73 1s.87.5.37
|
||||
1.37c-.5.87-1.37.37-1.37.37z" fill-opacity=".86"/><path d="M3
|
||||
9H1S0 9 0 8s1-1 1-1h2s1 0 1 1-1 1-1 1z" fill-opacity=".79"/><path d="M4.1 11.37l-1.73 1S1.5 12.87 1
|
||||
12c-.5-.87.37-1.37.37-1.37l1.73-1s.87-.5 1.37.37c.5.87-.37 1.37-.37 1.37z"
|
||||
fill-opacity=".72"/><path d="M3.63 13.56l1-1.73s.5-.87
|
||||
1.37-.37c.87.5.37 1.37.37 1.37l-1 1.73s-.5.87-1.37.37c-.87-.5-.37-1.37-.37-1.37z"
|
||||
fill-opacity=".65"/><path d="M7 15v-2s0-1 1-1 1 1 1 1v2s0 1-1
|
||||
1-1-1-1-1z" fill-opacity=".58"/><path d="M10.63
|
||||
14.56l-1-1.73s-.5-.87.37-1.37c.87-.5 1.37.37 1.37.37l1 1.73s.5.87-.37
|
||||
1.37c-.87.5-1.37-.37-1.37-.37z" fill-opacity=".51"/><path
|
||||
d="M13.56 12.37l-1.73-1s-.87-.5-.37-1.37c.5-.87 1.37-.37 1.37-.37l1.73 1s.87.5.37
|
||||
1.37c-.5.87-1.37.37-1.37.37z" fill-opacity=".44"/><path d="M15
|
||||
9h-2s-1 0-1-1 1-1 1-1h2s1 0 1 1-1 1-1 1z" fill-opacity=".37"/><path d="M14.56 5.37l-1.73
|
||||
1s-.87.5-1.37-.37c-.5-.87.37-1.37.37-1.37l1.73-1s.87-.5 1.37.37c.5.87-.37 1.37-.37
|
||||
1.37z" fill-opacity=".3"/><path d="M9.64 3.1l.98-1.66s.5-.874
|
||||
1.37-.37c.87.5.37 1.37.37 1.37l-1 1.73s-.5.87-1.37.37c-.87-.5-.37-1.37-.37-1.37z"
|
||||
fill-opacity=".23"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" style="animation:spinLoadingIcon 1s steps(12,end) infinite"><style>@keyframes spinLoadingIcon{to{transform:rotate(360deg)}}</style><path d="M7 3V1s0-1 1-1 1 1 1 1v2s0 1-1 1-1-1-1-1z"/><path d="M4.63 4.1l-1-1.73S3.13 1.5 4 1c.87-.5 1.37.37 1.37.37l1 1.73s.5.87-.37 1.37c-.87.57-1.37-.37-1.37-.37z" fill-opacity=".93"/><path d="M3.1 6.37l-1.73-1S.5 4.87 1 4c.5-.87 1.37-.37 1.37-.37l1.73 1s.87.5.37 1.37c-.5.87-1.37.37-1.37.37z" fill-opacity=".86"/><path d="M3 9H1S0 9 0 8s1-1 1-1h2s1 0 1 1-1 1-1 1z" fill-opacity=".79"/><path d="M4.1 11.37l-1.73 1S1.5 12.87 1 12c-.5-.87.37-1.37.37-1.37l1.73-1s.87-.5 1.37.37c.5.87-.37 1.37-.37 1.37z" fill-opacity=".72"/><path d="M3.63 13.56l1-1.73s.5-.87 1.37-.37c.87.5.37 1.37.37 1.37l-1 1.73s-.5.87-1.37.37c-.87-.5-.37-1.37-.37-1.37z" fill-opacity=".65"/><path d="M7 15v-2s0-1 1-1 1 1 1 1v2s0 1-1 1-1-1-1-1z" fill-opacity=".58"/><path d="M10.63 14.56l-1-1.73s-.5-.87.37-1.37c.87-.5 1.37.37 1.37.37l1 1.73s.5.87-.37 1.37c-.87.5-1.37-.37-1.37-.37z" fill-opacity=".51"/><path d="M13.56 12.37l-1.73-1s-.87-.5-.37-1.37c.5-.87 1.37-.37 1.37-.37l1.73 1s.87.5.37 1.37c-.5.87-1.37.37-1.37.37z" fill-opacity=".44"/><path d="M15 9h-2s-1 0-1-1 1-1 1-1h2s1 0 1 1-1 1-1 1z" fill-opacity=".37"/><path d="M14.56 5.37l-1.73 1s-.87.5-1.37-.37c-.5-.87.37-1.37.37-1.37l1.73-1s.87-.5 1.37.37c.5.87-.37 1.37-.37 1.37z" fill-opacity=".3"/><path d="M9.64 3.1l.98-1.66s.5-.874 1.37-.37c.87.5.37 1.37.37 1.37l-1 1.73s-.5.87-1.37.37c-.87-.5-.37-1.37-.37-1.37z" fill-opacity=".23"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 403 B |
@@ -0,0 +1,15 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16
|
||||
16">
|
||||
<path
|
||||
d="M8 16a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8zM8 2a6 6 0 1 0 6 6 6.006 6.006 0 0 0-6-6z">
|
||||
</path>
|
||||
<path
|
||||
d="M8 7a1 1 0 0 0-1 1v3a1 1 0 0 0 2 0V8a1 1 0 0 0-1-1z">
|
||||
</path>
|
||||
<circle
|
||||
cx="8" cy="5" r="1.188">
|
||||
</circle>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 530 B |
|
Before Width: | Height: | Size: 933 B |
|
Before Width: | Height: | Size: 179 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13 13c-.3 0-.5-.1-.7-.3L8 8.4l-4.3 4.3c-.9.9-2.3-.5-1.4-1.4l5-5c.4-.4 1-.4 1.4 0l5 5c.6.6.2 1.7-.7 1.7zm0-11H3C1.7 2 1.7 4 3 4h10c1.3 0 1.3-2 0-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 266 B |
|
Before Width: | Height: | Size: 301 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M15 3.7V13c0 1.5-1.53 3-3 3H7.13c-.72 0-1.63-.5-2.13-1l-5-5s.84-1 .87-1c.13-.1.33-.2.53-.2.1 0 .3.1.4.2L4 10.6V2.7c0-.6.4-1 1-1s1 .4 1 1v4.6h1V1c0-.6.4-1 1-1s1 .4 1 1v6.3h1V1.7c0-.6.4-1 1-1s1 .4 1 1v5.7h1V3.7c0-.6.4-1 1-1s1 .4 1 1z"/></svg>
|
||||
|
After Width: | Height: | Size: 312 B |
|
Before Width: | Height: | Size: 583 B |
|
Before Width: | Height: | Size: 175 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M8 10c-.3 0-.5-.1-.7-.3l-5-5c-.9-.9.5-2.3 1.4-1.4L8 7.6l4.3-4.3c.9-.9 2.3.5 1.4 1.4l-5 5c-.2.2-.4.3-.7.3zm5 2H3c-1.3 0-1.3 2 0 2h10c1.3 0 1.3-2 0-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 276 B |
|
Before Width: | Height: | Size: 360 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M1 1a1 1 0 011 1v2.4A7 7 0 118 15a7 7 0 01-4.9-2 1 1 0 011.4-1.5 5 5 0 10-1-5.5H6a1 1 0 010 2H1a1 1 0 01-1-1V2a1 1 0 011-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 731 B |
|
Before Width: | Height: | Size: 359 B |
@@ -0,0 +1,4 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M15 1a1 1 0 0 0-1 1v2.418A6.995 6.995 0 1 0 8 15a6.954 6.954 0 0 0 4.95-2.05 1 1 0 0 0-1.414-1.414A5.019 5.019 0 1 1 12.549 6H10a1 1 0 0 0 0 2h5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"></path></svg>
|
||||
|
After Width: | Height: | Size: 494 B |
|
Before Width: | Height: | Size: 714 B |
|
Before Width: | Height: | Size: 218 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M0 4h1.5c1 0 1.5.5 1.5 1.5v5c0 1-.5 1.5-1.5 1.5H0zM9.5 4c1 0 1.5.5 1.5 1.5v5c0 1-.5 1.5-1.5 1.5h-3c-1 0-1.5-.5-1.5-1.5v-5C5 4.5 5.5 4 6.5 4zM16 4h-1.5c-1 0-1.5.5-1.5 1.5v5c0 1 .5 1.5 1.5 1.5H16z"/></svg>
|
||||
|
After Width: | Height: | Size: 275 B |
|
Before Width: | Height: | Size: 332 B |