Compare commits

..

1 Commits

4400 changed files with 3820 additions and 6698 deletions

5
.gitignore vendored
View File

@@ -17,6 +17,7 @@ target/
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
@@ -26,5 +27,5 @@ nbdist/
### VS Code ###
.vscode/
server/src/main/cache/
server/src/main/file/
jodconverter-web/src/main/cache/
jodconverter-web/src/main/file/

View File

@@ -1,6 +1,6 @@
FROM ubuntu:20.04
MAINTAINER chenjh "842761733@qq.com"
ADD server/target/kkFileView-*.tar.gz /opt/
ADD jodconverter-web/target/kkFileView-*.tar.gz /opt/
COPY fonts/* /usr/share/fonts/chienes/
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 &&\
@@ -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-2.2.1/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-2.2.1/config/application.properties","-jar","/opt/kkFileView-2.2.1/bin/kkFileView-2.2.1.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,60 +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共同建设
1. 架构模块调整,大量的代码重构代码质量提升N个等级欢迎品鉴
2. 增强XML文件预览效果新增XML文档数结构预览
3. 新增markdown文件预览支持预览支持md渲染和源文本切换支持
4. 切换底层web server为jetty解决这个issuehttps://github.com/kekingcn/kkFileView/issues/168
5. 引入cpdetector解决文件编码识别问题
6. url采用base64+urlencode双编码彻底解决各种奇葩文件名预览问题
7. 新增配置项office.preview.switch.disabled控制offic文件预览切换开关
8. 优化文本类型文件预览逻辑采用Base64传输内容避免预览时再次请求文件内容
9. office预览图片模式禁用图片放大效果达到图片和pdf预览效果一致的体验
10. 直接代码静态设置pdfbox兼容低版本jdk在IDEA中运行也不会有警告提示
11. 移除guavahutool等非必须的工具包减少代码体积
12. Office组件加载异步化提速应用启动速度最快到5秒内
13. 合理设置预览消费队列的线程数
14. 修复压缩包里文件再次预览失败的bug
15. 修复图片预览的bug
> 2020年05月20日
1. 新增支持全局水印并支持通过参数动态改变水印内容
2. 新增支持CAD文件预览
@@ -207,13 +163,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>
<artifactId>office-plugin</artifactId>
<groupId>cn.keking</groupId>
<artifactId>jodconverter-core</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

@@ -19,7 +19,6 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.artofsolving.jodconverter.util.ConfigUtils;
import org.artofsolving.jodconverter.util.PlatformUtils;
import com.sun.star.beans.PropertyValue;
@@ -56,7 +55,7 @@ public class OfficeUtils {
Map<String,Object> subProperties = (Map<String,Object>) value;
value = toUnoProperties(subProperties);
}
propertyValues[i++] = property(entry.getKey(), value);
propertyValues[i++] = property((String) entry.getKey(), value);
}
return propertyValues;
}
@@ -69,7 +68,7 @@ public class OfficeUtils {
public static File getDefaultOfficeHome() {
Properties properties = new Properties();
String customizedConfigPath = ConfigUtils.getCustomizedConfigPath();
String customizedConfigPath = getCustomizedConfigPath();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
properties.load(bufferedReader);
@@ -81,7 +80,7 @@ public class OfficeUtils {
}
if (PlatformUtils.isWindows()) {
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
String officePluginPath = ConfigUtils.getOfficePluginPath();
String homePath = OfficeUtils.getHomePath();
String programFiles = System.getenv("ProgramFiles(x86)");
if (programFiles == null) {
programFiles = System.getenv("ProgramFiles");
@@ -89,7 +88,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(
@@ -128,7 +127,30 @@ public class OfficeUtils {
}
}
public static String getHomePath() {
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
if (userDir == null) {
userDir = System.getProperty("user.dir");
}
if (userDir.endsWith("bin")) {
userDir = userDir.substring(0, userDir.length() - 4);
} else {
String separator = File.separator;
if (userDir.contains("jodconverter-web")) {
userDir = userDir + separator + "src" + separator + "main";
} else {
userDir = userDir + separator + "jodconverter-web" + separator + "src" + separator + "main";
}
}
return userDir;
}
public static String getCustomizedConfigPath() {
String homePath = OfficeUtils.getHomePath();
String separator = java.io.File.separator;
String configFilePath = homePath + separator + "config" + separator + "application.properties";
return configFilePath;
}
/**
* SpringBoot application.properties 支持从环境变量获取值

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>2.2.1</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>
@@ -31,18 +35,12 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -50,8 +48,14 @@
</dependency>
<dependency>
<groupId>cn.keking</groupId>
<artifactId>office-plugin</artifactId>
<version>${project.version}</version>
<artifactId>jodconverter-core</artifactId>
<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 +71,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 +99,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 +158,12 @@
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.16</version>
<version>1.4.15</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
@@ -178,22 +192,7 @@
<scope>system</scope>
<systemPath>${basedir}/lib/aspose-cad-19.9.jar</systemPath>
</dependency>
<!-- 编码识别 -->
<dependency>
<groupId>cpdetector</groupId>
<artifactId>cpdetector</artifactId>
<version>1.04</version>
<scope>system</scope>
<systemPath>${basedir}/lib/cpdetector-1.04.jar</systemPath>
</dependency>
<!-- url 规范化 -->
<dependency>
<groupId>io.mola.galimatias</groupId>
<artifactId>galimatias</artifactId>
<version>0.2.1</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@@ -205,6 +204,9 @@
</resource>
<resource>
<directory>src/main/config</directory>
<excludes>
<exclude>${build.exclude.resource}</exclude>
</excludes>
<filtering>true</filtering>
</resource>
</resources>
@@ -212,25 +214,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

@@ -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-2.2.1.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-2.2.1.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,17 +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" --]
[#-- @ftlvariable name="textData" type="java.lang.String" --]
[#-- @ftlvariable name="xmlContent" type="java.lang.String" --]
[#-- @ftlvariable name="textContent" type="java.lang.String" --]
[#-- @ftlvariable name="textType" type="java.lang.String" --]
[#-- @ftlvariable name="markdown" type="String" --]
[#-- @ftlvariable name="xml" type="String" --]
[#-- @ftlvariable name="switchDisabled" type="String" --]
[#-- @ftlvariable name="imgurls" type="String" --]
[#-- @ftlvariable name="watermarkAngle" type="String" --]

View File

@@ -0,0 +1,15 @@
package cn.keking;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@ComponentScan(value = "cn.keking.*")
public class FilePreviewApplication {
public static void main(String[] args) {
SpringApplication.run(FilePreviewApplication.class, args);
}
}

View File

@@ -1,6 +1,6 @@
package cn.keking.config;
import org.artofsolving.jodconverter.util.ConfigUtils;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -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 = OfficeUtils.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}")
@@ -164,11 +158,11 @@ public class ConfigConstants {
}
public static void setFileDirValue(String fileDir) {
if (!DEFAULT_FILE_DIR_VALUE.equalsIgnoreCase(fileDir)) {
if (!DEFAULT_FILE_DIR_VALUE.equals(fileDir.toLowerCase())) {
if (!fileDir.endsWith(File.separator)) {
fileDir = fileDir + File.separator;
}
ConfigConstants.fileDir = fileDir;
FILE_DIR = fileDir;
}
}
@@ -179,7 +173,7 @@ public class ConfigConstants {
public static void setTrustHostValue(String trustHost) {
CopyOnWriteArraySet<String> trustHostSet;
if (DEFAULT_TRUST_HOST.equalsIgnoreCase(trustHost)) {
if (DEFAULT_TRUST_HOST.equals(trustHost.toLowerCase())) {
trustHostSet = new CopyOnWriteArraySet<>();
} else {
String[] trustHostArray = trustHost.toLowerCase().split(",");
@@ -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,15 @@ public class ConfigConstants {
setPdfDownloadDisableValue(pdfDownloadDisable);
}
public static void setPdfDownloadDisableValue(String pdfDownloadDisable) {
ConfigConstants.pdfDownloadDisable = pdfDownloadDisable;
PDF_DOWNLOAD_DISABLE = pdfDownloadDisable;
}
public static String getOfficePreviewSwitchDisabled() {
return officePreviewSwitchDisabled;
}
@Value("${office.preview.switch.disabled:true}")
public void setOfficePreviewSwitchDisabled(String officePreviewSwitchDisabled) {
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
}
public static void setOfficePreviewSwitchDisabledValue(String officePreviewSwitchDisabled) {
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
return OFFICE_PREVIEW_SWITCH_DISABLED;
}
@Value("${office.preview.switch.disabled:true}")
public static void setOfficePreviewSwitchDisabled(String officePreviewSwitchDisabled) {
OFFICE_PREVIEW_SWITCH_DISABLED = officePreviewSwitchDisabled;
}
}

View File

@@ -1,7 +1,6 @@
package cn.keking.config;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.artofsolving.jodconverter.util.ConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -11,7 +10,6 @@ import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* @auther: chenjh
@@ -44,7 +42,7 @@ public class ConfigRefreshComponent {
String ftpUsername;
String ftpPassword;
String ftpControlEncoding;
String configFilePath = ConfigUtils.getCustomizedConfigPath();
String configFilePath = OfficeUtils.getCustomizedConfigPath();
String baseUrl;
String trustHost;
String pdfDownloadDisable;
@@ -75,12 +73,12 @@ public class ConfigRefreshComponent {
ConfigConstants.setFtpControlEncodingValue(ftpControlEncoding);
ConfigConstants.setBaseUrlValue(baseUrl);
ConfigConstants.setTrustHostValue(trustHost);
ConfigConstants.setOfficePreviewSwitchDisabledValue(officePreviewSwitchDisabled);
ConfigConstants.setOfficePreviewSwitchDisabled(officePreviewSwitchDisabled);
ConfigConstants.setPdfDownloadDisableValue(pdfDownloadDisable);
setWatermarkConfig(properties);
bufferedReader.close();
fileReader.close();
TimeUnit.SECONDS.sleep(1);
Thread.sleep(1000L);
}
} catch (IOException | InterruptedException e) {
LOGGER.error("读取配置文件异常", e);

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

@@ -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

@@ -1,4 +1,4 @@
package cn.keking.service;
package cn.keking.extend;
import org.artofsolving.jodconverter.document.DocumentFamily;
import org.artofsolving.jodconverter.document.DocumentFormat;
@@ -13,9 +13,9 @@ import java.util.Map;
* @author yudian-it
* @date 2017/12/5
*/
public class OfficePluginExtendFormatRegistry extends SimpleDocumentFormatRegistry {
public class ControlDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
public OfficePluginExtendFormatRegistry() {
public ControlDocumentFormatRegistry() {
DocumentFormat pdf = new DocumentFormat("Portable Document Format", "pdf", "application/pdf");
pdf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer_pdf_Export"));
pdf.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc_pdf_Export"));

View File

@@ -0,0 +1,388 @@
package cn.keking.hutool;
import java.awt.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 十六进制简写为hex或下标16在数学中是一种逢16进1的进位制一般用数字0到9和字母A到F表示其中:A~F即10~15。<br>
* 例如十进制数57在二进制写作111001在16进制写作39。<br>
* 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br>
* <p>
* 参考https://my.oschina.net/xinxingegeya/blog/287476
*
* @author Looly
*/
public class HexUtil {
/**
* 用于建立十六进制字符的输出的小写字符数组
*/
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 用于建立十六进制字符的输出的大写字符数组
*/
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* 判断给定字符串是否为16进制数<br>
* 如果是,需要使用对应数字类型对象的<code>decode</code>方法解码<br>
* 例如:{@code Integer.decode}方法解码int类型的16进制数字
*
* @param value 值
* @return 是否为16进制
*/
public static boolean isHexNumber(String value) {
final int index = (value.startsWith("-") ? 1 : 0);
if (value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index)) {
try {
Long.decode(value);
} catch (NumberFormatException e) {
return false;
}
return true;
} else {
return false;
}
}
// ---------------------------------------------------------------------------------------------------- encode
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data) {
return encodeHex(data, true);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param str 字符串
* @param charset 编码
* @return 十六进制char[]
*/
public static char[] encodeHex(String str, Charset charset) {
return encodeHex(StrUtil.bytes(str, charset), true);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data) {
return encodeHexStr(data, true);
}
/**
* 将字节数组转换为十六进制字符串,结果为小写
*
* @param data 被编码的字符串
* @param charset 编码
* @return 十六进制String
*/
public static String encodeHexStr(String data, Charset charset) {
return encodeHexStr(StrUtil.bytes(data, charset), true);
}
/**
* 将字节数组转换为十六进制字符串结果为小写默认编码是UTF-8
*
* @param data 被编码的字符串
* @return 十六进制String
*/
public static String encodeHexStr(String data) {
return encodeHexStr(data, StandardCharsets.UTF_8);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data, boolean toLowerCase) {
return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
// ---------------------------------------------------------------------------------------------------- decode
/**
* 将十六进制字符数组转换为字符串默认编码UTF-8
*
* @param hexStr 十六进制String
* @return 字符串
*/
public static String decodeHexStr(String hexStr) {
return decodeHexStr(hexStr, StandardCharsets.UTF_8);
}
/**
* 将十六进制字符数组转换为字符串
*
* @param hexStr 十六进制String
* @param charset 编码
* @return 字符串
*/
public static String decodeHexStr(String hexStr, Charset charset) {
if (StrUtil.isEmpty(hexStr)) {
return hexStr;
}
return decodeHexStr(hexStr.toCharArray(), charset);
}
/**
* 将十六进制字符数组转换为字符串
*
* @param hexData 十六进制char[]
* @param charset 编码
* @return 字符串
*/
public static String decodeHexStr(char[] hexData, Charset charset) {
return StrUtil.str(decodeHex(hexData), charset);
}
/**
* 将十六进制字符数组转换为字节数组
*
* @param hexData 十六进制char[]
* @return byte[]
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
*/
public static byte[] decodeHex(char[] hexData) {
int len = hexData.length;
if ((len & 0x01) != 0) {
throw new RuntimeException("Odd number of characters.");
}
byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(hexData[j], j) << 4;
j++;
f = f | toDigit(hexData[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
/**
* 将十六进制字符串解码为byte[]
*
* @param hexStr 十六进制String
* @return byte[]
*/
public static byte[] decodeHex(String hexStr) {
if (StrUtil.isEmpty(hexStr)) {
return null;
}
return decodeHex(hexStr.toCharArray());
}
// ---------------------------------------------------------------------------------------- Color
/**
* 将{@link Color}编码为Hex形式
*
* @param color {@link Color}
* @return Hex字符串
* @since 3.0.8
*/
public static String encodeColor(Color color) {
return encodeColor(color, "#");
}
/**
* 将{@link Color}编码为Hex形式
*
* @param color {@link Color}
* @param prefix 前缀字符串,可以是#、0x等
* @return Hex字符串
* @since 3.0.8
*/
public static String encodeColor(Color color, String prefix) {
final StringBuilder builder = new StringBuilder(prefix);
String colorHex;
colorHex = Integer.toHexString(color.getRed());
if (1 == colorHex.length()) {
builder.append('0');
}
builder.append(colorHex);
colorHex = Integer.toHexString(color.getGreen());
if (1 == colorHex.length()) {
builder.append('0');
}
builder.append(colorHex);
colorHex = Integer.toHexString(color.getBlue());
if (1 == colorHex.length()) {
builder.append('0');
}
builder.append(colorHex);
return builder.toString();
}
/**
* 将Hex颜色值转为
*
* @param hexColor 16进制颜色值可以以#开头也可以用0x开头
* @return {@link Color}
* @since 3.0.8
*/
public static Color decodeColor(String hexColor) {
return Color.decode(hexColor);
}
/**
* 将指定int值转换为Unicode字符串形式常用于特殊字符例如汉字转Unicode形式<br>
* 转换的字符串如果u后不足4位则前面用0填充例如
*
* <pre>
* '我' =》\u4f60
* </pre>
*
* @param value int值也可以是char
* @return Unicode表现形式
*/
public static String toUnicodeHex(int value) {
final StringBuilder builder = new StringBuilder(6);
builder.append("\\u");
String hex = toHex(value);
int len = hex.length();
if (len < 4) {
builder.append("0000", 0, 4 - len);// 不足4位补0
}
builder.append(hex);
return builder.toString();
}
/**
* 将指定char值转换为Unicode字符串形式常用于特殊字符例如汉字转Unicode形式<br>
* 转换的字符串如果u后不足4位则前面用0填充例如
*
* <pre>
* '我' =》\u4f60
* </pre>
*
* @param ch char值
* @return Unicode表现形式
* @since 4.0.1
*/
public static String toUnicodeHex(char ch) {
return "\\u" +//
DIGITS_LOWER[(ch >> 12) & 15] +//
DIGITS_LOWER[(ch >> 8) & 15] +//
DIGITS_LOWER[(ch >> 4) & 15] +//
DIGITS_LOWER[(ch) & 15];
}
/**
* 转为16进制字符串
*
* @param value int值
* @return 16进制字符串
* @since 4.4.1
*/
public static String toHex(int value) {
return Integer.toHexString(value);
}
/**
* 转为16进制字符串
*
* @param value int值
* @return 16进制字符串
* @since 4.4.1
*/
public static String toHex(long value) {
return Long.toHexString(value);
}
/**
* 将byte值转为16进制并添加到{@link StringBuilder}中
*
* @param builder {@link StringBuilder}
* @param b byte
* @param toLowerCase 是否使用小写
* @since 4.4.1
*/
public static void appendHex(StringBuilder builder, byte b, boolean toLowerCase) {
final char[] toDigits = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER;
int high = (b & 0xf0) >>> 4;//高位
int low = b & 0x0f;//低位
builder.append(toDigits[high]);
builder.append(toDigits[low]);
}
// ---------------------------------------------------------------------------------------- Private method start
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制String
*/
private static String encodeHexStr(byte[] data, char[] toDigits) {
return new String(encodeHex(data, toDigits));
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制char[]
*/
private static char[] encodeHex(byte[] data, char[] toDigits) {
final int len = data.length;
final char[] out = new char[len << 1];//len*2
// two characters from the hex value.
for (int i = 0, j = 0; i < len; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];// 高位
out[j++] = toDigits[0x0F & data[i]];// 低位
}
return out;
}
/**
* 将十六进制字符转换成一个整数
*
* @param ch 十六进制char
* @param index 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException 当ch不是一个合法的十六进制字符时抛出运行时异常
*/
private static int toDigit(char ch, int index) {
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index);
}
return digit;
}
// ---------------------------------------------------------------------------------------- Private method end
}

View File

@@ -0,0 +1,283 @@
package cn.keking.hutool;
import java.nio.charset.Charset;
/**
* 字符串工具类
*
* @author xiaoleilu
*
*/
public class StrUtil {
public static final String EMPTY = "";
/**
* 是否空白符<br>
* 空白符包括空格、制表符、全角空格和不间断空格<br>
*
* @see Character#isWhitespace(int)
* @see Character#isSpaceChar(int)
* @param c 字符
* @return 是否空白符
* @since 4.0.10
*/
public static boolean isBlankChar(int c) {
return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == '\ufeff' || c == '\u202a';
}
/**
* 是否空白符<br>
* 空白符包括空格、制表符、全角空格和不间断空格<br>
*
* @param c 字符
* @return 是否空白符
* @see Character#isWhitespace(int)
* @see Character#isSpaceChar(int)
* @since 4.0.10
*/
public static boolean isBlankChar(char c) {
return isBlankChar((int) c);
}
/**
* 字符串是否为空白 空白的定义如下: <br>
* 1、为null <br>
* 2、为不可见字符如空格<br>
* 3、""<br>
*
* @param str 被检测的字符串
* @return 是否为空
*/
public static boolean isBlank(CharSequence str) {
int length;
if ((str == null) || ((length = str.length()) == 0)) {
return true;
}
for (int i = 0; i < length; i++) {
// 只要有一个非空字符即为非空字符串
if (false == isBlankChar(str.charAt(i))) {
return false;
}
}
return true;
}
/**
* 字符串是否为空,空的定义如下:<br>
* 1、为null <br>
* 2、为""<br>
*
* @param str 被检测的字符串
* @return 是否为空
*/
public static boolean isEmpty(CharSequence str) {
return str == null || str.length() == 0;
}
/**
* 编码字符串
*
* @param str 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 编码后的字节码
*/
public static byte[] bytes(CharSequence str, Charset charset) {
if (str == null) {
return null;
}
if (null == charset) {
return str.toString().getBytes();
}
return str.toString().getBytes(charset);
}
/**
* {@link CharSequence} 转为字符串null安全
*
* @param cs {@link CharSequence}
* @return 字符串
*/
public static String str(CharSequence cs) {
return null == cs ? null : cs.toString();
}
/**
* 解码字节码
*
* @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
public static String str(byte[] data, Charset charset) {
if (data == null) {
return null;
}
if (null == charset) {
return new String(data);
}
return new String(data, charset);
}
/**
* 改进JDK subString<br>
* index从0开始计算最后一个字符为-1<br>
* 如果from和to位置一样返回 "" <br>
* 如果from或to为负数则按照length从后向前数位置如果绝对值大于字符串长度则from归到0to归到length<br>
* 如果经过修正的index中from大于to则互换from和to example: <br>
* abcdefgh 2 3 =》 c <br>
* abcdefgh 2 -3 =》 cde <br>
*
* @param str String
* @param fromIndex 开始的index包括
* @param toIndex 结束的index不包括
* @return 字串
*/
public static String sub(CharSequence str, int fromIndex, int toIndex) {
if (isEmpty(str)) {
return str(str);
}
int len = str.length();
if (fromIndex < 0) {
fromIndex = len + fromIndex;
if (fromIndex < 0) {
fromIndex = 0;
}
} else if (fromIndex > len) {
fromIndex = len;
}
if (toIndex < 0) {
toIndex = len + toIndex;
if (toIndex < 0) {
toIndex = len;
}
} else if (toIndex > len) {
toIndex = len;
}
if (toIndex < fromIndex) {
int tmp = fromIndex;
fromIndex = toIndex;
toIndex = tmp;
}
if (fromIndex == toIndex) {
return EMPTY;
}
return str.toString().substring(fromIndex, toIndex);
}
/**
* 切割指定位置之前部分的字符串
*
* @param string 字符串
* @param toIndex 切割到的位置(不包括)
* @return 切割后的剩余的前半部分字符串
*/
public static String subPre(CharSequence string, int toIndex) {
return sub(string, 0, toIndex);
}
/**
* 切割指定位置之后部分的字符串
*
* @param string 字符串
* @param fromIndex 切割开始的位置(包括)
* @return 切割后后剩余的后半部分字符串
*/
public static String subSuf(CharSequence string, int fromIndex) {
if (isEmpty(string)) {
return null;
}
return sub(string, fromIndex, string.length());
}
/**
* 指定范围内查找指定字符
*
* @param str 字符串
* @param searchChar 被查找的字符
* @param start 起始位置如果小于0从0开始查找
* @param end 终止位置如果超过str.length()则默认查找到字符串末尾
* @return 位置
*/
public static int indexOf(final CharSequence str, char searchChar, int start, int end) {
final int len = str.length();
if (start < 0 || start > len) {
start = 0;
}
if (end > len || end < 0) {
end = len;
}
for (int i = start; i < end; i++) {
if (str.charAt(i) == searchChar) {
return i;
}
}
return -1;
}
/**
* 指定范围内查找指定字符
*
* @param str 字符串
* @param searchChar 被查找的字符
* @param start 起始位置如果小于0从0开始查找
* @return 位置
*/
public static int indexOf(final CharSequence str, char searchChar, int start) {
if (str instanceof String) {
return ((String) str).indexOf(searchChar, start);
} else {
return indexOf(str, searchChar, start, -1);
}
}
/**
* 指定范围内查找指定字符
*
* @param str 字符串
* @param searchChar 被查找的字符
* @return 位置
*/
public static int indexOf(final CharSequence str, char searchChar) {
return indexOf(str, searchChar, 0);
}
/**
* 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。
*
* <pre>
* nullToDefault(null, &quot;default&quot;) = &quot;default&quot;
* nullToDefault(&quot;&quot;, &quot;default&quot;) = &quot;&quot;
* nullToDefault(&quot; &quot;, &quot;default&quot;) = &quot; &quot;
* nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;
* </pre>
*
* @param str 要转换的字符串
* @param defaultStr 默认字符串
*
* @return 字符串本身或指定的默认字符串
*/
public static String nullToDefault(CharSequence str, String defaultStr) {
return (str == null) ? defaultStr : str.toString();
}
/**
* 当给定字符串为null时转换为Empty
*
* @param str 被转换的字符串
* @return 转换后的字符串
*/
public static String nullToEmpty(CharSequence str) {
return nullToDefault(str, EMPTY);
}
}

View File

@@ -0,0 +1,232 @@
package cn.keking.hutool;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.BitSet;
/**
* URL编码数据内容的类型是 application/x-www-form-urlencoded。
*
* <pre>
* 1.字符"a"-"z""A"-"Z""0"-"9"".""-""*",和"_" 都不会被编码;
* 2.将空格转换为%20 ;
* 3.将非文本内容转换成"%xy"的形式,xy是两位16进制的数值;
* 4.在每个 name=value 对之间放置 &amp; 符号。
* </pre>
*
* @author looly,
*
*/
public class URLEncoder implements Serializable{
private static final long serialVersionUID = 1L;
// --------------------------------------------------------------------------------------------- Static method start
/**
* 默认{@link URLEncoder}<br>
* 默认的编码器针对URI路径编码定义如下
*
* <pre>
* pchar = unreserved不处理 / pct-encoded / sub-delims子分隔符 / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&amp;" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
* </pre>
*/
public static final URLEncoder DEFAULT = createDefault();
/**
* 用于查询语句的{@link URLEncoder}<br>
* 编码器针对URI路径编码定义如下
*
* <pre>
* 0x20 ' ' =》 '+'
* 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
* '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' Also '=' and '&amp;' 不编码
* 其它编码为 %nn 形式
* </pre>
*
* 详细见https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
*/
public static final URLEncoder QUERY = createQuery();
/**
* 创建默认{@link URLEncoder}<br>
* 默认的编码器针对URI路径编码定义如下
*
* <pre>
* pchar = unreserved不处理 / pct-encoded / sub-delims子分隔符 / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&amp;" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
* </pre>
*
* @return {@link URLEncoder}
*/
public static URLEncoder createDefault() {
final URLEncoder encoder = new URLEncoder();
encoder.addSafeCharacter('-');
encoder.addSafeCharacter('.');
encoder.addSafeCharacter('_');
encoder.addSafeCharacter('~');
// Add the sub-delims
encoder.addSafeCharacter('!');
encoder.addSafeCharacter('$');
encoder.addSafeCharacter('&');
encoder.addSafeCharacter('\'');
encoder.addSafeCharacter('(');
encoder.addSafeCharacter(')');
encoder.addSafeCharacter('*');
encoder.addSafeCharacter('+');
encoder.addSafeCharacter(',');
encoder.addSafeCharacter(';');
encoder.addSafeCharacter('=');
// Add the remaining literals
encoder.addSafeCharacter(':');
encoder.addSafeCharacter('@');
// Add '/' so it isn't encoded when we encode a path
encoder.addSafeCharacter('/');
return encoder;
}
/**
* 创建用于查询语句的{@link URLEncoder}<br>
* 编码器针对URI路径编码定义如下
*
* <pre>
* 0x20 ' ' =》 '+'
* 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
* '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z' Also '=' and '&amp;' 不编码
* 其它编码为 %nn 形式
* </pre>
*
* 详细见https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
*
* @return {@link URLEncoder}
*/
public static URLEncoder createQuery() {
final URLEncoder encoder = new URLEncoder();
// Special encoding for space
encoder.setEncodeSpaceAsPlus(true);
// Alpha and digit are safe by default
// Add the other permitted characters
encoder.addSafeCharacter('*');
encoder.addSafeCharacter('-');
encoder.addSafeCharacter('.');
encoder.addSafeCharacter('_');
encoder.addSafeCharacter('=');
encoder.addSafeCharacter('&');
return encoder;
}
// --------------------------------------------------------------------------------------------- Static method end
/** 存放安全编码 */
private final BitSet safeCharacters;
/** 是否编码空格为+ */
private boolean encodeSpaceAsPlus = false;
/**
* 构造<br>
*
* [a-zA-Z0-9]默认不被编码
*/
public URLEncoder() {
this(new BitSet(256));
for (char i = 'a'; i <= 'z'; i++) {
addSafeCharacter(i);
}
for (char i = 'A'; i <= 'Z'; i++) {
addSafeCharacter(i);
}
for (char i = '0'; i <= '9'; i++) {
addSafeCharacter(i);
}
}
/**
* 构造
*
* @param safeCharacters 安全字符,安全字符不被编码
*/
private URLEncoder(BitSet safeCharacters) {
this.safeCharacters = safeCharacters;
}
/**
* 增加安全字符<br>
* 安全字符不被编码
*
* @param c 字符
*/
public void addSafeCharacter(char c) {
safeCharacters.set(c);
}
/**
* 移除安全字符<br>
* 安全字符不被编码
*
* @param c 字符
*/
public void removeSafeCharacter(char c) {
safeCharacters.clear(c);
}
/**
* 是否将空格编码为+
*
* @param encodeSpaceAsPlus 是否将空格编码为+
*/
public void setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) {
this.encodeSpaceAsPlus = encodeSpaceAsPlus;
}
/**
* 将URL中的字符串编码为%形式
*
* @param path 需要编码的字符串
* @param charset 编码
*
* @return 编码后的字符串
*/
public String encode(String path, Charset charset) {
int maxBytesPerChar = 10;
final StringBuilder rewrittenPath = new StringBuilder(path.length());
ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
OutputStreamWriter writer = new OutputStreamWriter(buf, charset);
int c;
for (int i = 0; i < path.length(); i++) {
c = path.charAt(i);
if (safeCharacters.get(c)) {
rewrittenPath.append((char) c);
} else if (encodeSpaceAsPlus && c == ' ') {
// 对于空格单独处理
rewrittenPath.append('+');
} else {
// convert to external encoding before hex conversion
try {
writer.write((char) c);
writer.flush();
} catch (IOException e) {
buf.reset();
continue;
}
byte[] ba = buf.toByteArray();
for (int j = 0; j < ba.length; j++) {
// Converting each byte in the buffer
byte toEncode = ba[j];
rewrittenPath.append('%');
HexUtil.appendHex(rewrittenPath, toEncode, false);
}
buf.reset();
}
}
return rewrittenPath.toString();
}
}

View File

@@ -0,0 +1,74 @@
package cn.keking.hutool;
import java.nio.charset.StandardCharsets;
/**
* 统一资源定位符相关工具类
*
* @author xiaoleilu
*
*/
public class URLUtil {
/**
* 标准化URL字符串包括
*
* <pre>
* 1. 多个/替换为一个
* </pre>
*
* @param url URL字符串
* @return 标准化后的URL字符串
*/
public static String normalize(String url) {
return normalize(url, false, false);
}
/**
* 标准化URL字符串包括
*
* <pre>
* 1. 多个/替换为一个
* </pre>
*
* @param url URL字符串
* @param isEncodeBody 是否对URL中body部分的中文和特殊字符做转义不包括http:和/
* @param isEncodeParam 是否对URL中参数部分的中文和特殊字符做转义
* @return 标准化后的URL字符串
* @since 4.4.1
*/
public static String normalize(String url, boolean isEncodeBody, boolean isEncodeParam) {
if (StrUtil.isBlank(url)) {
return url;
}
final int sepIndex = url.indexOf("://");
String pre;
String body;
if (sepIndex > 0) {
pre = StrUtil.subPre(url, sepIndex + 3);
body = StrUtil.subSuf(url, sepIndex + 3);
} else {
pre = "http://";
body = url;
}
final int paramsSepIndex = StrUtil.indexOf(body, '?');
String params = null;
if (paramsSepIndex > 0) {
params = StrUtil.subSuf(body, paramsSepIndex + 1);
body = StrUtil.subPre(body, paramsSepIndex);
}
// 去除开头的\或者/
body = body.replaceAll("^[\\\\/]+", StrUtil.EMPTY);
// 替换多个\或/为单个/
body = body.replace("\\", "/").replaceAll("//+", "/");
if (isEncodeBody) {
body = URLEncoder.DEFAULT.encode(body, StandardCharsets.UTF_8);
if (params != null) {
params = "?" + URLEncoder.DEFAULT.encode(params, StandardCharsets.UTF_8);
}
}
return pre + body + StrUtil.nullToEmpty(params);
}
}

View File

@@ -1,7 +1,5 @@
package cn.keking.model;
import cn.keking.config.ConfigConstants;
/**
* Created by kl on 2018/1/17.
* Content :
@@ -9,11 +7,12 @@ import cn.keking.config.ConfigConstants;
public class FileAttribute {
private FileType type;
private String suffix;
private String name;
private String url;
private String fileKey;
private String officePreviewType = ConfigConstants.getOfficePreviewType();
public FileAttribute() {
}
@@ -25,30 +24,6 @@ public class FileAttribute {
this.url = url;
}
public FileAttribute(FileType type, String suffix, String name, String url, String officePreviewType) {
this.type = type;
this.suffix = suffix;
this.name = name;
this.url = url;
this.officePreviewType = officePreviewType;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getOfficePreviewType() {
return officePreviewType;
}
public void setOfficePreviewType(String officePreviewType) {
this.officePreviewType = officePreviewType;
}
public FileType getType() {
return type;
}

View File

@@ -0,0 +1,29 @@
package cn.keking.model;
/**
* Created by kl on 2018/1/17.
* Content :文件类型文本office压缩包等等
*/
public enum FileType {
picture("picturefilepreviewimpl"),
compress("compressFilePreviewImpl"),
office("officeFilePreviewImpl"),
simText("simTextFilePreviewImpl"),
pdf("pdfFilePreviewImpl"),
other("otherFilePreviewImpl"),
media("mediaFilePreviewImpl"),
markdown("markdownFilePreviewImpl"),
cad("cadFilePreviewImpl");
private final String instanceName;
FileType(String instanceName){
this.instanceName=instanceName;
}
public String getInstanceName() {
return instanceName;
}
}

View File

@@ -4,18 +4,11 @@ import java.io.Serializable;
/**
* 接口返回值结构
*
* @author yudian-it
* @date 2017/11/17
*/
public class ReturnResponse<T> implements Serializable {
public class ReturnResponse<T> implements Serializable{
private static final long serialVersionUID = 313975329998789878L;
public static final int SUCCESS_CODE = 0;
public static final int FAILURE_CODE = 1;
public static final String SUCCESS_MSG = "SUCCESS";
public static final String FAILURE_MSG = "FAILURE";
/**
* 返回状态
* 0. 成功
@@ -38,30 +31,6 @@ public class ReturnResponse<T> implements Serializable {
this.content = content;
}
public static ReturnResponse<Object> failure(String errMsg) {
return new ReturnResponse<>(FAILURE_CODE, errMsg, null);
}
public static ReturnResponse<Object> failure() {
return failure(FAILURE_MSG);
}
public static ReturnResponse<Object> success(){
return success(null);
}
public static ReturnResponse<Object> success(Object content) {
return new ReturnResponse<>(SUCCESS_CODE, SUCCESS_MSG, content);
}
public boolean isSuccess(){
return SUCCESS_CODE == code;
}
public boolean isFailure(){
return !isSuccess();
}
public int getCode() {
return code;
}

View File

@@ -3,6 +3,7 @@ package cn.keking.service;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@@ -10,7 +11,6 @@ import org.springframework.ui.ExtendedModelMap;
import javax.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Created by kl on 2018/1/19.
@@ -20,36 +20,44 @@ import java.util.concurrent.TimeUnit;
public class FileConvertQueueTask {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final FilePreviewFactory previewFactory;
private final CacheService cacheService;
private final FileHandlerService fileHandlerService;
public FileConvertQueueTask(FilePreviewFactory previewFactory, CacheService cacheService, FileHandlerService fileHandlerService) {
private final FilePreviewFactory previewFactory;
private final CacheService cacheService;
private final FileUtils fileUtils;
public FileConvertQueueTask(FilePreviewFactory previewFactory,
CacheService cacheService,
FileUtils fileUtils) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileHandlerService = fileHandlerService;
this.fileUtils=fileUtils;
}
@PostConstruct
public void startTask(){
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(new ConvertTask(previewFactory, cacheService, fileHandlerService));
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new ConvertTask(previewFactory, cacheService, fileUtils));
logger.info("队列处理文件转换任务启动完成 ");
}
static class ConvertTask implements Runnable {
private final Logger logger = LoggerFactory.getLogger(ConvertTask.class);
private final FilePreviewFactory previewFactory;
private final CacheService cacheService;
private final FileHandlerService fileHandlerService;
private final FileUtils fileUtils;
public ConvertTask(FilePreviewFactory previewFactory,
CacheService cacheService,
FileHandlerService fileHandlerService) {
FileUtils fileUtils) {
this.previewFactory = previewFactory;
this.cacheService = cacheService;
this.fileHandlerService = fileHandlerService;
this.fileUtils=fileUtils;
}
@Override
@@ -59,10 +67,10 @@ public class FileConvertQueueTask {
try {
url = cacheService.takeQueueTask();
if(url != null){
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url,null);
FileAttribute fileAttribute = fileUtils.getFileAttribute(url);
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 {
@@ -71,7 +79,7 @@ public class FileConvertQueueTask {
}
} catch (Exception e) {
try {
TimeUnit.SECONDS.sleep(10);
Thread.sleep(1000*10);
} catch (Exception ex){
ex.printStackTrace();
}

View File

@@ -0,0 +1,12 @@
package cn.keking.service;
import cn.keking.model.FileAttribute;
import org.springframework.ui.Model;
/**
* Created by kl on 2018/1/17.
* Content :
*/
public interface FilePreview {
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
}

View File

@@ -5,10 +5,7 @@ import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.Weighers;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
@@ -24,78 +21,15 @@ import java.util.concurrent.BlockingQueue;
public class CacheServiceJDKImpl implements CacheService {
private Map<String, String> pdfCache;
private Map<String, List<String>> imgCache;
private Map<String, Integer> pdfImagesCache;
private static final int QUEUE_SIZE = 500000;
private final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
@PostConstruct
public void initCache(){
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
@Override
public void putPDFCache(String key, String value) {
pdfCache.put(key, value);
}
@Override
public void putImgCache(String key, List<String> value) {
imgCache.put(key, value);
}
@Override
public Map<String, String> getPDFCache() {
return pdfCache;
}
@Override
public String getPDFCache(String key) {
return pdfCache.get(key);
}
@Override
public Map<String, List<String>> getImgCache() {
return imgCache;
}
@Override
public List<String> getImgCache(String key) {
if(StringUtils.isEmpty(key)){
return new ArrayList<>();
}
return imgCache.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
return pdfImagesCache.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
pdfImagesCache.put(pdfFilePath, num);
}
@Override
public void cleanCache() {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);
}
@Override
public String takeQueueTask() throws InterruptedException {
return blockingQueue.take();
}
@Override
public void initPDFCachePool(Integer capacity) {
pdfCache = new ConcurrentLinkedHashMap.Builder<String, String>()
@@ -116,4 +50,85 @@ public class CacheServiceJDKImpl implements CacheService {
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
.build();
}
@Override
public void putPDFCache(String key, String value) {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
pdfCache.put(key, value);
}
@Override
public void putImgCache(String key, List<String> value) {
if (imgCache == null) {
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
imgCache.put(key, value);
}
@Override
public Map<String, String> getPDFCache() {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
return pdfCache;
}
@Override
public String getPDFCache(String key) {
if (pdfCache == null) {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
}
return pdfCache.get(key);
}
@Override
public Map<String, List<String>> getImgCache() {
if (imgCache == null) {
initPDFCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
return imgCache;
}
@Override
public List<String> getImgCache(String key) {
if (imgCache == null) {
initPDFCachePool(CacheService.DEFAULT_IMG_CAPACITY);
}
return imgCache.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
return pdfImagesCache.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
pdfImagesCache.put(pdfFilePath, num);
}
@Override
public void cleanCache() {
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);
}
@Override
public String takeQueueTask() throws InterruptedException {
return blockingQueue.take();
}
}

View File

@@ -28,11 +28,19 @@ public class CacheServiceRedisImpl implements CacheService {
}
@Override
public void initPDFCachePool(Integer capacity) { }
public void initPDFCachePool(Integer capacity) {
}
@Override
public void initIMGCachePool(Integer capacity) { }
public void initIMGCachePool(Integer capacity) {
}
@Override
public void initPdfImagesCachePool(Integer capacity) { }
public void initPdfImagesCachePool(Integer capacity) {
}
@Override
public void putPDFCache(String key, String value) {

View File

@@ -1,7 +1,7 @@
package cn.keking.service.cache.impl;
import cn.keking.service.cache.CacheService;
import org.artofsolving.jodconverter.util.ConfigUtils;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import org.slf4j.Logger;
@@ -30,9 +30,12 @@ public class CacheServiceRocksDBImpl implements CacheService {
RocksDB.loadLibrary();
}
private static final String DB_PATH = ConfigUtils.getHomePath() + File.separator + "cache";
private static final String DB_PATH = OfficeUtils.getHomePath() + File.separator + "cache";
private static final int QUEUE_SIZE = 500000;
private static final Logger LOGGER = LoggerFactory.getLogger(CacheServiceRocksDBImpl.class);
private final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
private RocksDB db;

View File

@@ -4,8 +4,10 @@ import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.CadUtils;
import cn.keking.utils.DownloadUtils;
import cn.keking.service.FileHandlerService;
import cn.keking.utils.FileUtils;
import cn.keking.utils.PdfUtils;
import cn.keking.web.filter.BaseUrlFilter;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
@@ -20,50 +22,67 @@ import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
@Service
public class CadFilePreviewImpl implements FilePreview {
private final FileUtils fileUtils;
private final DownloadUtils downloadUtils;
private final CadUtils cadUtils;
private final PdfUtils pdfUtils;
public CadFilePreviewImpl(FileUtils fileUtils,
DownloadUtils downloadUtils,
CadUtils cadUtils,
PdfUtils pdfUtils) {
this.fileUtils = fileUtils;
this.downloadUtils = downloadUtils;
this.cadUtils = cadUtils;
this.pdfUtils = pdfUtils;
}
private static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
private static final String FILE_DIR = ConfigConstants.getFileDir();
private final FileHandlerService fileHandlerService;
private final OtherFilePreviewImpl otherFilePreview;
public CadFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
this.fileHandlerService = fileHandlerService;
this.otherFilePreview = otherFilePreview;
}
@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 suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
String outFilePath = FILE_DIR + pdfName;
// 判断之前是否已转换过如果转换过直接返回否则执行转换
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
if (!fileUtils.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
String filePath;
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
if (response.isFailure()) {
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
filePath = response.getContent();
if (StringUtils.hasText(outFilePath)) {
boolean convertResult = fileHandlerService.cadToPdf(filePath, outFilePath);
boolean convertResult = cadUtils.cadToPdf(filePath, outFilePath);
if (!convertResult) {
return otherFilePreview.notSupportedFile(model, fileAttribute, "cad文件转换异常请联系管理员");
model.addAttribute("fileType", suffix);
model.addAttribute("msg", "cad文件转换异常请联系管理员");
return "fileNotSupported";
}
if (ConfigConstants.isCacheEnabled()) {
// 加入缓存
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
}
}
}
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview);
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, pdfUtils, OFFICE_PREVIEW_TYPE_IMAGE);
}
model.addAttribute("pdfUrl", pdfName);
return PDF_FILE_PREVIEW_PAGE;
return "pdf";
}

View File

@@ -0,0 +1,71 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.ZipReader;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
/**
* Created by kl on 2018/1/17.
* Content :处理压缩包文件
*/
@Service
public class CompressFilePreviewImpl implements FilePreview {
private final FileUtils fileUtils;
private final DownloadUtils downloadUtils;
private final ZipReader zipReader;
public CompressFilePreviewImpl(FileUtils fileUtils,
DownloadUtils downloadUtils,
ZipReader zipReader) {
this.fileUtils = fileUtils;
this.downloadUtils = downloadUtils;
this.zipReader = zipReader;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileName=fileAttribute.getName();
String suffix=fileAttribute.getSuffix();
String fileTree = null;
// 判断文件名是否存在(redis缓存读取)
if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) {
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
String filePath = response.getContent();
if ("zip".equalsIgnoreCase(suffix) || "jar".equalsIgnoreCase(suffix) || "gzip".equalsIgnoreCase(suffix)) {
fileTree = zipReader.readZipFile(filePath, fileName);
} else if ("rar".equalsIgnoreCase(suffix)) {
fileTree = zipReader.unRar(filePath, fileName);
} else if ("7z".equalsIgnoreCase(suffix)) {
fileTree = zipReader.read7zFile(filePath, fileName);
}
if (fileTree != null && !"null".equals(fileTree) && ConfigConstants.isCacheEnabled()) {
fileUtils.addConvertedFile(fileName, fileTree);
}
} else {
fileTree = fileUtils.getConvertedFile(fileName);
}
if (fileTree != null && !"null".equals(fileTree)) {
model.addAttribute("fileTree", fileTree);
return "compress";
} else {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", "压缩文件类型不受支持尝试在压缩的时候选择RAR4格式");
return "fileNotSupported";
}
}
}

View File

@@ -21,7 +21,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("markdown","true");
return simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
}
}

View File

@@ -4,11 +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.service.FileHandlerService;
import cn.keking.utils.FileUtils;
import cn.keking.web.filter.BaseUrlFilter;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
/**
* @author : kl
* @authorboke : kailing.pub
@@ -18,29 +17,37 @@ import org.springframework.ui.Model;
@Service
public class MediaFilePreviewImpl implements FilePreview {
private final FileHandlerService fileHandlerService;
private final OtherFilePreviewImpl otherFilePreview;
private final DownloadUtils downloadUtils;
public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
this.fileHandlerService = fileHandlerService;
this.otherFilePreview = otherFilePreview;
private final FileUtils fileUtils;
public MediaFilePreviewImpl(DownloadUtils downloadUtils,
FileUtils fileUtils) {
this.downloadUtils = downloadUtils;
this.fileUtils = fileUtils;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
// 不是http开头浏览器不能直接访问需下载到本地
if (url != null && !url.toLowerCase().startsWith("http")) {
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
if (response.isFailure()) {
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileAttribute.getName());
if (0 != response.getCode()) {
model.addAttribute("fileType", fileAttribute.getSuffix());
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
} else {
model.addAttribute("mediaUrl", BaseUrlFilter.getBaseUrl() + fileHandlerService.getRelativePath(response.getContent()));
model.addAttribute("mediaUrl", BaseUrlFilter.getBaseUrl() + fileUtils.getRelativePath(response.getContent()));
}
} else {
model.addAttribute("mediaUrl", url);
}
model.addAttribute("mediaUrl", url);
return MEDIA_FILE_PREVIEW_PAGE;
String suffix=fileAttribute.getSuffix();
if ("flv".equalsIgnoreCase(suffix)) {
return "flv";
}
return "media";
}

View File

@@ -5,8 +5,9 @@ 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.OfficeToPdfService;
import cn.keking.utils.FileUtils;
import cn.keking.utils.OfficeToPdf;
import cn.keking.utils.PdfUtils;
import cn.keking.web.filter.BaseUrlFilter;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
@@ -21,68 +22,81 @@ import java.util.List;
@Service
public class OfficeFilePreviewImpl implements FilePreview {
private final FileUtils fileUtils;
private final PdfUtils pdfUtils;
private final DownloadUtils downloadUtils;
private final OfficeToPdf officeToPdf;
public OfficeFilePreviewImpl(FileUtils fileUtils,
PdfUtils pdfUtils,
DownloadUtils downloadUtils,
OfficeToPdf officeToPdf) {
this.fileUtils = fileUtils;
this.pdfUtils = pdfUtils;
this.downloadUtils = downloadUtils;
this.officeToPdf = officeToPdf;
}
public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
public static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
private static final String FILE_DIR = ConfigConstants.getFileDir();
private final FileHandlerService fileHandlerService;
private final OfficeToPdfService officeToPdfService;
private final OtherFilePreviewImpl otherFilePreview;
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
this.fileHandlerService = fileHandlerService;
this.officeToPdfService = officeToPdfService;
this.otherFilePreview = otherFilePreview;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
// 预览Type参数传了就取参数的没传取系统默认
String officePreviewType = fileAttribute.getOfficePreviewType();
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
String baseUrl = BaseUrlFilter.getBaseUrl();
String suffix = fileAttribute.getSuffix();
String fileName = fileAttribute.getName();
String suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx");
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
String outFilePath = FILE_DIR + pdfName;
model.addAttribute("switchDisabled", ConfigConstants.getOfficePreviewSwitchDisabled());
// 判断之前是否已转换过如果转换过直接返回否则执行转换
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
if (!fileUtils.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
String filePath;
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
if (response.isFailure()) {
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
filePath = response.getContent();
if (StringUtils.hasText(outFilePath)) {
officeToPdfService.openOfficeToPDF(filePath, outFilePath);
officeToPdf.openOfficeToPDF(filePath, outFilePath);
if (isHtml) {
// 对转换后的文件进行操作(改变编码方式)
fileHandlerService.doActionConvertedFile(outFilePath);
fileUtils.doActionConvertedFile(outFilePath);
}
if (ConfigConstants.isCacheEnabled()) {
// 加入缓存
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
fileUtils.addConvertedFile(pdfName, fileUtils.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, pdfName, outFilePath, pdfUtils, OFFICE_PREVIEW_TYPE_IMAGE);
}
model.addAttribute("pdfUrl", pdfName);
return isHtml ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
return isHtml ? "html" : "pdf";
}
static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String baseUrl, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
List<String> imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, baseUrl);
static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String baseUrl, String pdfName, String outFilePath, PdfUtils pdfUtils, String officePreviewTypeImage) {
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, baseUrl);
if (imageUrls == null || imageUrls.size() < 1) {
return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常请联系管理员");
model.addAttribute("msg", "office转图片异常请联系管理员");
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("imgurls", imageUrls);
model.addAttribute("currentUrl", imageUrls.get(0));
if (officePreviewTypeImage.equals(officePreviewType)) {
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
return "officePicture";
} else {
return PICTURE_FILE_PREVIEW_PAGE;
return "picture";
}
}
}

View File

@@ -0,0 +1,20 @@
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;
/**
* Created by kl on 2018/1/17.
* Content :其他文件
*/
@Service
public class OtherFilePreviewImpl implements FilePreview {
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
model.addAttribute("fileType",fileAttribute.getSuffix());
model.addAttribute("msg", "系统还不支持该格式文件的在线预览");
return "fileNotSupported";
}
}

View File

@@ -0,0 +1,100 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.PdfUtils;
import cn.keking.web.filter.BaseUrlFilter;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.util.List;
/**
* Created by kl on 2018/1/17.
* Content :处理pdf文件
*/
@Service
public class PdfFilePreviewImpl implements FilePreview {
private final FileUtils fileUtils;
private final PdfUtils pdfUtils;
private final DownloadUtils downloadUtils;
private static final String FILE_DIR = ConfigConstants.getFileDir();
public PdfFilePreviewImpl(FileUtils fileUtils,
PdfUtils pdfUtils,
DownloadUtils downloadUtils) {
this.fileUtils = fileUtils;
this.pdfUtils = pdfUtils;
this.downloadUtils = downloadUtils;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
String baseUrl = BaseUrlFilter.getBaseUrl();
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
String outFilePath = FILE_DIR + pdfName;
model.addAttribute("switchDisabled", ConfigConstants.getOfficePreviewSwitchDisabled());
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
//当文件不存在时,就去下载
if (!fileUtils.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
outFilePath = response.getContent();
if (ConfigConstants.isCacheEnabled()) {
// 加入缓存
fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
}
}
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, baseUrl);
if (imageUrls == null || imageUrls.size() < 1) {
model.addAttribute("msg", "pdf转图片异常请联系管理员");
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("imgurls", imageUrls);
model.addAttribute("currentUrl", imageUrls.get(0));
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
return "officePicture";
} else {
return "picture";
}
} else {
// 不是http开头浏览器不能直接访问需下载到本地
if (url != null && !url.toLowerCase().startsWith("http")) {
if (!fileUtils.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, pdfName);
if (0 != response.getCode()) {
model.addAttribute("fileType", suffix);
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
}
model.addAttribute("pdfUrl", fileUtils.getRelativePath(response.getContent()));
if (ConfigConstants.isCacheEnabled()) {
// 加入缓存
fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
}
} else {
model.addAttribute("pdfUrl", pdfName);
}
} else {
model.addAttribute("pdfUrl", url);
}
}
return "pdf";
}
}

View File

@@ -0,0 +1,62 @@
package cn.keking.service.impl;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.List;
/**
* Created by kl on 2018/1/17.
* Content :图片文件处理
*/
@Service
public class PictureFilePreviewImpl implements FilePreview {
private final FileUtils fileUtils;
private final DownloadUtils downloadUtils;
public PictureFilePreviewImpl(FileUtils fileUtils,
DownloadUtils downloadUtils) {
this.fileUtils = fileUtils;
this.downloadUtils = downloadUtils;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
String fileKey = (String) RequestContextHolder.currentRequestAttributes().getAttribute("fileKey",0);
List<String> imgUrls = Lists.newArrayList(url);
model.addAttribute("switchDisabled", ConfigConstants.getOfficePreviewSwitchDisabled());
try {
imgUrls.clear();
imgUrls.addAll(fileUtils.getImgCache(fileKey));
} catch (Exception e){
imgUrls = Lists.newArrayList(url);
}
// 不是http开头浏览器不能直接访问需下载到本地
if (url != null && !url.toLowerCase().startsWith("http")) {
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
if (0 != response.getCode()) {
model.addAttribute("fileType", fileAttribute.getSuffix());
model.addAttribute("msg", response.getMsg());
return "fileNotSupported";
} else {
String file = fileUtils.getRelativePath(response.getContent());
model.addAttribute("imgurls", Lists.newArrayList(file));
model.addAttribute("currentUrl", file);
}
} else {
model.addAttribute("imgurls", imgUrls);
model.addAttribute("currentUrl", url);
}
return "picture";
}
}

View File

@@ -0,0 +1,52 @@
package cn.keking.service.impl;
import cn.keking.model.FileAttribute;
import cn.keking.model.ReturnResponse;
import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
/**
* Created by kl on 2018/1/17.
* Content :处理文本文件
*/
@Service
public class SimTextFilePreviewImpl implements FilePreview {
private final DownloadUtils downloadUtils;
public SimTextFilePreviewImpl(DownloadUtils downloadUtils) {
this.downloadUtils = downloadUtils;
}
@Override
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute){
String fileName = fileAttribute.getName();
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
if (0 != response.getCode()) {
model.addAttribute("msg", response.getMsg());
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
try {
File originFile = new File(response.getContent());
File previewFile = new File(response.getContent() + ".txt");
if (previewFile.exists()) {
previewFile.delete();
}
Files.copy(originFile.toPath(), previewFile.toPath());
} catch (IOException e) {
model.addAttribute("msg", e.getLocalizedMessage());
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("ordinaryUrl", response.getMsg());
return "txt";
}
}

View File

@@ -0,0 +1,50 @@
package cn.keking.utils;
import com.aspose.cad.Color;
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
import com.aspose.cad.imageoptions.CadRasterizationOptions;
import com.aspose.cad.imageoptions.PdfOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* @author chenjhc
* @since 2019/11/21 14:34
*/
@Component
public class CadUtils {
private final Logger logger = LoggerFactory.getLogger(CadUtils.class);
public boolean cadToPdf(String inputFilePath, String outputFilePath) {
com.aspose.cad.Image cadImage = com.aspose.cad.Image.load(inputFilePath);
CadRasterizationOptions cadRasterizationOptions = new CadRasterizationOptions();
cadRasterizationOptions.setLayouts(new String[]{"Model"});
cadRasterizationOptions.setNoScaling(true);
cadRasterizationOptions.setBackgroundColor(Color.getWhite());
cadRasterizationOptions.setPageWidth(cadImage.getWidth());
cadRasterizationOptions.setPageHeight(cadImage.getHeight());
cadRasterizationOptions.setPdfProductLocation("center");
cadRasterizationOptions.setAutomaticLayoutsScaling(true);
cadRasterizationOptions.setDrawType(CadDrawTypeMode.UseObjectColor);
PdfOptions pdfOptions = new PdfOptions();
pdfOptions.setVectorRasterizationOptions(cadRasterizationOptions);
File outputFile = new File(outputFilePath);
OutputStream stream;
try {
stream = new FileOutputStream(outputFile);
cadImage.save(stream, pdfOptions);
cadImage.close();
return true;
} catch (FileNotFoundException e) {
logger.error("PDFFileNotFoundExceptioninputFilePath{}", inputFilePath, e);
return false;
}
}
}

View File

@@ -1,6 +1,7 @@
package cn.keking.service;
package cn.keking.utils;
import com.sun.star.document.UpdateDocMode;
import cn.keking.extend.ControlDocumentFormatRegistry;
import org.apache.commons.lang3.StringUtils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
@@ -8,10 +9,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;
import javax.annotation.PostConstruct;
@@ -21,11 +18,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;
@@ -36,29 +29,16 @@ import java.util.Properties;
* @date 2017/11/13
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OfficePluginManager {
public class ConverterUtils {
private final Logger logger = LoggerFactory.getLogger(OfficePluginManager.class);
private final Logger logger = LoggerFactory.getLogger(ConverterUtils.class);
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();
}
/**
* 启动Office组件进程
*/
private void startOfficeManager(){
File officeHome = OfficeUtils.getDefaultOfficeHome();
File officeHome;
officeHome = OfficeUtils.getDefaultOfficeHome();
if (officeHome == null) {
throw new RuntimeException("找不到office组件请确认'office.home'配置是否有误");
}
@@ -69,14 +49,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();
@@ -88,7 +63,7 @@ public class OfficePluginManager {
}
public OfficeDocumentConverter getDocumentConverter() {
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new OfficePluginExtendFormatRegistry());
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new ControlDocumentFormatRegistry());
converter.setDefaultLoadProperties(getLoadProperties());
return converter;
}

View File

@@ -0,0 +1,82 @@
package cn.keking.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Objects;
public class DeleteFileUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(DeleteFileUtil.class);
/**
* 删除单个文件
*
* @param fileName
* 要删除的文件的文件名
* @return 单个文件删除成功返回true否则返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
LOGGER.info("删除单个文件" + fileName + "成功!");
return true;
} else {
LOGGER.info("删除单个文件" + fileName + "失败!");
return false;
}
} else {
LOGGER.info("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
/**
* 删除目录及目录下的文件
*
* @param dir
* 要删除的目录的文件路径
* @return 目录删除成功返回true否则返回false
*/
public static boolean deleteDirectory(String dir) {
// 如果dir不以文件分隔符结尾自动添加文件分隔符
if (!dir.endsWith(File.separator)) {
dir = dir + File.separator;
}
File dirFile = new File(dir);
// 如果dir对应的文件不存在或者不是一个目录则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
LOGGER.info("删除目录失败:" + dir + "不存在!");
return false;
}
boolean flag = true;
// 删除文件夹中的所有文件包括子目录
File[] files = dirFile.listFiles();
for (int i = 0; i < Objects.requireNonNull(files).length; i++) {
// 删除子文件
if (files[i].isFile()) {
flag = DeleteFileUtil.deleteFile(files[i].getAbsolutePath());
if (!flag) {
break;
}
} else if (files[i].isDirectory()) {
// 删除子目录
flag = DeleteFileUtil.deleteDirectory(files[i].getAbsolutePath());
if (!flag) {
break;
}
}
}
dirFile.delete();
if (!flag) {
LOGGER.info("删除目录失败!");
return false;
}
return true;
}
}

View File

@@ -0,0 +1,176 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.hutool.URLUtil;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.model.ReturnResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* @author yudian-it
*/
@Component
public class DownloadUtils {
private final Logger logger = LoggerFactory.getLogger(DownloadUtils.class);
private final String fileDir = ConfigConstants.getFileDir();
private final FileUtils fileUtils;
public DownloadUtils(FileUtils fileUtils) {
this.fileUtils = fileUtils;
}
private static final String URL_PARAM_FTP_USERNAME = "ftp.username";
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
/**
* @param fileAttribute fileAttribute
* @param fileName 文件名
* @return 本地文件绝对路径
*/
public ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
String urlStr = fileAttribute.getUrl();
String type = fileAttribute.getSuffix();
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
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();
}
try {
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 = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
String ftpPassword = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
String ftpControlEncoding = fileUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
} else {
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 e) {
logger.error("文件下载失败url{}", urlStr, e);
response.setCode(1);
response.setContent(null);
if (e instanceof FileNotFoundException) {
response.setMsg("文件不存在!!!");
} else {
response.setMsg(e.getMessage());
}
return response;
}
}
public byte[] getBytesFromUrl(String urlStr) throws IOException {
InputStream is = getInputStreamFromUrl(urlStr);
if (is != null) {
return getBytesFromStream(is);
} else {
urlStr = URLUtil.normalize(urlStr, true, true);
is = getInputStreamFromUrl(urlStr);
if (is == null) {
logger.error("文件下载异常url{}", urlStr);
throw new IOException("文件下载异常url" + urlStr);
}
return getBytesFromStream(is);
}
}
public void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
os.write(b);
os.close();
}
private InputStream getInputStreamFromUrl(String urlStr) {
try {
URL url = new URL(urlStr);
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 e) {
logger.warn("连接url异常url{}", urlStr);
return null;
}
}
private byte[] getBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
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 = null;
try {
FileCharsetDetector.Observer observer = FileCharsetDetector.guessFileEncoding(sourceFile);
// 为准确探测到编码,不适用猜测的编码
encoding = observer.isFound()?observer.getEncoding():null;
// 为准确探测到编码,可以考虑使用GBK 大部分文件都是windows系统产生的
} catch (IOException e) {
// 编码探测失败,
e.printStackTrace();
}
if(encoding != null && !"UTF-8".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();
// 删除源文件
sourceFile.delete();
// 重命名
tmpUtf8File.renameTo(sourceFile);
}
}
}
}

View File

@@ -0,0 +1,157 @@
package cn.keking.utils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.mozilla.intl.chardet.nsDetector;
import org.mozilla.intl.chardet.nsICharsetDetectionObserver;
/**
* 文本文件编码探测工具类
*
* @author HWliao
* @date 2017-12-24
*/
public class FileCharsetDetector {
/**
* 传入一个文件(File)对象,检查文件编码
*
* @param file File对象实例
* @return 文件编码若无则返回null
* @throws FileNotFoundException
* @throws IOException
*/
public static Observer guessFileEncoding(File file)
throws FileNotFoundException, IOException {
return guessFileEncoding(file, new nsDetector());
}
/**
* <pre>
* 获取文件的编码
* @param file
* File对象实例
* @param languageHint
* 语言提示区域代码 @see #nsPSMDetector ,取值如下:
* 1 : Japanese
* 2 : Chinese
* 3 : Simplified Chinese
* 4 : Traditional Chinese
* 5 : Korean
* 6 : Dont know(default)
* </pre>
*
* @return 文件编码egUTF-8,GBK,GB2312形式(不确定的时候,返回可能的字符编码序列)若无则返回null
* @throws FileNotFoundException
* @throws IOException
*/
public static Observer guessFileEncoding(File file, int languageHint)
throws FileNotFoundException, IOException {
return guessFileEncoding(file, new nsDetector(languageHint));
}
/**
* 获取文件的编码
*
* @param file
* @param det
* @return
* @throws FileNotFoundException
* @throws IOException
*/
private static Observer guessFileEncoding(File file, nsDetector det)
throws FileNotFoundException, IOException {
// new Observer
Observer observer = new Observer();
// set Observer
// The Notify() will be called when a matching charset is found.
det.Init(observer);
BufferedInputStream imp = new BufferedInputStream(new FileInputStream(
file));
byte[] buf = new byte[1024];
int len;
boolean done = false;
boolean isAscii = false;
while ((len = imp.read(buf, 0, buf.length)) != -1) {
// Check if the stream is only ascii.
isAscii = det.isAscii(buf, len);
if (isAscii) {
break;
}
// DoIt if non-ascii and not done yet.
done = det.DoIt(buf, len, false);
if (done) {
break;
}
}
imp.close();
det.DataEnd();
if (isAscii) {
observer.encoding = "ASCII";
observer.found = true;
}
if (!observer.isFound()) {
String[] prob = det.getProbableCharsets();
// // 这里将可能的字符集组合起来返回
// for (int i = 0; i < prob.length; i++) {
// if (i == 0) {
// encoding = prob[i];
// } else {
// encoding += "," + prob[i];
// }
// }
if (prob.length > 0) {
// 在没有发现情况下,去第一个可能的编码
observer.encoding = prob[0];
} else {
observer.encoding = null;
}
}
return observer;
}
/**
* @author liaohongwei
* @Description: 文件字符编码观察者, 但判断出字符编码时候调用
* @date 2016年6月20日 下午2:27:06
*/
public static class Observer implements nsICharsetDetectionObserver {
/**
* @Fields encoding : 字符编码
*/
private String encoding = null;
/**
* @Fields found : 是否找到字符集
*/
private boolean found = false;
@Override
public void Notify(String charset) {
this.encoding = charset;
this.found = true;
}
public String getEncoding() {
return encoding;
}
public boolean isFound() {
return found;
}
@Override
public String toString() {
return "Observer [encoding=" + encoding + ", found=" + found + "]";
}
}
}

View File

@@ -0,0 +1,339 @@
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileAttribute;
import cn.keking.model.FileType;
import cn.keking.service.cache.CacheService;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author yudian-it
* @date 2017/11/13
*/
@Component
public class FileUtils {
private static final String DEFAULT_CONVERTER_CHARSET = System.getProperty("sun.jnu.encoding");
private final String fileDir = ConfigConstants.getFileDir();
private final CacheService cacheService;
public FileUtils(CacheService cacheService) {
this.cacheService = cacheService;
}
/**
* @return 已转换过的文件集合(缓存)
*/
public Map<String, String> listConvertedFiles() {
return cacheService.getPDFCache();
}
/**
* @return 已转换过的文件,根据文件名获取
*/
public String getConvertedFile(String key) {
return cacheService.getPDFCache(key);
}
/**
* @param key pdf本地路径
* @return 已将pdf转换成图片的图片本地相对路径
*/
public Integer getConvertedPdfImage(String key) {
return cacheService.getPdfImageCache(key);
}
/**
* 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
*
* @param url url
* @return 文件类型
*/
public FileType typeFromUrl(String url) {
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
return typeFromFileName(fileName);
}
private FileType typeFromFileName(String fileName) {
String[] simText = ConfigConstants.getSimText();
String[] media = ConfigConstants.getMedia();
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
if (listPictureTypes().contains(fileType.toLowerCase())) {
return FileType.picture;
}
if (listArchiveTypes().contains(fileType.toLowerCase())) {
return FileType.compress;
}
if (listOfficeTypes().contains(fileType.toLowerCase())) {
return FileType.office;
}
if("md".equalsIgnoreCase(fileType)){
return FileType.markdown;
}
if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
return FileType.simText;
}
if (Arrays.asList(media).contains(fileType.toLowerCase())) {
return FileType.media;
}
if ("pdf".equalsIgnoreCase(fileType)) {
return FileType.pdf;
}
if ("dwg".equalsIgnoreCase(fileType)) {
return FileType.cad;
}
return FileType.other;
}
/**
* 从url中剥离出文件名
* @param url
* 格式如http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k=
* @return 文件名
*/
public String getFileNameFromURL(String url) {
// 因为url的参数中可能会存在/的情况所以直接url.lastIndexOf("/")会有问题
// 所以先从处将url截断然后运用url.lastIndexOf("/")获取文件名
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?"): url.length());
return noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1);
}
/**
* 从路径中获取文件负
* @param path
* 类似这种C:\Users\yudian-it\Downloads
* @return 文件名
*/
public String getFileNameFromPath(String path) {
return path.substring(path.lastIndexOf(File.separator) + 1);
}
public List<String> listPictureTypes(){
List<String> list = Lists.newArrayList();
list.add("jpg");
list.add("jpeg");
list.add("png");
list.add("gif");
list.add("bmp");
list.add("ico");
list.add("RAW");
return list;
}
public List<String> listArchiveTypes(){
List<String> list = Lists.newArrayList();
list.add("rar");
list.add("zip");
list.add("jar");
list.add("7-zip");
list.add("tar");
list.add("gzip");
list.add("7z");
return list;
}
public List<String> listOfficeTypes() {
List<String> list = Lists.newArrayList();
list.add("docx");
list.add("doc");
list.add("xls");
list.add("xlsx");
list.add("ppt");
list.add("pptx");
return list;
}
/**
* 获取相对路径
* @param absolutePath 绝对路径
* @return 相对路径
*/
public String getRelativePath(String absolutePath) {
return absolutePath.substring(fileDir.length());
}
/**
* 添加转换后PDF缓存
* @param fileName pdf文件名
* @param value 缓存相对路径
*/
public void addConvertedFile(String fileName, String value){
cacheService.putPDFCache(fileName, value);
}
/**
* 添加转换后图片组缓存
* @param pdfFilePath pdf文件绝对路径
* @param num 图片张数
*/
public void addConvertedPdfImage(String pdfFilePath, int num){
cacheService.putPdfImageCache(pdfFilePath, num);
}
/**
* 获取redis中压缩包内图片文件
* @param fileKey fileKey
* @return 图片文件访问url列表
*/
public List<String> getImgCache(String fileKey){
return cacheService.getImgCache(fileKey);
}
/**
* 设置redis中压缩包内图片文件
* @param fileKey fileKey
* @param imgs 图片文件访问url列表
*/
public void putImgCache(String fileKey,List<String> imgs){
cacheService.putImgCache(fileKey, imgs);
}
/**
* 判断文件编码格式
* @param path 绝对路径
* @return 编码格式
*/
public String getFileEncodeUTFGBK(String path){
String enc = Charset.forName("GBK").name();
File file = new File(path);
InputStream in;
try {
in = new FileInputStream(file);
byte[] b = new byte[3];
in.read(b);
in.close();
if (b[0] == -17 && b[1] == -69 && b[2] == -65) {
enc = StandardCharsets.UTF_8.name();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("文件编码格式为:" + enc);
return enc;
}
/**
* 对转换后的文件进行操作(改变编码方式)
* @param outFilePath 文件绝对路径
*/
public void doActionConvertedFile(String outFilePath) {
StringBuilder sb = new StringBuilder();
try (InputStream inputStream = new FileInputStream(outFilePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, DEFAULT_CONVERTER_CHARSET))){
String line;
while(null != (line = reader.readLine())){
if (line.contains("charset=gb2312")) {
line = line.replace("charset=gb2312", "charset=utf-8");
}
sb.append(line);
}
// 添加sheet控制头
sb.append("<script src=\"js/jquery-3.0.0.min.js\" type=\"text/javascript\"></script>");
sb.append("<script src=\"js/excel.header.js\" type=\"text/javascript\"></script>");
sb.append("<link rel=\"stylesheet\" href=\"bootstrap/css/bootstrap.min.css\">");
} catch (IOException e) {
e.printStackTrace();
}
// 重新写入文件
try(FileOutputStream fos = new FileOutputStream(outFilePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
writer.write(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取文件后缀
* @param url url
* @return 文件后缀
*/
private String suffixFromUrl(String url) {
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
return suffixFromFileName(fileName);
}
private String suffixFromFileName(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
/**
* 获取url中的参数
* @param url url
* @param name 参数名
* @return 参数值
*/
public String getUrlParameterReg(String url, String name) {
Map<String, String> mapRequest = new HashMap<>();
String strUrlParam = truncateUrlPage(url);
if (strUrlParam == null) {
return "";
}
//每个键值为一组
String[] arrSplit = strUrlParam.split("[&]");
for(String strSplit : arrSplit) {
String[] arrSplitEqual = strSplit.split("[=]");
//解析出键值
if(arrSplitEqual.length > 1) {
//正确解析
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
} else if (!arrSplitEqual[0].equals("")) {
//只有参数没有值,不加入
mapRequest.put(arrSplitEqual[0], "");
}
}
return mapRequest.get(name);
}
/**
* 去掉url中的路径留下请求参数部分
* @param strURL url地址
* @return url请求参数部分
*/
private String truncateUrlPage(String strURL) {
String strAllParam = null;
strURL = strURL.trim();
String[] arrSplit = strURL.split("[?]");
if(strURL.length() > 1) {
if(arrSplit.length > 1) {
if(arrSplit[1] != null) {
strAllParam=arrSplit[1];
}
}
}
return strAllParam;
}
/**
* 获取文件属性
* @param url url
* @return 文件属性
*/
public FileAttribute getFileAttribute(String url) {
String fileName;
FileType type;
String suffix;
String fullFileName = getUrlParameterReg(url, "fullfilename");
if (StringUtils.hasText(fullFileName)) {
fileName = fullFileName;
type = typeFromFileName(fileName);
suffix = suffixFromFileName(fileName);
} else {
fileName = getFileNameFromURL(url);
type = typeFromUrl(url);
suffix = suffixFromUrl(url);
}
return new FileAttribute(type,suffix,fileName,url);
}
}

View File

@@ -1,8 +1,6 @@
package cn.keking.service;
package cn.keking.utils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
@@ -11,13 +9,11 @@ import java.io.File;
* @author yudian-it
*/
@Component
public class OfficeToPdfService {
public class OfficeToPdf {
private final ConverterUtils converterUtils;
private final static Logger logger = LoggerFactory.getLogger(OfficeToPdfService.class);
private final OfficePluginManager officePluginManager;
public OfficeToPdfService(OfficePluginManager officePluginManager) {
this.officePluginManager = officePluginManager;
public OfficeToPdf(ConverterUtils converterUtils) {
this.converterUtils = converterUtils;
}
public void openOfficeToPDF(String inputFilePath, String outputFilePath) {
@@ -25,18 +21,19 @@ public class OfficeToPdfService {
}
public static void converterFile(File inputFile, String outputFilePath_end, OfficeDocumentConverter converter) {
public static void converterFile(File inputFile, String outputFilePath_end,
OfficeDocumentConverter converter) {
File outputFile = new File(outputFilePath_end);
// 假如目标路径不存在,则新建该路径
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end);
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
converter.convert(inputFile, outputFile);
}
public void office2pdf(String inputFilePath, String outputFilePath) {
OfficeDocumentConverter converter = officePluginManager.getDocumentConverter();
OfficeDocumentConverter converter = converterUtils.getDocumentConverter();
if (null != inputFilePath) {
File inputFile = new File(inputFilePath);
// 判断目标文件路径是否为空

View File

@@ -0,0 +1,78 @@
package cn.keking.utils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
@Component
public class PdfUtils {
private final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
private final FileUtils fileUtils;
@Value("${server.tomcat.uri-encoding:UTF-8}")
private String uriEncoding;
public PdfUtils(FileUtils fileUtils) {
this.fileUtils = fileUtils;
}
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String baseUrl) {
List<String> imageUrls = new ArrayList<>();
Integer imageCount = fileUtils.getConvertedPdfImage(pdfFilePath);
String imageFileSuffix = ".jpg";
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
String urlPrefix = null;
try {
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++)
imageUrls.add(urlPrefix + "/" + i + imageFileSuffix);
return imageUrls;
}
try {
File pdfFile = new File(pdfFilePath);
PDDocument doc = PDDocument.load(pdfFile);
int pageCount = doc.getNumberOfPages();
PDFRenderer pdfRenderer = new PDFRenderer(doc);
int index = pdfFilePath.lastIndexOf(".");
String folder = pdfFilePath.substring(0, index);
File path = new File(folder);
if (!path.exists()) {
path.mkdirs();
}
String imageFilePath;
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
imageFilePath = folder + File.separator + pageIndex + imageFileSuffix;
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 105, ImageType.RGB);
ImageIOUtil.writeImage(image, imageFilePath, 105);
imageUrls.add(urlPrefix + "/" + pageIndex + imageFileSuffix);
}
doc.close();
fileUtils.addConvertedPdfImage(pdfFilePath, pageCount);
} catch (IOException e) {
logger.error("Convert pdf to jpg exception, pdfFilePath{}", pdfFilePath, e);
}
return imageUrls;
}
}

View File

@@ -1,7 +1,7 @@
package cn.keking.config;
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.service.cache.CacheService;
import cn.keking.utils.KkFileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@@ -14,13 +14,13 @@ import org.springframework.stereotype.Component;
*/
@Component
@ConditionalOnExpression("'${cache.clean.enabled:false}'.equals('true')")
public class SchedulerCleanConfig {
public class ShedulerClean {
private final Logger logger = LoggerFactory.getLogger(SchedulerCleanConfig.class);
private final Logger logger = LoggerFactory.getLogger(ShedulerClean.class);
private final CacheService cacheService;
public SchedulerCleanConfig(CacheService cacheService) {
public ShedulerClean(CacheService cacheService) {
this.cacheService = cacheService;
}
@@ -31,7 +31,7 @@ public class SchedulerCleanConfig {
public void clean() {
logger.info("Cache clean start");
cacheService.cleanCache();
KkFileUtils.deleteDirectory(fileDir);
DeleteFileUtil.deleteDirectory(fileDir);
logger.info("Cache clean end");
}
}

View File

@@ -1,14 +1,15 @@
package cn.keking.service;
package cn.keking.utils;
import cn.keking.config.ConfigConstants;
import cn.keking.model.FileType;
import cn.keking.utils.KkFileUtils;
import cn.keking.web.filter.BaseUrlFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.junrar.Archive;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
@@ -26,34 +27,37 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author yudian-it
* create 2017/11/27
* @date 2017/11/27
*/
@Component
public class CompressFileReader {
public class ZipReader {
static Pattern pattern = Pattern.compile("^\\d+");
private final FileUtils fileUtils;
private static final Pattern pattern = Pattern.compile("^\\d+");
private final FileHandlerService fileHandlerService;
private final String fileDir = ConfigConstants.getFileDir();
private final ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public CompressFileReader(FileHandlerService fileHandlerService) {
this.fileHandlerService = fileHandlerService;
public ZipReader(FileUtils fileUtils) {
this.fileUtils = fileUtils;
}
public String readZipFile(String filePath, String fileKey) {
public String readZipFile(String filePath,String fileKey) {
String archiveSeparator = "/";
Map<String, FileNode> appender = new HashMap<>();
List<String> imgUrls = new LinkedList<>();
Map<String, FileNode> appender = Maps.newHashMap();
List<String> imgUrls = Lists.newArrayList();
String baseUrl = BaseUrlFilter.getBaseUrl();
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
String archiveFileName = fileUtils.getFileNameFromPath(filePath);
try {
ZipFile zipFile = new ZipFile(filePath, KkFileUtils.getFileEncode(filePath));
ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath));
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
// 排序
entries = sortZipEntries(entries);
List<Map<String, ZipArchiveEntry>> entriesToBeExtracted = new LinkedList<>();
while (entries.hasMoreElements()) {
List<Map<String, ZipArchiveEntry>> entriesToBeExtracted = Lists.newArrayList();
while (entries.hasMoreElements()){
ZipArchiveEntry entry = entries.nextElement();
String fullName = entry.getName();
int level = fullName.split(archiveSeparator).length;
@@ -66,10 +70,10 @@ public class CompressFileReader {
entriesToBeExtracted.add(Collections.singletonMap(childName, entry));
}
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level - 1) + "_" + parentName;
FileType type = FileType.typeFromUrl(childName);
if (type.equals(FileType.PICTURE)) {//添加图片文件到图片列表
imgUrls.add(baseUrl + childName);
parentName = (level-1) + "_" + parentName;
FileType type=fileUtils.typeFromUrl(childName);
if (type.equals(FileType.picture)){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
addNodes(appender, parentName, node);
@@ -77,7 +81,7 @@ public class CompressFileReader {
}
// 开启新的线程处理文件解压
executors.submit(new ZipExtractorWorker(entriesToBeExtracted, zipFile, filePath));
fileHandlerService.putImgCache(fileKey, imgUrls);
fileUtils.putImgCache(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (IOException e) {
e.printStackTrace();
@@ -86,29 +90,29 @@ public class CompressFileReader {
}
private Enumeration<ZipArchiveEntry> sortZipEntries(Enumeration<ZipArchiveEntry> entries) {
List<ZipArchiveEntry> sortedEntries = new LinkedList<>();
while (entries.hasMoreElements()) {
List<ZipArchiveEntry> sortedEntries = Lists.newArrayList();
while(entries.hasMoreElements()){
sortedEntries.add(entries.nextElement());
}
sortedEntries.sort(Comparator.comparingInt(o -> o.getName().length()));
return Collections.enumeration(sortedEntries);
}
public String unRar(String filePath, String fileKey) {
Map<String, FileNode> appender = new HashMap<>();
List<String> imgUrls = new ArrayList<>();
public String unRar(String filePath,String fileKey){
Map<String, FileNode> appender = Maps.newHashMap();
List<String> imgUrls = Lists.newArrayList();
String baseUrl = BaseUrlFilter.getBaseUrl();
try {
Archive archive = new Archive(new FileInputStream(filePath));
Archive archive = new Archive(new FileInputStream(new File(filePath)));
List<FileHeader> headers = archive.getFileHeaders();
headers = sortedHeaders(headers);
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
List<Map<String, FileHeader>> headersToBeExtracted = new ArrayList<>();
String archiveFileName = fileUtils.getFileNameFromPath(filePath);
List<Map<String, FileHeader>> headersToBeExtracted = Lists.newArrayList();
for (FileHeader header : headers) {
String fullName;
if (header.isUnicode()) {
fullName = header.getFileNameW();
} else {
}else {
fullName = header.getFileNameString();
}
// 展示名
@@ -120,16 +124,16 @@ public class CompressFileReader {
headersToBeExtracted.add(Collections.singletonMap(childName, header));
}
String parentName = getLast2FileName(fullName, "\\", archiveFileName);
FileType type = FileType.typeFromUrl(childName);
if (type.equals(FileType.PICTURE)) {//添加图片文件到图片列表
imgUrls.add(baseUrl + childName);
FileType type = fileUtils.typeFromUrl(childName);
if (type.equals(FileType.picture)){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
addNodes(appender, parentName, node);
appender.put(childName, node);
}
executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath));
fileHandlerService.putImgCache(fileKey, imgUrls);
fileUtils.putImgCache(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (RarException | IOException e) {
e.printStackTrace();
@@ -137,19 +141,19 @@ public class CompressFileReader {
return null;
}
public String read7zFile(String filePath, String fileKey) {
public String read7zFile(String filePath,String fileKey) {
String archiveSeparator = "/";
Map<String, FileNode> appender = new HashMap<>();
List<String> imgUrls = new ArrayList<>();
String baseUrl = BaseUrlFilter.getBaseUrl();
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
Map<String, FileNode> appender = Maps.newHashMap();
List<String> imgUrls = Lists.newArrayList();
String baseUrl= BaseUrlFilter.getBaseUrl();
String archiveFileName = fileUtils.getFileNameFromPath(filePath);
try {
SevenZFile zipFile = new SevenZFile(new File(filePath));
Iterable<SevenZArchiveEntry> entries = zipFile.getEntries();
// 排序
Enumeration<SevenZArchiveEntry> newEntries = sortSevenZEntries(entries);
List<Map<String, SevenZArchiveEntry>> entriesToBeExtracted = new ArrayList<>();
while (newEntries.hasMoreElements()) {
List<Map<String, SevenZArchiveEntry>> entriesToBeExtracted = Lists.newArrayList();
while (newEntries.hasMoreElements()){
SevenZArchiveEntry entry = newEntries.nextElement();
String fullName = entry.getName();
int level = fullName.split(archiveSeparator).length;
@@ -162,10 +166,10 @@ public class CompressFileReader {
entriesToBeExtracted.add(Collections.singletonMap(childName, entry));
}
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level - 1) + "_" + parentName;
FileType type = FileType.typeFromUrl(childName);
if (type.equals(FileType.PICTURE)) {//添加图片文件到图片列表
imgUrls.add(baseUrl + childName);
parentName = (level-1) + "_" + parentName;
FileType type=fileUtils.typeFromUrl(childName);
if (type.equals(FileType.picture)){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
addNodes(appender, parentName, node);
@@ -173,7 +177,7 @@ public class CompressFileReader {
}
// 开启新的线程处理文件解压
executors.submit(new SevenZExtractorWorker(entriesToBeExtracted, filePath));
fileHandlerService.putImgCache(fileKey, imgUrls);
fileUtils.putImgCache(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (IOException e) {
e.printStackTrace();
@@ -183,7 +187,7 @@ public class CompressFileReader {
private Enumeration<SevenZArchiveEntry> sortSevenZEntries(Iterable<SevenZArchiveEntry> entries) {
List<SevenZArchiveEntry> sortedEntries = new ArrayList<>();
List<SevenZArchiveEntry> sortedEntries = Lists.newArrayList();
for (SevenZArchiveEntry entry : entries) {
sortedEntries.add(entry);
}
@@ -207,7 +211,7 @@ public class CompressFileReader {
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));
for (Map.Entry<Integer, FileHeader> entry : mapHeaders.entrySet()) {
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())) {
sortedHeaders.add(header);
@@ -219,7 +223,7 @@ public class CompressFileReader {
private static String getLast2FileName(String fullName, String seperator, String rootName) {
if (fullName.endsWith(seperator)) {
fullName = fullName.substring(0, fullName.length() - 1);
fullName = fullName.substring(0, fullName.length()-1);
}
// 1.获取剩余部分
int endIndex = fullName.lastIndexOf(seperator);
@@ -234,7 +238,7 @@ public class CompressFileReader {
private static String getLastFileName(String fullName, String seperator) {
if (fullName.endsWith(seperator)) {
fullName = fullName.substring(0, fullName.length() - 1);
fullName = fullName.substring(0, fullName.length()-1);
}
String newName = fullName;
if (fullName.contains(seperator)) {
@@ -245,11 +249,10 @@ public class CompressFileReader {
public static Comparator<FileNode> sortComparator = new Comparator<FileNode>() {
final Collator cmp = Collator.getInstance(Locale.US);
@Override
public int compare(FileNode o1, FileNode o2) {
// 判断两个对比对象是否是开头包含数字如果包含数字则获取数字并按数字真正大小进行排序
BigDecimal num1, num2;
BigDecimal num1,num2;
if (null != (num1 = isStartNumber(o1))
&& null != (num2 = isStartNumber(o2))) {
return num1.subtract(num2).intValue();
@@ -285,16 +288,14 @@ public class CompressFileReader {
this.childList = childList;
this.directory = directory;
}
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory, String fileKey) {
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory,String fileKey) {
this.originName = originName;
this.fileName = fileName;
this.parentFileName = parentFileName;
this.childList = childList;
this.directory = directory;
this.fileKey = fileKey;
this.fileKey=fileKey;
}
public String getFileKey() {
return fileKey;
}
@@ -382,15 +383,17 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
if (new File(filePath).exists()) {
new File(filePath).delete();
}
}
private void extractZipFile(String childName, InputStream zipFile) {
String outPath = fileDir + childName;
try (OutputStream ot = new FileOutputStream(outPath)) {
try (OutputStream ot = new FileOutputStream(outPath)){
byte[] inByte = new byte[1024];
int len;
while ((-1 != (len = zipFile.read(inByte)))) {
while ((-1 != (len = zipFile.read(inByte)))){
ot.write(inByte, 0, len);
}
} catch (IOException e) {
@@ -439,7 +442,10 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
if (new File(filePath).exists()) {
new File(filePath).delete();
}
}
}
@@ -468,12 +474,14 @@ public class CompressFileReader {
} catch (IOException e) {
e.printStackTrace();
}
KkFileUtils.deleteFileByPath(filePath);
if (new File(filePath).exists()) {
new File(filePath).delete();
}
}
private void extractRarFile(String childName, FileHeader header, Archive archive) {
String outPath = fileDir + childName;
try (OutputStream ot = new FileOutputStream(outPath)) {
try(OutputStream ot = new FileOutputStream(outPath)) {
archive.extractFile(header, ot);
} catch (IOException | RarException e) {
e.printStackTrace();

View File

@@ -3,7 +3,8 @@ package cn.keking.web.controller;
import cn.keking.config.ConfigConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import cn.keking.model.ReturnResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,9 +16,10 @@ 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.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
*
@@ -30,7 +32,9 @@ public class FileController {
private final Logger logger = LoggerFactory.getLogger(FileController.class);
private final String fileDir = ConfigConstants.getFileDir();
private final String demoDir = "demo";
private final String demoPath = demoDir + File.separator;
@RequestMapping(value = "fileUpload", method = RequestMethod.POST)
@@ -38,10 +42,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
@@ -53,19 +53,19 @@ public class FileController {
}
// 判断是否存在同名文件
if (existsFile(fileName)) {
return new ObjectMapper().writeValueAsString(ReturnResponse.failure("存在同名文件,请先删除原有文件再次上传"));
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "存在同名文件,请先删除原有文件再次上传", null));
}
File outFile = new File(fileDir + demoPath);
if (!outFile.exists() && !outFile.mkdirs()) {
logger.error("创建文件夹【{}】失败,请检查目录权限!",fileDir + demoPath);
if (!outFile.exists()) {
outFile.mkdirs();
}
logger.info("上传文件:{}", 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 new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
} catch (IOException e) {
logger.error("文件上传失败", e);
return new ObjectMapper().writeValueAsString(ReturnResponse.failure());
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "FAILURE", null));
}
}
@@ -76,22 +76,18 @@ public class FileController {
}
File file = new File(fileDir + demoPath + fileName);
logger.info("删除文件:{}", file.getAbsolutePath());
if (file.exists() && !file.delete()) {
logger.error("删除文件【{}】失败,请检查目录权限!",file.getPath());
if (file.exists()) {
file.delete();
}
return new ObjectMapper().writeValueAsString(ReturnResponse.success());
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
}
@RequestMapping(value = "listFiles", method = RequestMethod.GET)
public String getFiles() throws JsonProcessingException {
List<Map<String, String>> list = new ArrayList<>();
List<Map<String, String>> list = Lists.newArrayList();
File file = new File(fileDir + demoPath);
if (file.exists()) {
Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(file1 -> {
Map<String, String> fileName = new HashMap<>();
fileName.put("fileName", demoDir + "/" + file1.getName());
list.add(fileName);
});
Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(file1 -> list.add(ImmutableMap.of("fileName", demoDir + "/" + file1.getName())));
}
return new ObjectMapper().writeValueAsString(list);
}

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