mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-28 19:16:43 +00:00
Compare commits
12 Commits
klencoding
...
log
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2eef41ec7 | ||
|
|
60da610d1f | ||
|
|
08415aa5ca | ||
|
|
7a7e1a1855 | ||
|
|
f530f441d5 | ||
|
|
10160e8104 | ||
|
|
602e80ee9e | ||
|
|
9c83860e1b | ||
|
|
1f1970232b | ||
|
|
594bd895ec | ||
|
|
486c09b24a | ||
|
|
aaf396fbc8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,7 +17,6 @@ target/
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
|
||||
@@ -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-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"]
|
||||
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-3.3.0/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-3.3.0/config/application.properties","-jar","/opt/kkFileView-3.3.0/bin/kkFileView-3.3.0.jar"]
|
||||
20
README.md
20
README.md
@@ -109,6 +109,26 @@ pdf预览模式预览效果如下
|
||||
|
||||
### 历史更新记录
|
||||
|
||||
> 2020年12月27日 :
|
||||
|
||||
2020年年终大版本更新,架构全面设计,代码全面重构,代码质量全面提升,二次开发更便捷,欢迎拉源码品鉴,提issue、pr共同建设
|
||||
|
||||
1. 架构模块调整,大量的代码重构,代码质量提升N个等级,欢迎品鉴
|
||||
2. 增强XML文件预览效果,新增XML文档数结构预览
|
||||
3. 新增markdown文件预览支持,预览支持md渲染和源文本切换支持
|
||||
4. 切换底层web server为jetty,解决这个issue:https://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. 移除guava、hutool等非必须的工具包,减少代码体积
|
||||
12. Office组件加载异步化,提速应用启动速度最快到5秒内
|
||||
13. 合理设置预览消费队列的线程数
|
||||
14. 修复压缩包里文件再次预览失败的bug
|
||||
15. 修复图片预览的bug
|
||||
|
||||
> 2020年05月20日 :
|
||||
1. 新增支持全局水印,并支持通过参数动态改变水印内容
|
||||
2. 新增支持CAD文件预览
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>filepreview</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
<modules>
|
||||
<module>office-plugin</module>
|
||||
<module>server</module>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>kkFileView</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -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 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\config\application.properties -jar kkFileView-2.2.1.jar -> ..\log\kkFileView.log
|
||||
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\config\application.properties -jar kkFileView-3.3.0.jar -> ..\log\kkFileView.log
|
||||
@@ -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 -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 &
|
||||
nohup java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../config/application.properties -jar kkFileView-3.3.0.jar > ../log/kkFileView.log 2>&1 &
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[#ftl]
|
||||
[#-- @implicitly included --]
|
||||
[#-- @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" --]
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package cn.keking.service;
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.config.WatermarkConfigConstants;
|
||||
import org.artofsolving.jodconverter.office.OfficeUtils;
|
||||
import org.artofsolving.jodconverter.util.ConfigUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -13,6 +11,7 @@ import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
@@ -81,7 +80,7 @@ public class ConfigRefreshComponent {
|
||||
setWatermarkConfig(properties);
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
Thread.sleep(1000L);
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOGGER.error("读取配置文件异常", e);
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.keking.utils;
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.FileUtils;
|
||||
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 ShedulerClean {
|
||||
public class SchedulerCleanConfig {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ShedulerClean.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(SchedulerCleanConfig.class);
|
||||
|
||||
private final CacheService cacheService;
|
||||
|
||||
public ShedulerClean(CacheService cacheService) {
|
||||
public SchedulerCleanConfig(CacheService cacheService) {
|
||||
this.cacheService = cacheService;
|
||||
}
|
||||
|
||||
@@ -1,388 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
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归到0,to归到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, "default") = "default"
|
||||
* nullToDefault("", "default") = ""
|
||||
* nullToDefault(" ", "default") = " "
|
||||
* nullToDefault("bat", "default") = "bat"
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
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 对之间放置 & 符号。
|
||||
* </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 = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
||||
* </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 '&' 不编码
|
||||
* 其它编码为 %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 = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
||||
* </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 '&' 不编码
|
||||
* 其它编码为 %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();
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import java.util.Map;
|
||||
* Content :文件类型,文本,office,压缩包等等
|
||||
*/
|
||||
public enum FileType {
|
||||
|
||||
picture("pictureFilePreviewImpl"),
|
||||
compress("compressFilePreviewImpl"),
|
||||
office("officeFilePreviewImpl"),
|
||||
@@ -19,12 +20,13 @@ public enum FileType {
|
||||
media("mediaFilePreviewImpl"),
|
||||
markdown("markdownFilePreviewImpl"),
|
||||
xml("xmlFilePreviewImpl"),
|
||||
flv("flvFilePreviewImpl"),
|
||||
cad("cadFilePreviewImpl");
|
||||
|
||||
private static final String[] OFFICE_TYPES = {"docx", "doc", "xls", "xlsx", "ppt", "pptx"};
|
||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "RAW"};
|
||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
||||
private static final String[] SIMTEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
|
||||
private static final Map<String, FileType> FILE_TYPE_MAPPER = new HashMap<>();
|
||||
|
||||
@@ -38,7 +40,7 @@ public enum FileType {
|
||||
for (String archive : ARCHIVE_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(archive, FileType.compress);
|
||||
}
|
||||
for (String text : SIMTEXT_TYPES) {
|
||||
for (String text : SSIM_TEXT_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(text, FileType.simText);
|
||||
}
|
||||
for (String media : MEDIA_TYPES) {
|
||||
@@ -48,11 +50,29 @@ public enum FileType {
|
||||
FILE_TYPE_MAPPER.put("xml", FileType.xml);
|
||||
FILE_TYPE_MAPPER.put("pdf", FileType.pdf);
|
||||
FILE_TYPE_MAPPER.put("dwg", FileType.cad);
|
||||
FILE_TYPE_MAPPER.put("flv", FileType.flv);
|
||||
|
||||
}
|
||||
|
||||
public static FileType to(String fileType){
|
||||
private static FileType to(String fileType){
|
||||
return FILE_TYPE_MAPPER.getOrDefault(fileType,other);
|
||||
}
|
||||
/**
|
||||
* 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件类型
|
||||
*/
|
||||
public static 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);
|
||||
}
|
||||
|
||||
public static FileType typeFromFileName(String fileName) {
|
||||
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
return FileType.to(fileType);
|
||||
}
|
||||
|
||||
private final String instanceName;
|
||||
|
||||
|
||||
@@ -4,11 +4,18 @@ 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. 成功
|
||||
@@ -31,6 +38,30 @@ 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;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class CompressFileReader {
|
||||
}
|
||||
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
|
||||
parentName = (level - 1) + "_" + parentName;
|
||||
FileType type = fileHandlerService.typeFromUrl(childName);
|
||||
FileType type = FileType.typeFromUrl(childName);
|
||||
if (type.equals(FileType.picture)) {//添加图片文件到图片列表
|
||||
imgUrls.add(baseUrl + childName);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class CompressFileReader {
|
||||
headersToBeExtracted.add(Collections.singletonMap(childName, header));
|
||||
}
|
||||
String parentName = getLast2FileName(fullName, "\\", archiveFileName);
|
||||
FileType type = fileHandlerService.typeFromUrl(childName);
|
||||
FileType type = FileType.typeFromUrl(childName);
|
||||
if (type.equals(FileType.picture)) {//添加图片文件到图片列表
|
||||
imgUrls.add(baseUrl + childName);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class CompressFileReader {
|
||||
}
|
||||
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
|
||||
parentName = (level - 1) + "_" + parentName;
|
||||
FileType type = fileHandlerService.typeFromUrl(childName);
|
||||
FileType type = FileType.typeFromUrl(childName);
|
||||
if (type.equals(FileType.picture)) {//添加图片文件到图片列表
|
||||
imgUrls.add(baseUrl + childName);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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.
|
||||
@@ -70,7 +71,7 @@ public class FileConvertQueueTask {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
Thread.sleep(1000*10);
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (Exception ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -4,13 +4,28 @@ import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.FileUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
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.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 org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -21,10 +36,15 @@ import java.util.Map;
|
||||
@Component
|
||||
public class FileHandlerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FileHandlerService.class);
|
||||
|
||||
private static final String DEFAULT_CONVERTER_CHARSET = System.getProperty("sun.jnu.encoding");
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
private final CacheService cacheService;
|
||||
|
||||
@Value("${server.tomcat.uri-encoding:UTF-8}")
|
||||
private String uriEncoding;
|
||||
|
||||
public FileHandlerService(CacheService cacheService) {
|
||||
this.cacheService = cacheService;
|
||||
}
|
||||
@@ -51,35 +71,6 @@ public class FileHandlerService {
|
||||
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 this.typeFromFileName(fileName);
|
||||
}
|
||||
|
||||
private FileType typeFromFileName(String fileName) {
|
||||
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
return FileType.to(fileType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从url中剥离出文件名
|
||||
*
|
||||
* @param url 格式如:http://www.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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从路径中获取文件负
|
||||
@@ -174,68 +165,87 @@ public class FileHandlerService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件后缀
|
||||
* pdf文件转换成jpg图片集
|
||||
* @param pdfFilePath pdf文件路径
|
||||
* @param pdfName pdf文件名称
|
||||
* @param baseUrl 基础访问地址
|
||||
* @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);
|
||||
}
|
||||
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String baseUrl) {
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
Integer imageCount = this.getConvertedPdfImage(pdfFilePath);
|
||||
String imageFileSuffix = ".jpg";
|
||||
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
|
||||
String urlPrefix;
|
||||
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);
|
||||
|
||||
private String suffixFromFileName(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
int index = pdfFilePath.lastIndexOf(".");
|
||||
String folder = pdfFilePath.substring(0, index);
|
||||
|
||||
File path = new File(folder);
|
||||
if (!path.exists() && !path.mkdirs()) {
|
||||
logger.error("创建转换文件【{}】目录失败,请检查目录权限!", folder);
|
||||
}
|
||||
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();
|
||||
this.addConvertedPdfImage(pdfFilePath, pageCount);
|
||||
} catch (IOException e) {
|
||||
logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e);
|
||||
}
|
||||
return imageUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取url中的参数
|
||||
*
|
||||
* @param url url
|
||||
* @param name 参数名
|
||||
* @return 参数值
|
||||
* cad文件转pdf
|
||||
* @param inputFilePath cad文件路径
|
||||
* @param outputFilePath pdf输出文件路径
|
||||
* @return 转换是否成功
|
||||
*/
|
||||
public String getUrlParameterReg(String url, String name) {
|
||||
Map<String, String> mapRequest = new HashMap<>();
|
||||
String strUrlParam = truncateUrlPage(url);
|
||||
if (strUrlParam == null) {
|
||||
return "";
|
||||
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("PDFFileNotFoundException,inputFilePath:{}", inputFilePath, e);
|
||||
return false;
|
||||
}
|
||||
//每个键值为一组
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,15 +259,15 @@ public class FileHandlerService {
|
||||
String suffix;
|
||||
FileType type;
|
||||
String fileName;
|
||||
String fullFileName = this.getUrlParameterReg(url, "fullfilename");
|
||||
String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
|
||||
if (StringUtils.hasText(fullFileName)) {
|
||||
fileName = fullFileName;
|
||||
type = this.typeFromFileName(fullFileName);
|
||||
suffix = suffixFromFileName(fullFileName);
|
||||
type = FileType.typeFromFileName(fullFileName);
|
||||
suffix = FileUtils.suffixFromFileName(fullFileName);
|
||||
} else {
|
||||
fileName = getFileNameFromURL(url);
|
||||
type = typeFromUrl(url);
|
||||
suffix = suffixFromUrl(url);
|
||||
fileName = WebUtils.getFileNameFromURL(url);
|
||||
type = FileType.typeFromUrl(url);
|
||||
suffix = WebUtils.suffixFromUrl(url);
|
||||
}
|
||||
attribute.setType(type);
|
||||
attribute.setName(fileName);
|
||||
|
||||
@@ -8,5 +8,16 @@ import org.springframework.ui.Model;
|
||||
* Content :
|
||||
*/
|
||||
public interface FilePreview {
|
||||
|
||||
String FLV_FILE_PREVIEW_PAGE = "flv";
|
||||
String PDF_FILE_PREVIEW_PAGE = "pdf";
|
||||
String COMPRESS_FILE_PREVIEW_PAGE = "compress";
|
||||
String MEDIA_FILE_PREVIEW_PAGE = "media";
|
||||
String PICTURE_FILE_PREVIEW_PAGE = "picture";
|
||||
String OFFICE_PICTURE_FILE_PREVIEW_PAGE = "officePicture";
|
||||
String TXT_FILE_PREVIEW_PAGE = "txt";
|
||||
String EXEL_FILE_PREVIEW_PAGE = "html";
|
||||
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
|
||||
|
||||
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.keking.extend;
|
||||
package cn.keking.service;
|
||||
|
||||
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 ControlDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
|
||||
public class OfficePluginExtendFormatRegistry extends SimpleDocumentFormatRegistry {
|
||||
|
||||
public ControlDocumentFormatRegistry() {
|
||||
public OfficePluginExtendFormatRegistry() {
|
||||
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"));
|
||||
@@ -1,7 +1,6 @@
|
||||
package cn.keking.service;
|
||||
|
||||
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;
|
||||
@@ -72,7 +71,7 @@ public class OfficePluginManager {
|
||||
}
|
||||
|
||||
public OfficeDocumentConverter getDocumentConverter() {
|
||||
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new ControlDocumentFormatRegistry());
|
||||
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new OfficePluginExtendFormatRegistry());
|
||||
converter.setDefaultLoadProperties(getLoadProperties());
|
||||
return converter;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import org.artofsolving.jodconverter.OfficeDocumentConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
@@ -10,6 +12,8 @@ import java.io.File;
|
||||
*/
|
||||
@Component
|
||||
public class OfficeToPdfService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(OfficeToPdfService.class);
|
||||
private final OfficePluginManager officePluginManager;
|
||||
|
||||
public OfficeToPdfService(OfficePluginManager officePluginManager) {
|
||||
@@ -21,12 +25,11 @@ 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();
|
||||
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end);
|
||||
}
|
||||
converter.convert(inputFile, outputFile);
|
||||
}
|
||||
|
||||
@@ -28,19 +28,11 @@ 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) {
|
||||
|
||||
@@ -31,11 +31,8 @@ public class CacheServiceRocksDBImpl implements CacheService {
|
||||
}
|
||||
|
||||
private static final String DB_PATH = ConfigUtils.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;
|
||||
|
||||
@@ -4,10 +4,8 @@ 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.PdfUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
@@ -22,55 +20,38 @@ import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
|
||||
@Service
|
||||
public class CadFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
private final DownloadUtils downloadUtils;
|
||||
|
||||
private final CadUtils cadUtils;
|
||||
|
||||
private final PdfUtils pdfUtils;
|
||||
|
||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService,
|
||||
DownloadUtils downloadUtils,
|
||||
CadUtils cadUtils,
|
||||
PdfUtils pdfUtils) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
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 = 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 fileName = fileAttribute.getName();
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
|
||||
String outFilePath = FILE_DIR + pdfName;
|
||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
String filePath;
|
||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
|
||||
if (0 != response.getCode()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
boolean convertResult = cadUtils.cadToPdf(filePath, outFilePath);
|
||||
boolean convertResult = fileHandlerService.cadToPdf(filePath, outFilePath);
|
||||
if (!convertResult) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", "cad文件转换异常,请联系管理员");
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "cad文件转换异常,请联系管理员");
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
@@ -79,10 +60,10 @@ public class CadFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
}
|
||||
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, pdfUtils, OFFICE_PREVIEW_TYPE_IMAGE);
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", pdfName);
|
||||
return "pdf";
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ import org.springframework.util.StringUtils;
|
||||
public class CompressFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final DownloadUtils downloadUtils;
|
||||
private final CompressFileReader compressFileReader;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, DownloadUtils downloadUtils, CompressFileReader compressFileReader) {
|
||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.downloadUtils = downloadUtils;
|
||||
this.compressFileReader = compressFileReader;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,11 +35,9 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
String fileTree = null;
|
||||
// 判断文件名是否存在(redis缓存读取)
|
||||
if (!StringUtils.hasText(fileHandlerService.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";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
if ("zip".equalsIgnoreCase(suffix) || "jar".equalsIgnoreCase(suffix) || "gzip".equalsIgnoreCase(suffix)) {
|
||||
@@ -57,11 +55,9 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
if (fileTree != null && !"null".equals(fileTree)) {
|
||||
model.addAttribute("fileTree", fileTree);
|
||||
return "compress";
|
||||
return COMPRESS_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* create : 2020-12-27 2:50 下午
|
||||
* flv文件预览处理实现
|
||||
**/
|
||||
@Service
|
||||
public class FlvFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final MediaFilePreviewImpl mediaFilePreview;
|
||||
|
||||
public FlvFilePreviewImpl(MediaFilePreviewImpl mediaFilePreview) {
|
||||
this.mediaFilePreview = mediaFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
mediaFilePreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return FLV_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static com.sun.glass.ui.Clipboard.TEXT_TYPE;
|
||||
import static cn.keking.service.impl.SimTextFilePreviewImpl.TEXT_TYPE;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* @authorboke : kailing.pub
|
||||
@@ -17,25 +18,21 @@ import org.springframework.ui.Model;
|
||||
@Service
|
||||
public class MediaFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final DownloadUtils downloadUtils;
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public MediaFilePreviewImpl(DownloadUtils downloadUtils,
|
||||
FileHandlerService fileHandlerService) {
|
||||
this.downloadUtils = downloadUtils;
|
||||
public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@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 (0 != response.getCode()) {
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
} else {
|
||||
model.addAttribute("mediaUrl", BaseUrlFilter.getBaseUrl() + fileHandlerService.getRelativePath(response.getContent()));
|
||||
}
|
||||
@@ -43,11 +40,7 @@ public class MediaFilePreviewImpl implements FilePreview {
|
||||
model.addAttribute("mediaUrl", url);
|
||||
}
|
||||
model.addAttribute("mediaUrl", url);
|
||||
String suffix=fileAttribute.getSuffix();
|
||||
if ("flv".equalsIgnoreCase(suffix)) {
|
||||
return "flv";
|
||||
}
|
||||
return "media";
|
||||
return MEDIA_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.OfficeToPdfService;
|
||||
import cn.keking.utils.PdfUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
@@ -22,40 +21,36 @@ import java.util.List;
|
||||
@Service
|
||||
public class OfficeFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final PdfUtils pdfUtils;
|
||||
private final DownloadUtils downloadUtils;
|
||||
private final OfficeToPdfService officeToPdfService;
|
||||
|
||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils, DownloadUtils downloadUtils, OfficeToPdfService officeToPdfService) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.pdfUtils = pdfUtils;
|
||||
this.downloadUtils = downloadUtils;
|
||||
this.officeToPdfService = officeToPdfService;
|
||||
}
|
||||
|
||||
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 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;
|
||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
String filePath;
|
||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
|
||||
if (0 != response.getCode()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
@@ -71,25 +66,23 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
}
|
||||
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, pdfUtils, OFFICE_PREVIEW_TYPE_IMAGE);
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", pdfName);
|
||||
return isHtml ? "html" : "pdf";
|
||||
return isHtml ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
model.addAttribute("msg", "office转图片异常,请联系管理员");
|
||||
model.addAttribute("fileType",fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgurls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (officePreviewTypeImage.equals(officePreviewType)) {
|
||||
return "officePicture";
|
||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,41 @@ import org.springframework.ui.Model;
|
||||
*/
|
||||
@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";
|
||||
return this.notSupportedFile(model, fileAttribute, "系统还不支持该格式文件的在线预览");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, FileAttribute fileAttribute, String errMsg) {
|
||||
return this.notSupportedFile(model, fileAttribute.getSuffix(), errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String errMsg) {
|
||||
return this.notSupportedFile(model, "未知", errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String fileType, String errMsg) {
|
||||
model.addAttribute("fileType", fileType);
|
||||
model.addAttribute("msg", errMsg);
|
||||
return NOT_SUPPORTED_FILE_PAGE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.utils.PdfUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
@@ -21,25 +20,17 @@ import java.util.List;
|
||||
public class PdfFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
private final PdfUtils pdfUtils;
|
||||
|
||||
private final DownloadUtils downloadUtils;
|
||||
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final String FILE_DIR = ConfigConstants.getFileDir();
|
||||
|
||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService,
|
||||
PdfUtils pdfUtils,
|
||||
DownloadUtils downloadUtils) {
|
||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.pdfUtils = pdfUtils;
|
||||
this.downloadUtils = downloadUtils;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String suffix=fileAttribute.getSuffix();
|
||||
String fileName=fileAttribute.getName();
|
||||
String fileName = fileAttribute.getName();
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
|
||||
@@ -47,11 +38,9 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
||||
//当文件不存在时,就去下载
|
||||
if (!fileHandlerService.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";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
outFilePath = response.getContent();
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
@@ -59,28 +48,24 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
}
|
||||
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, baseUrl);
|
||||
List<String> imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, baseUrl);
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
model.addAttribute("msg", "pdf转图片异常,请联系管理员");
|
||||
model.addAttribute("fileType",fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "pdf转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgurls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
|
||||
return "officePicture";
|
||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
} else {
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
if (!fileHandlerService.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";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
model.addAttribute("pdfUrl", fileHandlerService.getRelativePath(response.getContent()));
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
@@ -94,6 +79,6 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
model.addAttribute("pdfUrl", url);
|
||||
}
|
||||
}
|
||||
return "pdf";
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,11 @@ import java.util.List;
|
||||
public class PictureFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
private final DownloadUtils downloadUtils;
|
||||
|
||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService,
|
||||
DownloadUtils downloadUtils) {
|
||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.downloadUtils = downloadUtils;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,22 +37,20 @@ public class PictureFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
// 不是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";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
} else {
|
||||
String file = fileHandlerService.getRelativePath(response.getContent());
|
||||
imgUrls.clear();
|
||||
imgUrls.add(file);
|
||||
model.addAttribute("imgurls", imgUrls);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl", file);
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("imgurls", imgUrls);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl", url);
|
||||
}
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,34 +23,30 @@ public class SimTextFilePreviewImpl implements FilePreview {
|
||||
public static final String TEXT_TYPE = "textType";
|
||||
public static final String DEFAULT_TEXT_TYPE = "simText";
|
||||
|
||||
private final DownloadUtils downloadUtils;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public SimTextFilePreviewImpl(DownloadUtils downloadUtils) {
|
||||
this.downloadUtils = downloadUtils;
|
||||
public SimTextFilePreviewImpl(OtherFilePreviewImpl otherFilePreview) {
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@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";
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
try {
|
||||
File originFile = new File(response.getContent());
|
||||
String xmlString = FileUtils.readFileToString(originFile, StandardCharsets.UTF_8);
|
||||
model.addAttribute("textData", Base64Utils.encodeToString(xmlString.getBytes()));
|
||||
model.addAttribute("textData", Base64Utils.encodeToString(xmlString.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (IOException e) {
|
||||
model.addAttribute("msg", e.getLocalizedMessage());
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
|
||||
}
|
||||
if (!model.containsAttribute(TEXT_TYPE)) {
|
||||
model.addAttribute(TEXT_TYPE, DEFAULT_TEXT_TYPE);
|
||||
}
|
||||
return "txt";
|
||||
return TXT_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static com.sun.glass.ui.Clipboard.TEXT_TYPE;
|
||||
import static cn.keking.service.impl.SimTextFilePreviewImpl.TEXT_TYPE;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
@@ -20,7 +20,6 @@ public class XmlFilePreviewImpl implements FilePreview {
|
||||
this.simTextFilePreview = simTextFilePreview;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
model.addAttribute(TEXT_TYPE,"xml");
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
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("PDFFileNotFoundException,inputFilePath:{}", inputFilePath, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
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 cn.keking.service.FileHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
@@ -18,27 +15,20 @@ import java.util.UUID;
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@Component
|
||||
public class DownloadUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(DownloadUtils.class);
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
private static final String fileDir = ConfigConstants.getFileDir();
|
||||
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";
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
public DownloadUtils(FileHandlerService fileHandlerService) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileAttribute fileAttribute
|
||||
* @param fileName 文件名
|
||||
* @return 本地文件绝对路径
|
||||
*/
|
||||
public ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
String urlStr = fileAttribute.getUrl();
|
||||
String type = fileAttribute.getSuffix();
|
||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||
@@ -60,9 +50,9 @@ public class DownloadUtils {
|
||||
OutputStream os = new FileOutputStream(realPath);
|
||||
saveBytesToOutStream(bytes, os);
|
||||
} else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
|
||||
String ftpUsername = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||
} else {
|
||||
response.setCode(1);
|
||||
@@ -72,7 +62,7 @@ public class DownloadUtils {
|
||||
response.setContent(realPath);
|
||||
response.setMsg(fileName);
|
||||
if (FileType.simText.equals(fileAttribute.getType())) {
|
||||
this.convertTextPlainFileCharsetToUtf8(realPath);
|
||||
convertTextPlainFileCharsetToUtf8(realPath);
|
||||
}
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
@@ -88,10 +78,10 @@ public class DownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getBytesFromUrl(String urlStr) throws IOException {
|
||||
public static byte[] getBytesFromUrl(String urlStr) throws IOException {
|
||||
InputStream is = getInputStreamFromUrl(urlStr);
|
||||
if (is == null) {
|
||||
urlStr = URLUtil.normalize(urlStr, true, true);
|
||||
// urlStr = URLUtil.normalize(urlStr, true, true);
|
||||
is = getInputStreamFromUrl(urlStr);
|
||||
if (is == null) {
|
||||
logger.error("文件下载异常:url:{}", urlStr);
|
||||
@@ -101,12 +91,12 @@ public class DownloadUtils {
|
||||
return getBytesFromStream(is);
|
||||
}
|
||||
|
||||
public void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
|
||||
public static void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
|
||||
os.write(b);
|
||||
os.close();
|
||||
}
|
||||
|
||||
private InputStream getInputStreamFromUrl(String urlStr) {
|
||||
private static InputStream getInputStreamFromUrl(String urlStr) {
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
URLConnection connection = url.openConnection();
|
||||
@@ -120,7 +110,7 @@ public class DownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getBytesFromStream(InputStream is) throws IOException {
|
||||
private static byte[] getBytesFromStream(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
@@ -139,7 +129,7 @@ public class DownloadUtils {
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
*/
|
||||
private void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
|
||||
private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
|
||||
File sourceFile = new File(filePath);
|
||||
if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
|
||||
String encoding = FileUtils.getFileEncode(filePath);
|
||||
|
||||
@@ -57,6 +57,16 @@ public class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过文件名获取文件后缀
|
||||
* @param fileName 文件名称
|
||||
* @return 文件后缀
|
||||
*/
|
||||
public static String suffixFromFileName(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据文件路径删除文件
|
||||
*
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import cn.keking.service.FileHandlerService;
|
||||
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 FileHandlerService fileHandlerService;
|
||||
|
||||
@Value("${server.tomcat.uri-encoding:UTF-8}")
|
||||
private String uriEncoding;
|
||||
|
||||
public PdfUtils(FileHandlerService fileHandlerService) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String baseUrl) {
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
Integer imageCount = fileHandlerService.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();
|
||||
fileHandlerService.addConvertedPdfImage(pdfFilePath, pageCount);
|
||||
} catch (IOException e) {
|
||||
logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e);
|
||||
}
|
||||
return imageUrls;
|
||||
}
|
||||
}
|
||||
86
server/src/main/java/cn/keking/utils/WebUtils.java
Normal file
86
server/src/main/java/cn/keking/utils/WebUtils.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* create : 2020-12-27 1:30 上午
|
||||
**/
|
||||
public class WebUtils {
|
||||
/**
|
||||
* 获取url中的参数
|
||||
*
|
||||
* @param url url
|
||||
* @param name 参数名
|
||||
* @return 参数值
|
||||
*/
|
||||
public static 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 static 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从url中剥离出文件名
|
||||
*
|
||||
* @param url 格式如:http://www.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k=
|
||||
* @return 文件名
|
||||
*/
|
||||
public static 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从url中获取文件后缀
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件后缀
|
||||
*/
|
||||
public static String suffixFromUrl(String url) {
|
||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
||||
return FileUtils.suffixFromFileName(fileName);
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,7 @@ 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)
|
||||
@@ -49,19 +47,19 @@ public class FileController {
|
||||
}
|
||||
// 判断是否存在同名文件
|
||||
if (existsFile(fileName)) {
|
||||
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "存在同名文件,请先删除原有文件再次上传", null));
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.failure("存在同名文件,请先删除原有文件再次上传"));
|
||||
}
|
||||
File outFile = new File(fileDir + demoPath);
|
||||
if (!outFile.exists()) {
|
||||
outFile.mkdirs();
|
||||
if (!outFile.exists() && !outFile.mkdirs()) {
|
||||
logger.error("创建文件夹【{}】失败,请检查目录权限!",fileDir + demoPath);
|
||||
}
|
||||
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(new ReturnResponse<String>(0, "SUCCESS", null));
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.success(null));
|
||||
} catch (IOException e) {
|
||||
logger.error("文件上传失败", e);
|
||||
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "FAILURE", null));
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.failure());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +70,10 @@ public class FileController {
|
||||
}
|
||||
File file = new File(fileDir + demoPath + fileName);
|
||||
logger.info("删除文件:{}", file.getAbsolutePath());
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
if (file.exists() && !file.delete()) {
|
||||
logger.error("删除文件【{}】失败,请检查目录权限!",file.getPath());
|
||||
}
|
||||
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
|
||||
return new ObjectMapper().writeValueAsString(ReturnResponse.success());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "listFiles", method = RequestMethod.GET)
|
||||
@@ -84,7 +82,7 @@ public class FileController {
|
||||
File file = new File(fileDir + demoPath);
|
||||
if (file.exists()) {
|
||||
Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(file1 -> {
|
||||
Map<String, String> fileName = new HashMap();
|
||||
Map<String, String> fileName = new HashMap<>();
|
||||
fileName.put("fileName", demoDir + "/" + file1.getName());
|
||||
list.add(fileName);
|
||||
});
|
||||
|
||||
@@ -5,12 +5,15 @@ import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.FilePreviewFactory;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@@ -18,68 +21,85 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@Controller
|
||||
public class OnlinePreviewController {
|
||||
|
||||
public static final String BASE64_DECODE_ERROR_MSG = "Base64解码失败,请检查你的 %s 是否采用 Base64 + urlEncode 双重编码了!";
|
||||
private final Logger logger = LoggerFactory.getLogger(OnlinePreviewController.class);
|
||||
|
||||
private final FilePreviewFactory previewFactory;
|
||||
private final CacheService cacheService;
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final DownloadUtils downloadUtils;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService, DownloadUtils downloadUtils) {
|
||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.previewFactory = filePreviewFactory;
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.cacheService = cacheService;
|
||||
this.downloadUtils = downloadUtils;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/onlinePreview")
|
||||
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url,req);
|
||||
String fileUrl;
|
||||
try {
|
||||
fileUrl = new String(Base64Utils.decodeFromString(url));
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req);
|
||||
FilePreview filePreview = previewFactory.get(fileAttribute);
|
||||
logger.info("预览文件url:{},previewType:{}", url, fileAttribute.getType());
|
||||
return filePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
logger.info("预览文件url:{},previewType:{}", fileUrl, fileAttribute.getType());
|
||||
return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/picturesPreview")
|
||||
public String picturesPreview(Model model, HttpServletRequest req) throws UnsupportedEncodingException {
|
||||
String urls = req.getParameter("urls");
|
||||
String currentUrl = req.getParameter("currentUrl");
|
||||
logger.info("预览文件url:{},urls:{}", currentUrl, urls);
|
||||
// 路径转码
|
||||
String decodedUrl = URLDecoder.decode(urls, "utf-8");
|
||||
String decodedCurrentUrl = URLDecoder.decode(currentUrl, "utf-8");
|
||||
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
|
||||
String fileUrls;
|
||||
try {
|
||||
fileUrls = new String(Base64Utils.decodeFromString(urls));
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "urls");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
logger.info("预览文件url:{},urls:{}", fileUrls, urls);
|
||||
// 抽取文件并返回文件列表
|
||||
String[] imgs = decodedUrl.split("\\|");
|
||||
List<String> imgUrls = Arrays.asList(imgs);
|
||||
String[] images = fileUrls.split("\\|");
|
||||
List<String> imgUrls = Arrays.asList(images);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl",decodedCurrentUrl);
|
||||
return "picture";
|
||||
|
||||
String currentUrl = req.getParameter("currentUrl");
|
||||
if (StringUtils.hasText(currentUrl)) {
|
||||
String decodedCurrentUrl = new String(Base64Utils.decodeFromString(currentUrl));
|
||||
model.addAttribute("currentUrl", decodedCurrentUrl);
|
||||
} else {
|
||||
model.addAttribute("currentUrl", imgUrls.get(0));
|
||||
}
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据url获取文件内容
|
||||
* 当pdfjs读取存在跨域问题的文件时将通过此接口读取
|
||||
*
|
||||
* @param urlPath url
|
||||
* @param urlPath url
|
||||
* @param response response
|
||||
*/
|
||||
@RequestMapping(value = "/getCorsFile", method = RequestMethod.GET)
|
||||
public void getCorsFile(String urlPath, HttpServletResponse response) {
|
||||
logger.info("下载跨域pdf文件url:{}", urlPath);
|
||||
try {
|
||||
byte[] bytes = downloadUtils.getBytesFromUrl(urlPath);
|
||||
downloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
|
||||
byte[] bytes = DownloadUtils.getBytesFromUrl(urlPath);
|
||||
DownloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
logger.error("下载跨域pdf文件异常,url:{}", urlPath, e);
|
||||
}
|
||||
@@ -87,6 +107,7 @@ public class OnlinePreviewController {
|
||||
|
||||
/**
|
||||
* 通过api接口入队
|
||||
*
|
||||
* @param url 请编码后在入队
|
||||
*/
|
||||
@RequestMapping("/addTask")
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BaseUrlFilter implements Filter {
|
||||
pathBuilder.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
|
||||
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
||||
String baseUrlTmp = ConfigConstants.getBaseUrl();
|
||||
if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equals(baseUrlTmp.toLowerCase())) {
|
||||
if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equalsIgnoreCase(baseUrlTmp)) {
|
||||
if (!baseUrlTmp.endsWith("/")) {
|
||||
baseUrlTmp = baseUrlTmp.concat("/");
|
||||
}
|
||||
|
||||
7
server/src/main/log/README.txt
Normal file
7
server/src/main/log/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
README.txt
|
||||
log目录是用来存放kkFileView.log的,预览服务的运行情况最终都会反映到这个日志文件里,
|
||||
可以提供给开发、运维排查系统问题。如果通过kkFileView.log还无法定位问题所在,请你在寻求
|
||||
kk官方支持时,QQ群一 613025121、QQ群二 484680571。将此日志文件一并携带,并按照这个
|
||||
格式重命名日志文件 kkFileView-QQ昵称-时间日期.log。如:kkFileView-kl博主-2020-12-27.log 。
|
||||
所有收集的日志文件我们都会存档,供所有的kk用户作为排查案例使用,所以在你提供日志前,请
|
||||
先自行处理日志文件里的业务敏感内容。
|
||||
25473
server/src/main/resources/static/pdfjs/build/pdf.js
Normal file
25473
server/src/main/resources/static/pdfjs/build/pdf.js
Normal file
File diff suppressed because it is too large
Load Diff
1
server/src/main/resources/static/pdfjs/build/pdf.js.map
Normal file
1
server/src/main/resources/static/pdfjs/build/pdf.js.map
Normal file
File diff suppressed because one or more lines are too long
57878
server/src/main/resources/static/pdfjs/build/pdf.worker.js
vendored
Normal file
57878
server/src/main/resources/static/pdfjs/build/pdf.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
server/src/main/resources/static/pdfjs/build/pdf.worker.js.map
vendored
Normal file
1
server/src/main/resources/static/pdfjs/build/pdf.worker.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user