Compare commits

..

1 Commits

Author SHA1 Message Date
kl
6e8bf0d359 更新index接入演示界面UI风格 2020-12-28 13:36:08 +08:00
3661 changed files with 874 additions and 4191 deletions

View File

@ -28,5 +28,5 @@ 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-3.5/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-3.5/config/application.properties","-jar","/opt/kkFileView-3.5/bin/kkFileView-3.5.jar"]
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-3.3.0/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-3.3.0/config/application.properties","-jar","/opt/kkFileView-3.3.0/bin/kkFileView-3.3.0.jar"]

View File

@ -2,14 +2,14 @@
此项目为文件文档在线预览项目解决方案对标业内付费产品有[永中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,图片等等
### 项目特性
1. 支持 office, pdf, cad 等办公文档
1. 支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本
1. 支持 zip, rar, jar, tar, gzip 等压缩包
1. 支持 jpg, jpeg, png, gif, tif, tiff 等图片预览翻转缩放镜像
1. 使用 spring-boot 开发预览服务搭建部署非常简便
1. rest 接口提供服务语言平台特性(java,php,python,go,php....)都支持应用接入简单方便
1. 支持officepdf, cad等办公文档
1. 支持txt,java,php,py,md,js,css等所有纯文本
1. 支持zip,rar,jar,tar,gzip等压缩包
1. 支持jpgjpegpnggif等图片预览翻转缩放镜像
1. 使用spring boot开发预览服务搭建部署非常简便
1. rest接口提供服务跨平台特性(java,php,python,go,php....)都支持应用接入简单方便
1. 抽象预览服务接口方便二次开发非常方便添加其他类型文件预览支持
1. 最最重要 Apache 协议开源代码 pull 下来想干嘛就干嘛
1. 最最重要Apache协议开源代码pull下来想干嘛就干嘛
### 官网及文档
@ -26,7 +26,7 @@
1. English documenthttps://gitee.com/kekingcn/file-online-preview/blob/master/README.en.md
### 联系我们加入组织
> 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少 Google baidu 珍爱生命远离无效的交流沟通
> 我们会用心回答解决大家在项目使用中的问题也请大家在提问前至少Google或baidu珍爱生命远离无效的交流沟通
![](./doc/KK开源技术交流2群群聊二维码.png)
@ -99,40 +99,16 @@ pdf预览模式预览效果如下
- jodconverter
> 依赖外部环境
- redis (可选默认不用)
- OpenOffice 或者 LibreOffice( Windows 下已内置Linux 脚本启动模式会自动安装Mac OS 下需要手动安装)
- OpenOffice或者LibreOffice(Windows下已内置Linux会自动安装Mac OS下需要手动安装)
1. 第一步pull 项目 https://github.com/kekingcn/file-online-preview.git
1. 第一步pull项目https://github.com/kekingcn/file-online-preview.git
3. 第二步运行 ServerMain main 方法服务启动后访问 http://localhost:8012/
3. 第二步运行FilePreviewApplication的main方法服务启动后访问http://localhost:8012/
会看到如下界面代表服务启动成功
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### 历史更新记录
> 2021年1月28日
2020农历年最后一个版本发布主要包含了部分 UI 改进和解决了 QQ 群友 Issue 里反馈的 Bug 修复最最重要的是发个新版过个好年
1. 引入galimatias,解决不规范文件名导致文件下载异常
2. 更新index接入演示界面UI风格
3. 更新markdown文件预览UI风格
4. 更新XML文件预览UI风格调整类文本预览架构更方便扩展
5. 更新simTxT文件预览UI风格
6. 调整多图连续预览上下翻图的UI
7. 采用apache-common-io包简化所有的文件下载io操作
8. XML文件预览支持切换纯文本模式
9. 增强url base64解码失败时的提示信息
10. 修复导包错误以及图片预览 bug
11. 修复发行包运行时找不到日志目录的问题
12. 修复压缩包内多图连续预览的bug
13. 修复大小写文件类型后缀没通用匹配的问题
14. 指定Base64转码采用Apache Commons-code中的实现修复base64部分jdk版本下出现的异常
15. 修复类文本类型HTML文件预览的bug
16. 修复dwg文件预览时无法在jpg和pdf两种类型之间切换
17. escaping of dangerous characters to prevent reflected xss
18. 修复重复编码导致文档转图片预览失败的问题&编码规范
> 2020年12月27日
2020年年终大版本更新架构全面设计代码全面重构代码质量全面提升二次开发更便捷欢迎拉源码品鉴提issuepr共同建设
@ -207,13 +183,5 @@ pdf预览模式预览效果如下
1. 引入pdf.js预览doc等文件支持doc标题生成pdf预览菜单支持手机端预览
### 使用登记
如果这个项目解决了你的实际问题可在 https://gitee.com/kekingcn/file-online-preview/issues/IGSBV
如果这个项目解决了你的实际问题可在https://gitee.com/kekingcn/file-online-preview/issues/IGSBV
登记下如果节省了你的三方预览服务费用也愿意支持下的话可点击下方捐助请作者喝杯咖啡也是非常感谢
### Stars 趋势图
#### Gitee
[![Stargazers over time](https://whnb.wang/img/kekingcn/file-online-preview)](https://whnb.wang/kekingcn/file-online-preview?e=86400)
#### GitHub
[![Stargazers over time](https://starchart.cc/kekingcn/kkFileView.svg)](https://starchart.cc/kekingcn/kkFileView)

View File

@ -3,15 +3,13 @@
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>
<groupId>cn.keking</groupId>
<version>3.5</version>
</parent>
<groupId>cn.keking</groupId>
<artifactId>office-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<!-- required for org.hyperic:sigar -->

View File

@ -81,7 +81,7 @@ public class OfficeUtils {
}
if (PlatformUtils.isWindows()) {
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
String officePluginPath = ConfigUtils.getOfficePluginPath();
String homePath = ConfigUtils.getHomePath();
String programFiles = System.getenv("ProgramFiles(x86)");
if (programFiles == null) {
programFiles = System.getenv("ProgramFiles");
@ -89,7 +89,7 @@ public class OfficeUtils {
return findOfficeHome(
programFiles + File.separator + "OpenOffice 4",
programFiles + File.separator + "LibreOffice 4",
officePluginPath + File.separator + "windows-office"
homePath + File.separator + "office"
);
} else if (PlatformUtils.isMac()) {
return findOfficeHome(

View File

@ -9,7 +9,6 @@ import java.io.File;
public class ConfigUtils {
private static final String MAIN_DIRECTORY_NAME = "server";
private static final String OFFICE_PLUGIN_NAME = "office-plugin";
public static String getHomePath() {
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
@ -29,23 +28,6 @@ public class ConfigUtils {
return userDir;
}
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;
}
}
return userDir;
}
public static String getCustomizedConfigPath() {
String homePath = getHomePath();
String separator = java.io.File.separator;

View File

@ -1,5 +0,0 @@
======================================================================
OpenOffice 4.1.6 ReadMe
======================================================================
Windows 内置集成的的 OpenOffice

68
pom.xml
View File

@ -2,60 +2,36 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<groupId>cn.keking</groupId>
<artifactId>filepreview</artifactId>
<version>3.5</version>
<properties>
<java.version>1.8</java.version>
<spring.boot.version>2.4.2</spring.boot.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>
<version>3.3.0</version>
<modules>
<module>office-plugin</module>
<module>server</module>
</modules>
<packaging>pom</packaging>
<profiles>
<profile>
<id>dev</id>
<properties>
<build.exclude.resource></build.exclude.resource>
</properties>
<activation>
<!--默认激活开发环境-->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>release</id>
<properties>
<build.exclude.resource>*.properties</build.exclude.resource>
</properties>
</profile>
</profiles>
<name>file-online-preview</name>
<description>专注文件在线预览服务</description>
<url>https://github.com/kekingcn/kkFileView</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<scm>
<url>https://github.com/kekingcn/kkFileView</url>
<connection>scm:git:git://github.com/kekingcn/kkFileView.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kekingcn/kkFileView.git</developerConnection>
</scm>
<developers>
<developer>
<id>klboke</id>
<name>kl</name>
<email>g632104866@gmail.com</email>
<url>http://www.kailing.pub</url>
</developer>
<developer>
<id>gitchenjh</id>
<name>chenjinghua</name>
<email>842761733@qq.com</email>
</developer>
</developers>
<issueManagement>
<system>github</system>
<url>https://github.com/kekingcn/kkFileView/issues</url>
</issueManagement>
</project>

View File

@ -2,27 +2,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>filepreview</artifactId>
<groupId>cn.keking</groupId>
<version>3.5</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>cn.keking</groupId>
<artifactId>kkFileView</artifactId>
<version>3.3.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<!-- required for org.hyperic:sigar -->
<id>jboss-public-repository-group</id>
<url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
@ -51,7 +55,13 @@
<dependency>
<groupId>cn.keking</groupId>
<artifactId>office-plugin</artifactId>
<version>${project.version}</version>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -67,7 +77,7 @@
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
<version>3.12</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
@ -95,6 +105,11 @@
<artifactId>fr.opensagres.xdocreport.document</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- 解压(apache) -->
<dependency>
<groupId>org.apache.commons</groupId>
@ -149,7 +164,7 @@
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.16</version>
<version>1.4.15</version>
</dependency>
<dependency>
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
@ -193,7 +208,6 @@
<version>0.2.1</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@ -205,6 +219,9 @@
</resource>
<resource>
<directory>src/main/config</directory>
<excludes>
<exclude>${build.exclude.resource}</exclude>
</excludes>
<filtering>true</filtering>
</resource>
</resources>
@ -212,25 +229,16 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/dist-win32.xml</descriptor>
<descriptor>src/main/assembly/dist-linux.xml</descriptor>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>

View File

@ -35,10 +35,10 @@
<outputDirectory>${file.separator}log</outputDirectory>
</fileSet>
<fileSet>
<directory>../office-plugin/windows-office</directory>
<outputDirectory>${file.separator}windows-office</outputDirectory>
<directory>src/main/office</directory>
<outputDirectory>${file.separator}office</outputDirectory>
</fileSet>
<fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>make-assembly</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/main/bin</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>
<include>*.sh</include>
</includes>
<fileMode>755</fileMode>
<lineEnding>unix</lineEnding>
</fileSet>
<fileSet>
<directory>src/main/config</directory>
<outputDirectory>${file.separator}config</outputDirectory>
<lineEnding>unix</lineEnding>
</fileSet>
<fileSet>
<directory>src/main/log</directory>
<outputDirectory>${file.separator}log</outputDirectory>
<lineEnding>unix</lineEnding>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>make-assembly</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/main/bin</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>
<include>*.bat</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/config</directory>
<outputDirectory>${file.separator}config</outputDirectory>
</fileSet>
<fileSet>
<directory>src/main/log</directory>
<outputDirectory>${file.separator}log</outputDirectory>
</fileSet>
<fileSet>
<directory>../office-plugin/windows-office</directory>
<outputDirectory>${file.separator}windows-office</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -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-3.5.jar -> ..\log\kkFileView.log
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\config\application.properties -jar kkFileView-3.3.0.jar -> ..\log\kkFileView.log

View File

@ -29,4 +29,4 @@ 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-3.5.jar > ../log/kkFileView.log 2>&1 &
nohup java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../config/application.properties -jar kkFileView-3.3.0.jar > ../log/kkFileView.log 2>&1 &

View File

@ -1,10 +1,7 @@
#######################################不可动态配置需要重启生效#######################################
server.port = ${KK_SERVER_PORT:8012}
server.servlet.context-path= ${KK_CONTEXT_PATH:/}
server.servlet.encoding.charset = utf-8
#文件上传限制
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB
server.context-path = ${KK_CONTEXT_PATH:/}
spring.http.encoding.charset = utf8
## Freemarker 配置
spring.freemarker.template-loader-path = classpath:/web/
spring.freemarker.cache = false
@ -16,11 +13,10 @@ spring.freemarker.expose-session-attributes = true
spring.freemarker.request-context-attribute = request
spring.freemarker.suffix = .ftl
# office-plugin
## office转换服务的进程数默认开启两个进程
office.plugin.server.ports = 2001,2002
## office 转换服务 task 超时时间默认五分钟
office.plugin.task.timeout = 5m
server.tomcat.uri-encoding = UTF-8
#文件上传限制
spring.http.multipart.max-request-size=500MB
spring.http.multipart.max-file-size=500MB
#文件资源路径默认为打包根路径下的file目录下
#file.dir = D:\\kkFileview\\

View File

@ -1,8 +1,5 @@
[#ftl]
[#-- @implicitly included --]
[#-- @ftlvariable name="currentUrl" type="java.lang.String" --]
[#-- @ftlvariable name="file" type="cn.keking.model.FileAttribute" --]
[#-- @ftlvariable name="fileName" type="java.lang.String" --]
[#-- @ftlvariable name="fileTree" type="java.lang.String" --]
[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
[#-- @ftlvariable name="imgUrls" type="String" --]

View File

@ -1,33 +1,22 @@
package cn.keking;
import cn.keking.config.AppBanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.StopWatch;
@SpringBootApplication
@EnableScheduling
@ComponentScan(value = "cn.keking.*")
public class ServerMain {
private static final Logger logger = LoggerFactory.getLogger(ServerMain.class);
public static void main(String[] args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = new SpringApplicationBuilder(ServerMain.class)
.logStartupInfo(false)
.banner(new AppBanner())
.run(args);
stopWatch.stop();
Integer port = context.getBean(ServerProperties.class).getPort();
logger.info("kkFileView 服务启动完成,耗时:{}s演示页请访问: http://127.0.0.1:{} ", stopWatch.getTotalTimeSeconds(), port);
}
public static void main(String[] args) {
ServerMain.staticInitSystemProperty();
SpringApplication.run(ServerMain.class, args);
}
private static void staticInitSystemProperty(){
//pdfbox兼容低版本jdk
System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
}
}

View File

@ -1,28 +0,0 @@
package cn.keking.config;
import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
/**
* @author kl (http://kailing.pub)
* @since 2021/2/8
*/
public class AppBanner implements Banner {
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
out.println(
" _ _ ______ _ _ __ __ _ \n" +
" | | | | | ____| (_) | | \\ \\ / / (_) \n" +
" | | __ | | __ | |__ _ | | ___ \\ \\ / / _ ___ __ __\n" +
" | |/ / | |/ / | __| | | | | / _ \\ \\ \\/ / | | / _ \\ \\ \\ /\\ / /\n" +
" | < | < | | | | | | | __/ \\ / | | | __/ \\ V V / \n" +
" |_|\\_\\ |_|\\_\\ |_| |_| |_| \\___| \\/ |_| \\___| \\_/\\_/ \n" +
" \n" +
" => Spring Boot :: (v2.4.2) QQ1 :: 613025121\n" +
" => kkFileView :: (v3.5) QQ2 :: 484680571\n" +
" => github :: https://github.com/kekingcn/kkFileView\n" +
" => gitee :: https://gitee.com/kekingcn/file-online-preview\n");
}
}

View File

@ -16,23 +16,18 @@ import java.util.Set;
@Component
public class ConfigConstants {
static {
//pdfbox兼容低版本jdk
System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
}
private static Boolean cacheEnabled;
private static String[] simTexts = {};
private static String[] medias = {};
private static String officePreviewType;
private static String officePreviewSwitchDisabled;
private static String ftpUsername;
private static String ftpPassword;
private static String ftpControlEncoding;
private static String baseUrl;
private static String fileDir = ConfigUtils.getHomePath() + File.separator + "file" + File.separator;
private static CopyOnWriteArraySet<String> trustHostSet;
private static String pdfDownloadDisable;
private static Boolean CACHE_ENABLED;
private static String[] SIM_TEXT = {};
private static String[] MEDIA = {};
private static String OFFICE_PREVIEW_TYPE;
private static String OFFICE_PREVIEW_SWITCH_DISABLED;
private static String FTP_USERNAME;
private static String FTP_PASSWORD;
private static String FTP_CONTROL_ENCODING;
private static String BASE_URL;
private static String FILE_DIR = ConfigUtils.getHomePath() + File.separator + "file" + File.separator;
private static CopyOnWriteArraySet<String> TRUST_HOST_SET;
private static String PDF_DOWNLOAD_DISABLE;
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,9 +42,8 @@ public class ConfigConstants {
public static final String DEFAULT_TRUST_HOST = "default";
public static final String DEFAULT_PDF_DOWNLOAD_DISABLE = "true";
public static Boolean isCacheEnabled() {
return cacheEnabled;
return CACHE_ENABLED;
}
@Value("${cache.enabled:true}")
@ -58,11 +52,11 @@ public class ConfigConstants {
}
public static void setCacheEnabledValueValue(Boolean cacheEnabled) {
ConfigConstants.cacheEnabled = cacheEnabled;
CACHE_ENABLED = cacheEnabled;
}
public static String[] getSimText() {
return simTexts;
return SIM_TEXT;
}
@Value("${simText:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}")
@ -72,11 +66,11 @@ public class ConfigConstants {
}
public static void setSimTextValue(String[] simText) {
ConfigConstants.simTexts = simText;
SIM_TEXT = simText;
}
public static String[] getMedia() {
return medias;
return MEDIA;
}
@Value("${media:mp3,wav,mp4,flv}")
@ -86,11 +80,11 @@ public class ConfigConstants {
}
public static void setMediaValue(String[] Media) {
ConfigConstants.medias = Media;
MEDIA = Media;
}
public static String getOfficePreviewType() {
return officePreviewType;
return OFFICE_PREVIEW_TYPE;
}
@Value("${office.preview.type:image}")
@ -99,11 +93,11 @@ public class ConfigConstants {
}
public static void setOfficePreviewTypeValue(String officePreviewType) {
ConfigConstants.officePreviewType = officePreviewType;
OFFICE_PREVIEW_TYPE = officePreviewType;
}
public static String getFtpUsername() {
return ftpUsername;
return FTP_USERNAME;
}
@Value("${ftp.username:}")
@ -112,11 +106,11 @@ public class ConfigConstants {
}
public static void setFtpUsernameValue(String ftpUsername) {
ConfigConstants.ftpUsername = ftpUsername;
FTP_USERNAME = ftpUsername;
}
public static String getFtpPassword() {
return ftpPassword;
return FTP_PASSWORD;
}
@Value("${ftp.password:}")
@ -125,11 +119,11 @@ public class ConfigConstants {
}
public static void setFtpPasswordValue(String ftpPassword) {
ConfigConstants.ftpPassword = ftpPassword;
FTP_PASSWORD = ftpPassword;
}
public static String getFtpControlEncoding() {
return ftpControlEncoding;
return FTP_CONTROL_ENCODING;
}
@Value("${ftp.control.encoding:UTF-8}")
@ -138,11 +132,11 @@ public class ConfigConstants {
}
public static void setFtpControlEncodingValue(String ftpControlEncoding) {
ConfigConstants.ftpControlEncoding = ftpControlEncoding;
FTP_CONTROL_ENCODING = ftpControlEncoding;
}
public static String getBaseUrl() {
return baseUrl;
return BASE_URL;
}
@Value("${base.url:default}")
@ -151,11 +145,11 @@ public class ConfigConstants {
}
public static void setBaseUrlValue(String baseUrl) {
ConfigConstants.baseUrl = baseUrl;
BASE_URL = baseUrl;
}
public static String getFileDir() {
return fileDir;
return FILE_DIR;
}
@Value("${file.dir:default}")
@ -168,7 +162,7 @@ public class ConfigConstants {
if (!fileDir.endsWith(File.separator)) {
fileDir = fileDir + File.separator;
}
ConfigConstants.fileDir = fileDir;
FILE_DIR = fileDir;
}
}
@ -190,15 +184,15 @@ public class ConfigConstants {
}
public static Set<String> getTrustHostSet() {
return trustHostSet;
return TRUST_HOST_SET;
}
private static void setTrustHostSet(CopyOnWriteArraySet<String> trustHostSet) {
ConfigConstants.trustHostSet = trustHostSet;
ConfigConstants.TRUST_HOST_SET = trustHostSet;
}
public static String getPdfDownloadDisable() {
return pdfDownloadDisable;
return PDF_DOWNLOAD_DISABLE;
}
@ -207,18 +201,17 @@ public class ConfigConstants {
setPdfDownloadDisableValue(pdfDownloadDisable);
}
public static void setPdfDownloadDisableValue(String pdfDownloadDisable) {
ConfigConstants.pdfDownloadDisable = pdfDownloadDisable;
PDF_DOWNLOAD_DISABLE = pdfDownloadDisable;
}
public static String getOfficePreviewSwitchDisabled() {
return officePreviewSwitchDisabled;
return OFFICE_PREVIEW_SWITCH_DISABLED;
}
@Value("${office.preview.switch.disabled:true}")
public void setOfficePreviewSwitchDisabled(String officePreviewSwitchDisabled) {
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
OFFICE_PREVIEW_SWITCH_DISABLED = officePreviewSwitchDisabled;
}
public static void setOfficePreviewSwitchDisabledValue(String officePreviewSwitchDisabled) {
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
OFFICE_PREVIEW_SWITCH_DISABLED = officePreviewSwitchDisabled;
}
}

View File

@ -0,0 +1,19 @@
package cn.keking.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author chenjh
* @since 2020/5/18 13:41
*/
@Configuration
public class RFCConfig {
@Bean
public Boolean setRequestTargetAllow() {
// RFC 7230RFC 3986规范不允许url相关特殊字符手动指定Tomcat url允许特殊符号 如{}做入参其他符号按需添加。见tomcat的HttpParser源码。
System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow", "|{}");
return true;
}
}

View File

@ -1,7 +1,7 @@
package cn.keking.config;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.KkFileUtils;
import cn.keking.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@ -31,7 +31,7 @@ public class SchedulerCleanConfig {
public void clean() {
logger.info("Cache clean start");
cacheService.cleanCache();
KkFileUtils.deleteDirectory(fileDir);
FileUtils.deleteDirectory(fileDir);
logger.info("Cache clean end");
}
}

View File

@ -4,14 +4,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author: chenjh
* @since: 2019/4/16 20:04
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
public class WebConfig extends WebMvcConfigurerAdapter {
private final static Logger LOGGER = LoggerFactory.getLogger(WebConfig.class);
/**
@ -22,5 +22,6 @@ public class WebConfig implements WebMvcConfigurer {
String filePath = ConfigConstants.getFileDir();
LOGGER.info("Add resource locations: {}", filePath);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
super.addResourceHandlers(registry);
}
}

View File

@ -11,63 +11,52 @@ import java.util.Map;
*/
public enum FileType {
PICTURE("pictureFilePreviewImpl"),
COMPRESS("compressFilePreviewImpl"),
OFFICE("officeFilePreviewImpl"),
SIMTEXT("simTextFilePreviewImpl"),
PDF("pdfFilePreviewImpl"),
CODE("codeFilePreviewImpl"),
OTHER("otherFilePreviewImpl"),
MEDIA("mediaFilePreviewImpl"),
MARKDOWN("markdownFilePreviewImpl"),
XML("xmlFilePreviewImpl"),
FLV("flvFilePreviewImpl"),
CAD("cadFilePreviewImpl"),
TIFF("tiffFilePreviewImpl");
picture("pictureFilePreviewImpl"),
compress("compressFilePreviewImpl"),
office("officeFilePreviewImpl"),
simText("simTextFilePreviewImpl"),
pdf("pdfFilePreviewImpl"),
other("otherFilePreviewImpl"),
media("mediaFilePreviewImpl"),
markdown("markdownFilePreviewImpl"),
xml("xmlFilePreviewImpl"),
flv("flvFilePreviewImpl"),
cad("cadFilePreviewImpl");
private static final String[] OFFICE_TYPES = {"docx", "wps", "doc", "xls", "xlsx", "ppt", "pptx"};
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "raw"};
private static final String[] OFFICE_TYPES = {"docx", "doc", "xls", "xlsx", "ppt", "pptx"};
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "RAW"};
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[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yml", "json", "h", "cpp", "cs", "aspx", "jsp"};
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
private static final Map<String, FileType> FILE_TYPE_MAPPER = new HashMap<>();
static {
for (String office : OFFICE_TYPES) {
FILE_TYPE_MAPPER.put(office, FileType.OFFICE);
FILE_TYPE_MAPPER.put(office, FileType.office);
}
for (String picture : PICTURE_TYPES) {
FILE_TYPE_MAPPER.put(picture, FileType.PICTURE);
FILE_TYPE_MAPPER.put(picture, FileType.picture);
}
for (String archive : ARCHIVE_TYPES) {
FILE_TYPE_MAPPER.put(archive, FileType.COMPRESS);
FILE_TYPE_MAPPER.put(archive, FileType.compress);
}
for (String text : SSIM_TEXT_TYPES) {
FILE_TYPE_MAPPER.put(text, FileType.SIMTEXT);
FILE_TYPE_MAPPER.put(text, FileType.simText);
}
for (String media : MEDIA_TYPES) {
FILE_TYPE_MAPPER.put(media, FileType.MEDIA);
FILE_TYPE_MAPPER.put(media, FileType.media);
}
for (String tif : TIFF_TYPES) {
FILE_TYPE_MAPPER.put(tif, FileType.TIFF);
}
for (String code : CODES) {
FILE_TYPE_MAPPER.put(code, FileType.CODE);
}
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);
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);
}
private static FileType to(String fileType) {
return FILE_TYPE_MAPPER.getOrDefault(fileType, OTHER);
private static FileType to(String fileType){
return FILE_TYPE_MAPPER.getOrDefault(fileType,other);
}
/**
* 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
*
@ -82,8 +71,7 @@ public enum FileType {
public static FileType typeFromFileName(String fileName) {
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
String lowerCaseFileType = fileType.toLowerCase();
return FileType.to(lowerCaseFileType);
return FileType.to(fileType);
}
private final String instanceName;

View File

@ -2,7 +2,7 @@ package cn.keking.service;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileType;
import cn.keking.utils.KkFileUtils;
import cn.keking.utils.FileUtils;
import cn.keking.web.filter.BaseUrlFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -48,7 +48,7 @@ public class CompressFileReader {
String baseUrl = BaseUrlFilter.getBaseUrl();
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
try {
ZipFile zipFile = new ZipFile(filePath, KkFileUtils.getFileEncode(filePath));
ZipFile zipFile = new ZipFile(filePath, FileUtils.getFileEncode(filePath));
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
// 排序
entries = sortZipEntries(entries);
@ -68,7 +68,7 @@ public class CompressFileReader {
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level - 1) + "_" + parentName;
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);
@ -121,7 +121,7 @@ public class CompressFileReader {
}
String parentName = getLast2FileName(fullName, "\\", 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);
@ -164,7 +164,7 @@ public class CompressFileReader {
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level - 1) + "_" + parentName;
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);
@ -382,7 +382,7 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
FileUtils.deleteFileByPath(filePath);
}
private void extractZipFile(String childName, InputStream zipFile) {
@ -439,7 +439,7 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
FileUtils.deleteFileByPath(filePath);
}
}
@ -468,7 +468,7 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
FileUtils.deleteFileByPath(filePath);
}
private void extractRarFile(String childName, FileHeader header, Archive archive) {

View File

@ -62,7 +62,7 @@ public class FileConvertQueueTask {
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url,null);
FileType fileType = fileAttribute.getType();
logger.info("正在处理预览转换任务url{},预览类型:{}", url, fileType);
if(fileType.equals(FileType.COMPRESS) || fileType.equals(FileType.OFFICE) || fileType.equals(FileType.CAD)) {
if(fileType.equals(FileType.compress) || fileType.equals(FileType.office) || fileType.equals(FileType.cad)) {
FilePreview filePreview = previewFactory.get(fileAttribute);
filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute);
} else {

View File

@ -4,7 +4,7 @@ import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.KkFileUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.WebUtils;
import com.aspose.cad.Color;
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
@ -178,15 +178,14 @@ public class FileHandlerService {
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
String urlPrefix;
try {
urlPrefix = baseUrl + URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20");
urlPrefix = baseUrl + URLEncoder.encode(URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20"), uriEncoding);
} catch (UnsupportedEncodingException e) {
logger.error("UnsupportedEncodingException", e);
urlPrefix = baseUrl + pdfFolder;
}
if (imageCount != null && imageCount > 0) {
for (int i = 0; i < imageCount; i++) {
for (int i = 0; i < imageCount; i++)
imageUrls.add(urlPrefix + "/" + i + imageFileSuffix);
}
return imageUrls;
}
try {
@ -264,7 +263,7 @@ public class FileHandlerService {
if (StringUtils.hasText(fullFileName)) {
fileName = fullFileName;
type = FileType.typeFromFileName(fullFileName);
suffix = KkFileUtils.suffixFromFileName(fullFileName);
suffix = FileUtils.suffixFromFileName(fullFileName);
} else {
fileName = WebUtils.getFileNameFromURL(url);
type = FileType.typeFromUrl(url);
@ -276,7 +275,7 @@ public class FileHandlerService {
attribute.setUrl(url);
if (req != null) {
String officePreviewType = req.getParameter("officePreviewType");
String fileKey = WebUtils.getUrlParameterReg(url,"fileKey");
String fileKey = req.getParameter("fileKey");
if (StringUtils.hasText(officePreviewType)) {
attribute.setOfficePreviewType(officePreviewType);
}

View File

@ -14,13 +14,9 @@ public interface FilePreview {
String COMPRESS_FILE_PREVIEW_PAGE = "compress";
String MEDIA_FILE_PREVIEW_PAGE = "media";
String PICTURE_FILE_PREVIEW_PAGE = "picture";
String TIFF_FILE_PREVIEW_PAGE = "tiff";
String OFFICE_PICTURE_FILE_PREVIEW_PAGE = "officePicture";
String TXT_FILE_PREVIEW_PAGE = "txt";
String CODE_FILE_PREVIEW_PAGE = "code";
String EXEL_FILE_PREVIEW_PAGE = "html";
String XML_FILE_PREVIEW_PAGE = "xml";
String MARKDOWN_FILE_PREVIEW_PAGE = "markdown";
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);

View File

@ -8,8 +8,6 @@ import org.artofsolving.jodconverter.office.OfficeManager;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.convert.DurationStyle;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@ -21,11 +19,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -43,12 +37,6 @@ public class OfficePluginManager {
private OfficeManager officeManager;
@Value("${office.plugin.server.ports:2001,2002}")
private String serverPorts;
@Value("${office.plugin.task.timeout:5m}")
private String timeOut;
@PostConstruct
public void initOfficeManager() {
new Thread(this::startOfficeManager).start();
@ -69,14 +57,9 @@ public class OfficePluginManager {
try {
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
configuration.setOfficeHome(officeHome);
String []portsString = serverPorts.split(",");
int[] ports = Arrays.stream(portsString).mapToInt(Integer::parseInt).toArray();
configuration.setPortNumbers(ports);
long timeout = DurationStyle.detectAndParse(timeOut).toMillis();
configuration.setPortNumber(8100);
// 设置任务执行超时为5分钟
configuration.setTaskExecutionTimeout(timeout);
configuration.setTaskExecutionTimeout(1000 * 60 * 5L);
// 设置任务队列超时为24小时
//configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);
officeManager = configuration.buildOfficeManager();

View File

@ -35,7 +35,7 @@ public class CadFilePreviewImpl implements FilePreview {
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
// 预览Type参数传了就取参数的没传取系统默认
String officePreviewType = fileAttribute.getOfficePreviewType() == null ? ConfigConstants.getOfficePreviewType() : fileAttribute.getOfficePreviewType();
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
String baseUrl = BaseUrlFilter.getBaseUrl();
String fileName = fileAttribute.getName();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";

View File

@ -1,26 +0,0 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
/**
* @author kl (http://kailing.pub)
* @since 2021/2/18
*/
@Component
public class CodeFilePreviewImpl implements FilePreview {
private final SimTextFilePreviewImpl filePreviewHandle;
public CodeFilePreviewImpl(SimTextFilePreviewImpl filePreviewHandle) {
this.filePreviewHandle = filePreviewHandle;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
filePreviewHandle.filePreviewHandle(url, model, fileAttribute);
return CODE_FILE_PREVIEW_PAGE;
}
}

View File

@ -5,6 +5,8 @@ import cn.keking.service.FilePreview;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import static cn.keking.service.impl.SimTextFilePreviewImpl.TEXT_TYPE;
/**
* @author kl (http://kailing.pub)
* @since 2020/12/25
@ -21,7 +23,7 @@ public class MarkdownFilePreviewImpl implements FilePreview {
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
return MARKDOWN_FILE_PREVIEW_PAGE;
model.addAttribute(TEXT_TYPE,"markdown");
return simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
}
}

View File

@ -4,12 +4,10 @@ import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.KkFileUtils;
import jodd.io.FileUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.util.HtmlUtils;
import org.springframework.util.Base64Utils;
import java.io.File;
import java.io.IOException;
@ -22,6 +20,9 @@ import java.nio.charset.StandardCharsets;
@Service
public class SimTextFilePreviewImpl implements FilePreview {
public static final String TEXT_TYPE = "textType";
public static final String DEFAULT_TEXT_TYPE = "simText";
private final OtherFilePreviewImpl otherFilePreview;
public SimTextFilePreviewImpl(OtherFilePreviewImpl otherFilePreview) {
@ -37,13 +38,14 @@ public class SimTextFilePreviewImpl implements FilePreview {
}
try {
File originFile = new File(response.getContent());
String charset = KkFileUtils.getFileEncode(originFile);
String fileData = FileUtil.readString(originFile, charset);
fileData = HtmlUtils.htmlEscape(fileData, StandardCharsets.UTF_8.name());
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
String xmlString = FileUtils.readFileToString(originFile, StandardCharsets.UTF_8);
model.addAttribute("textData", Base64Utils.encodeToString(xmlString.getBytes(StandardCharsets.UTF_8)));
} catch (IOException e) {
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
}
if (!model.containsAttribute(TEXT_TYPE)) {
model.addAttribute(TEXT_TYPE, DEFAULT_TEXT_TYPE);
}
return TXT_FILE_PREVIEW_PAGE;
}

View File

@ -1,27 +0,0 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.service.FilePreview;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
/**
* tiff 图片文件处理
* @author kl (http://kailing.pub)
* @since 2021/2/8
*/
@Service
public class TiffFilePreviewImpl implements FilePreview {
private final PictureFilePreviewImpl pictureFilePreview;
public TiffFilePreviewImpl(PictureFilePreviewImpl pictureFilePreview) {
this.pictureFilePreview = pictureFilePreview;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
pictureFilePreview.filePreviewHandle(url,model,fileAttribute);
return TIFF_FILE_PREVIEW_PAGE;
}
}

View File

@ -5,6 +5,8 @@ import cn.keking.service.FilePreview;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import static cn.keking.service.impl.SimTextFilePreviewImpl.TEXT_TYPE;
/**
* @author kl (http://kailing.pub)
* @since 2020/12/25
@ -20,7 +22,7 @@ public class XmlFilePreviewImpl implements FilePreview {
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
return XML_FILE_PREVIEW_PAGE;
model.addAttribute(TEXT_TYPE,"xml");
return simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
}
}

View File

@ -2,19 +2,17 @@ package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.model.ReturnResponse;
import io.mola.galimatias.GalimatiasParseException;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import static cn.keking.utils.KkFileUtils.isFtpUrl;
import static cn.keking.utils.KkFileUtils.isHttpUrl;
/**
* @author yudian-it
*/
@ -33,26 +31,42 @@ public class DownloadUtils {
*/
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
String urlStr = fileAttribute.getUrl();
String type = fileAttribute.getSuffix();
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
String realPath = DownloadUtils.getRelFilePath(fileName, fileAttribute);
UUID uuid = UUID.randomUUID();
if (null == fileName) {
fileName = uuid + "." + type;
} else { // 文件后缀不一致时以type为准(针对simText【将类txt文件转为txt】)
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
}
String realPath = fileDir + fileName;
File dirFile = new File(fileDir);
if (!dirFile.exists() && !dirFile.mkdirs()) {
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
}
try {
URL url = WebUtils.normalizedURL(urlStr);
if (isHttpUrl(url)) {
File realFile = new File(realPath);
FileUtils.copyURLToFile(url,realFile);
} else if (isFtpUrl(url)) {
URL url = new URL(urlStr);
if (url.getProtocol() != null && (url.getProtocol().toLowerCase().startsWith("file") || url.getProtocol().toLowerCase().startsWith("http"))) {
byte[] bytes = getBytesFromUrl(urlStr);
OutputStream os = new FileOutputStream(realPath);
saveBytesToOutStream(bytes, os);
} else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
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.setContent(null);
response.setMsg("url不能识别url" + urlStr);
}
response.setContent(realPath);
response.setMsg(fileName);
if (FileType.simText.equals(fileAttribute.getType())) {
convertTextPlainFileCharsetToUtf8(realPath);
}
return response;
} catch (IOException | GalimatiasParseException e) {
} catch (IOException e) {
logger.error("文件下载失败url{}", urlStr, e);
response.setCode(1);
response.setContent(null);
@ -65,27 +79,82 @@ public class DownloadUtils {
}
}
/**
* 获取真实文件绝对路径
*
* @param fileName 文件名
* @return 文件路径
*/
private static String getRelFilePath(String fileName, FileAttribute fileAttribute) {
String type = fileAttribute.getSuffix();
if (null == fileName) {
UUID uuid = UUID.randomUUID();
fileName = uuid + "." + type;
} else { // 文件后缀不一致时以type为准(针对simText【将类txt文件转为txt】)
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
public static byte[] getBytesFromUrl(String urlStr) throws IOException {
InputStream is = getInputStreamFromUrl(urlStr);
if (is == null) {
is = getInputStreamFromUrl(urlStr);
if (is == null) {
logger.error("文件下载异常url{}", urlStr);
throw new IOException("文件下载异常url" + urlStr);
}
}
String realPath = fileDir + fileName;
File dirFile = new File(fileDir);
if (!dirFile.exists() && !dirFile.mkdirs()) {
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
}
return realPath;
return getBytesFromStream(is);
}
public static void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
os.write(b);
os.close();
}
private static InputStream getInputStreamFromUrl(String urlStr) {
try {
URL url = io.mola.galimatias.URL.parse(urlStr).toJavaURL();
URLConnection connection = url.openConnection();
if (connection instanceof HttpURLConnection) {
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
}
return connection.getInputStream();
} catch (IOException | GalimatiasParseException e) {
logger.warn("连接url异常url{}", urlStr);
return null;
}
}
private static byte[] getBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
byte[] b = baos.toByteArray();
is.close();
baos.close();
return b;
}
/**
* 转换文本文件编码为utf8
* 探测源文件编码,探测到编码切不为utf8则进行转码
*
* @param filePath 文件路径
*/
private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
File sourceFile = new File(filePath);
if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
String encoding = FileUtils.getFileEncode(filePath);
if (!FileUtils.DEFAULT_FILE_ENCODING.equals(encoding)) {
// 不为utf8,进行转码
File tmpUtf8File = new File(filePath + ".utf8");
Writer writer = new OutputStreamWriter(new FileOutputStream(tmpUtf8File), StandardCharsets.UTF_8);
Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile), encoding));
char[] buf = new char[1024];
int read;
while ((read = reader.read(buf)) > 0) {
writer.write(buf, 0, read);
}
reader.close();
writer.close();
// 删除源文件
if (!sourceFile.delete()) {
logger.error("源文件【{}】删除失败,请检查文件目录权限!", filePath);
}
// 重命名
if (tmpUtf8File.renameTo(sourceFile)) {
logger.error("临时文件【{}】重命名失败,请检查文件路径权限!", tmpUtf8File.getPath());
}
}
}
}
}

View File

@ -6,39 +6,19 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
public class KkFileUtils {
public class FileUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(KkFileUtils.class);
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
public static final String DEFAULT_FILE_ENCODING = "UTF-8";
/**
* 判断url是否是http资源
*
* @param url url
* @return 是否http
*/
public static boolean isHttpUrl(URL url) {
return url.getProtocol().toLowerCase().startsWith("file") || url.getProtocol().toLowerCase().startsWith("http");
}
/**
* 判断url是否是ftp资源
*
* @param url url
* @return 是否ftp
*/
public static boolean isFtpUrl(URL url) {
return "ftp".equalsIgnoreCase(url.getProtocol());
}
/**
* 删除单个文件
*
* @param fileName 要删除的文件的文件名
* @param fileName
* 要删除的文件的文件名
* @return 单个文件删除成功返回true否则返回false
*/
public static boolean deleteFileByName(String fileName) {
@ -59,26 +39,17 @@ public class KkFileUtils {
}
/**
* 检测文件编码格式
* 判断文件编码格式
*
* @param filePath 绝对路径
* @return 编码格式
*/
public static String getFileEncode(String filePath) {
return getFileEncode(new File(filePath));
}
/**
* 检测文件编码格式
*
* @param file 检测的文件
* @return 编码格式
*/
public static String getFileEncode(File file) {
File file = new File(filePath);
CharsetPrinter cp = new CharsetPrinter();
try {
String encoding = cp.guessEncoding(file);
LOGGER.info("检测到文件【{}】编码: {}", file.getAbsolutePath(), encoding);
LOGGER.info("检测到文件【{}】编码: {}", filePath, encoding);
return encoding;
} catch (IOException e) {
LOGGER.warn("文件编码获取失败采用默认的编码格式UTF-8", e);
@ -88,7 +59,6 @@ public class KkFileUtils {
/**
* 通过文件名获取文件后缀
*
* @param fileName 文件名称
* @return 文件后缀
*/
@ -112,7 +82,8 @@ public class KkFileUtils {
/**
* 删除目录及目录下的文件
*
* @param dir 要删除的目录的文件路径
* @param dir
* 要删除的目录的文件路径
* @return 目录删除成功返回true否则返回false
*/
public static boolean deleteDirectory(String dir) {
@ -132,13 +103,13 @@ public class KkFileUtils {
for (int i = 0; i < Objects.requireNonNull(files).length; i++) {
// 删除子文件
if (files[i].isFile()) {
flag = KkFileUtils.deleteFileByName(files[i].getAbsolutePath());
flag = FileUtils.deleteFileByName(files[i].getAbsolutePath());
if (!flag) {
break;
}
} else if (files[i].isDirectory()) {
} else if (files[i].isDirectory()) {
// 删除子目录
flag = KkFileUtils.deleteDirectory(files[i].getAbsolutePath());
flag = FileUtils.deleteDirectory(files[i].getAbsolutePath());
if (!flag) {
break;
}

View File

@ -1,9 +1,5 @@
package cn.keking.utils;
import io.mola.galimatias.GalimatiasParseException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
@ -12,16 +8,6 @@ import java.util.Map;
* create : 2020-12-27 1:30 上午
**/
public class WebUtils {
/**
* 获取标准的URL
* @param urlStr url
* @return 标准的URL
*/
public static URL normalizedURL(String urlStr) throws GalimatiasParseException, MalformedURLException {
return io.mola.galimatias.URL.parse(urlStr).toJavaURL();
}
/**
* 获取url中的参数
*
@ -95,6 +81,6 @@ public class WebUtils {
public static String suffixFromUrl(String url) {
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
return KkFileUtils.suffixFromFileName(fileName);
return FileUtils.suffixFromFileName(fileName);
}
}

View File

@ -15,9 +15,7 @@ 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;
/**
*
@ -38,10 +36,6 @@ public class FileController {
// 获取文件名
String fileName = file.getOriginalFilename();
//判断是否为IE浏览器的文件名IE浏览器下文件名会带有盘符信息
// escaping dangerous characters to prevent XSS
fileName = HtmlUtils.htmlEscape(fileName, StandardCharsets.UTF_8.name());
// Check for Unix-style path
int unixSep = fileName.lastIndexOf('/');
// Check for Windows-style path

View File

@ -6,16 +6,13 @@ import cn.keking.service.FilePreviewFactory;
import cn.keking.service.cache.CacheService;
import cn.keking.service.impl.OtherFilePreviewImpl;
import cn.keking.utils.DownloadUtils;
import cn.keking.service.FileHandlerService;
import cn.keking.utils.WebUtils;
import fr.opensagres.xdocreport.core.io.IOUtils;
import io.mola.galimatias.GalimatiasParseException;
import jodd.io.NetUtil;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -24,8 +21,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
@ -56,13 +51,12 @@ public class OnlinePreviewController {
public String onlinePreview(String url, Model model, HttpServletRequest req) {
String fileUrl;
try {
fileUrl = new String(Base64.decodeBase64(url), StandardCharsets.UTF_8);
fileUrl = new String(Base64Utils.decodeFromString(url));
} catch (Exception ex) {
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
return otherFilePreview.notSupportedFile(model, errorMsg);
}
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req);
model.addAttribute("file", fileAttribute);
FilePreview filePreview = previewFactory.get(fileAttribute);
logger.info("预览文件url{}previewType{}", fileUrl, fileAttribute.getType());
return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
@ -72,7 +66,7 @@ public class OnlinePreviewController {
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
String fileUrls;
try {
fileUrls = new String(Base64.decodeBase64(urls));
fileUrls = new String(Base64Utils.decodeFromString(urls));
} catch (Exception ex) {
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "urls");
return otherFilePreview.notSupportedFile(model, errorMsg);
@ -85,7 +79,7 @@ public class OnlinePreviewController {
String currentUrl = req.getParameter("currentUrl");
if (StringUtils.hasText(currentUrl)) {
String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl));
String decodedCurrentUrl = new String(Base64Utils.decodeFromString(currentUrl));
model.addAttribute("currentUrl", decodedCurrentUrl);
} else {
model.addAttribute("currentUrl", imgUrls.get(0));
@ -104,10 +98,9 @@ public class OnlinePreviewController {
public void getCorsFile(String urlPath, HttpServletResponse response) {
logger.info("下载跨域pdf文件url{}", urlPath);
try {
URL url = WebUtils.normalizedURL(urlPath);
byte[] bytes = NetUtil.downloadBytes(url.toString());
IOUtils.write(bytes, response.getOutputStream());
} catch (IOException | GalimatiasParseException e) {
byte[] bytes = DownloadUtils.getBytesFromUrl(urlPath);
DownloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
} catch (IOException e) {
logger.error("下载跨域pdf文件异常url{}", urlPath, e);
}
}

View File

@ -3,7 +3,6 @@ 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.*;
@ -35,9 +34,6 @@ 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);
if (host != null &&!ConfigConstants.getTrustHostSet().isEmpty() && !ConfigConstants.getTrustHostSet().contains(host)) {
String html = this.notTrustHost.replace("${current_host}", host);

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