mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-28 02:56:44 +00:00
Compare commits
25 Commits
dependabot
...
utils
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38429b476e | ||
|
|
594bd895ec | ||
|
|
486c09b24a | ||
|
|
aaf396fbc8 | ||
|
|
4e01d6f5f3 | ||
|
|
342c391a9b | ||
|
|
f2d929e6fa | ||
|
|
41cdc227b3 | ||
|
|
0f4f1d580b | ||
|
|
37c37868a3 | ||
|
|
01218e4a5c | ||
|
|
f6d54902e9 | ||
|
|
5a559aa868 | ||
|
|
9b0f381c06 | ||
|
|
c1802b2487 | ||
|
|
d4b11a4056 | ||
|
|
da1553920b | ||
|
|
d787813bc6 | ||
|
|
4a3886e41a | ||
|
|
cf1f833d60 | ||
|
|
cb21952155 | ||
|
|
3498df0491 | ||
|
|
e3ebf1979f | ||
|
|
fb09a8c00f | ||
|
|
4c708f3cbd |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -27,5 +27,6 @@ nbdist/
|
|||||||
### VS Code ###
|
### VS Code ###
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
jodconverter-web/src/main/cache/
|
server/src/main/cache/
|
||||||
jodconverter-web/src/main/file/
|
server/src/main/file/
|
||||||
|
server/src/main/log
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
MAINTAINER chenjh "842761733@qq.com"
|
MAINTAINER chenjh "842761733@qq.com"
|
||||||
ADD jodconverter-web/target/kkFileView-*.tar.gz /opt/
|
ADD server/target/kkFileView-*.tar.gz /opt/
|
||||||
COPY fonts/* /usr/share/fonts/chienes/
|
COPY fonts/* /usr/share/fonts/chienes/
|
||||||
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" > /etc/apt/sources.list &&\
|
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" > /etc/apt/sources.list &&\
|
||||||
apt-get clean && apt-get update &&\
|
apt-get clean && apt-get update &&\
|
||||||
|
|||||||
@@ -28,8 +28,9 @@
|
|||||||
### 联系我们,加入组织
|
### 联系我们,加入组织
|
||||||
> 我们会用心回答解决大家在项目使用中的问题,也请大家在提问前至少Google或baidu过,珍爱生命远离无效的交流沟通
|
> 我们会用心回答解决大家在项目使用中的问题,也请大家在提问前至少Google或baidu过,珍爱生命远离无效的交流沟通
|
||||||
|
|
||||||

|

|
||||||
QQ群号:613025121
|
|
||||||
|
QQ群号:~~613025121(已满)~~ 2群:484680571
|
||||||
|
|
||||||
### 文档预览效果
|
### 文档预览效果
|
||||||
#### 1. 文本预览
|
#### 1. 文本预览
|
||||||
|
|||||||
BIN
doc/KK开源技术交流2群群聊二维码.png
Normal file
BIN
doc/KK开源技术交流2群群聊二维码.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
BIN
doc/kk开源技术交流群聊二维码.png
Normal file
BIN
doc/kk开源技术交流群聊二维码.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package cn.keking.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by kl on 2018/1/17.
|
|
||||||
* Content :文件类型,文本,office,压缩包等等
|
|
||||||
*/
|
|
||||||
public enum FileType {
|
|
||||||
picture("pictureFilePreviewImpl"),
|
|
||||||
compress("compressFilePreviewImpl"),
|
|
||||||
office("officeFilePreviewImpl"),
|
|
||||||
simText("simTextFilePreviewImpl"),
|
|
||||||
pdf("pdfFilePreviewImpl"),
|
|
||||||
other("otherFilePreviewImpl"),
|
|
||||||
media("mediaFilePreviewImpl"),
|
|
||||||
cad("cadFilePreviewImpl");
|
|
||||||
|
|
||||||
private final String instanceName;
|
|
||||||
|
|
||||||
FileType(String instanceName){
|
|
||||||
this.instanceName=instanceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInstanceName() {
|
|
||||||
return instanceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,157 +0,0 @@
|
|||||||
package cn.keking.utils;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.mozilla.intl.chardet.nsDetector;
|
|
||||||
import org.mozilla.intl.chardet.nsICharsetDetectionObserver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本文件编码探测工具类
|
|
||||||
*
|
|
||||||
* @author HWliao
|
|
||||||
* @date 2017-12-24
|
|
||||||
*/
|
|
||||||
public class FileCharsetDetector {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 传入一个文件(File)对象,检查文件编码
|
|
||||||
*
|
|
||||||
* @param file File对象实例
|
|
||||||
* @return 文件编码,若无,则返回null
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static Observer guessFileEncoding(File file)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
return guessFileEncoding(file, new nsDetector());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* 获取文件的编码
|
|
||||||
* @param file
|
|
||||||
* File对象实例
|
|
||||||
* @param languageHint
|
|
||||||
* 语言提示区域代码 @see #nsPSMDetector ,取值如下:
|
|
||||||
* 1 : Japanese
|
|
||||||
* 2 : Chinese
|
|
||||||
* 3 : Simplified Chinese
|
|
||||||
* 4 : Traditional Chinese
|
|
||||||
* 5 : Korean
|
|
||||||
* 6 : Dont know(default)
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @return 文件编码,eg:UTF-8,GBK,GB2312形式(不确定的时候,返回可能的字符编码序列);若无,则返回null
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static Observer guessFileEncoding(File file, int languageHint)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
return guessFileEncoding(file, new nsDetector(languageHint));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件的编码
|
|
||||||
*
|
|
||||||
* @param file
|
|
||||||
* @param det
|
|
||||||
* @return
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static Observer guessFileEncoding(File file, nsDetector det)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
// new Observer
|
|
||||||
Observer observer = new Observer();
|
|
||||||
// set Observer
|
|
||||||
// The Notify() will be called when a matching charset is found.
|
|
||||||
det.Init(observer);
|
|
||||||
|
|
||||||
BufferedInputStream imp = new BufferedInputStream(new FileInputStream(
|
|
||||||
file));
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
int len;
|
|
||||||
boolean done = false;
|
|
||||||
boolean isAscii = false;
|
|
||||||
|
|
||||||
while ((len = imp.read(buf, 0, buf.length)) != -1) {
|
|
||||||
// Check if the stream is only ascii.
|
|
||||||
isAscii = det.isAscii(buf, len);
|
|
||||||
if (isAscii) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// DoIt if non-ascii and not done yet.
|
|
||||||
done = det.DoIt(buf, len, false);
|
|
||||||
if (done) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imp.close();
|
|
||||||
det.DataEnd();
|
|
||||||
|
|
||||||
if (isAscii) {
|
|
||||||
observer.encoding = "ASCII";
|
|
||||||
observer.found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!observer.isFound()) {
|
|
||||||
String[] prob = det.getProbableCharsets();
|
|
||||||
// // 这里将可能的字符集组合起来返回
|
|
||||||
// for (int i = 0; i < prob.length; i++) {
|
|
||||||
// if (i == 0) {
|
|
||||||
// encoding = prob[i];
|
|
||||||
// } else {
|
|
||||||
// encoding += "," + prob[i];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if (prob.length > 0) {
|
|
||||||
// 在没有发现情况下,去第一个可能的编码
|
|
||||||
observer.encoding = prob[0];
|
|
||||||
} else {
|
|
||||||
observer.encoding = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author liaohongwei
|
|
||||||
* @Description: 文件字符编码观察者, 但判断出字符编码时候调用
|
|
||||||
* @date 2016年6月20日 下午2:27:06
|
|
||||||
*/
|
|
||||||
public static class Observer implements nsICharsetDetectionObserver {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Fields encoding : 字符编码
|
|
||||||
*/
|
|
||||||
private String encoding = null;
|
|
||||||
/**
|
|
||||||
* @Fields found : 是否找到字符集
|
|
||||||
*/
|
|
||||||
private boolean found = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void Notify(String charset) {
|
|
||||||
this.encoding = charset;
|
|
||||||
this.found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return encoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFound() {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Observer [encoding=" + encoding + ", found=" + found + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
package cn.keking.utils;
|
|
||||||
|
|
||||||
import cn.keking.config.ConfigConstants;
|
|
||||||
import cn.keking.model.FileAttribute;
|
|
||||||
import cn.keking.model.FileType;
|
|
||||||
import cn.keking.service.cache.CacheService;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author yudian-it
|
|
||||||
* @date 2017/11/13
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class FileUtils {
|
|
||||||
|
|
||||||
private static final String DEFAULT_CONVERTER_CHARSET = System.getProperty("sun.jnu.encoding");
|
|
||||||
|
|
||||||
private final String fileDir = ConfigConstants.getFileDir();
|
|
||||||
|
|
||||||
private final CacheService cacheService;
|
|
||||||
|
|
||||||
public FileUtils(CacheService cacheService) {
|
|
||||||
this.cacheService = cacheService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 已转换过的文件集合(缓存)
|
|
||||||
*/
|
|
||||||
public Map<String, String> listConvertedFiles() {
|
|
||||||
return cacheService.getPDFCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 已转换过的文件,根据文件名获取
|
|
||||||
*/
|
|
||||||
public String getConvertedFile(String key) {
|
|
||||||
return cacheService.getPDFCache(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param key pdf本地路径
|
|
||||||
* @return 已将pdf转换成图片的图片本地相对路径
|
|
||||||
*/
|
|
||||||
public Integer getConvertedPdfImage(String key) {
|
|
||||||
return cacheService.getPdfImageCache(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
|
|
||||||
*
|
|
||||||
* @param url url
|
|
||||||
* @return 文件类型
|
|
||||||
*/
|
|
||||||
public FileType typeFromUrl(String url) {
|
|
||||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
|
||||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
|
||||||
return typeFromFileName(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileType typeFromFileName(String fileName) {
|
|
||||||
String[] simText = ConfigConstants.getSimText();
|
|
||||||
String[] media = ConfigConstants.getMedia();
|
|
||||||
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
|
||||||
if (listPictureTypes().contains(fileType.toLowerCase())) {
|
|
||||||
return FileType.picture;
|
|
||||||
}
|
|
||||||
if (listArchiveTypes().contains(fileType.toLowerCase())) {
|
|
||||||
return FileType.compress;
|
|
||||||
}
|
|
||||||
if (listOfficeTypes().contains(fileType.toLowerCase())) {
|
|
||||||
return FileType.office;
|
|
||||||
}
|
|
||||||
if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
|
|
||||||
return FileType.simText;
|
|
||||||
}
|
|
||||||
if (Arrays.asList(media).contains(fileType.toLowerCase())) {
|
|
||||||
return FileType.media;
|
|
||||||
}
|
|
||||||
if ("pdf".equalsIgnoreCase(fileType)) {
|
|
||||||
return FileType.pdf;
|
|
||||||
}
|
|
||||||
if ("dwg".equalsIgnoreCase(fileType)) {
|
|
||||||
return FileType.cad;
|
|
||||||
}
|
|
||||||
return FileType.other;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 从url中剥离出文件名
|
|
||||||
* @param url
|
|
||||||
* 格式如:http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k=
|
|
||||||
* @return 文件名
|
|
||||||
*/
|
|
||||||
public String getFileNameFromURL(String url) {
|
|
||||||
// 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题
|
|
||||||
// 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名
|
|
||||||
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?"): url.length());
|
|
||||||
return noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从路径中获取文件负
|
|
||||||
* @param path
|
|
||||||
* 类似这种:C:\Users\yudian-it\Downloads
|
|
||||||
* @return 文件名
|
|
||||||
*/
|
|
||||||
public String getFileNameFromPath(String path) {
|
|
||||||
return path.substring(path.lastIndexOf(File.separator) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> listPictureTypes(){
|
|
||||||
List<String> list = Lists.newArrayList();
|
|
||||||
list.add("jpg");
|
|
||||||
list.add("jpeg");
|
|
||||||
list.add("png");
|
|
||||||
list.add("gif");
|
|
||||||
list.add("bmp");
|
|
||||||
list.add("ico");
|
|
||||||
list.add("RAW");
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> listArchiveTypes(){
|
|
||||||
List<String> list = Lists.newArrayList();
|
|
||||||
list.add("rar");
|
|
||||||
list.add("zip");
|
|
||||||
list.add("jar");
|
|
||||||
list.add("7-zip");
|
|
||||||
list.add("tar");
|
|
||||||
list.add("gzip");
|
|
||||||
list.add("7z");
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> listOfficeTypes() {
|
|
||||||
List<String> list = Lists.newArrayList();
|
|
||||||
list.add("docx");
|
|
||||||
list.add("doc");
|
|
||||||
list.add("xls");
|
|
||||||
list.add("xlsx");
|
|
||||||
list.add("ppt");
|
|
||||||
list.add("pptx");
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取相对路径
|
|
||||||
* @param absolutePath 绝对路径
|
|
||||||
* @return 相对路径
|
|
||||||
*/
|
|
||||||
public String getRelativePath(String absolutePath) {
|
|
||||||
return absolutePath.substring(fileDir.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加转换后PDF缓存
|
|
||||||
* @param fileName pdf文件名
|
|
||||||
* @param value 缓存相对路径
|
|
||||||
*/
|
|
||||||
public void addConvertedFile(String fileName, String value){
|
|
||||||
cacheService.putPDFCache(fileName, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加转换后图片组缓存
|
|
||||||
* @param pdfFilePath pdf文件绝对路径
|
|
||||||
* @param num 图片张数
|
|
||||||
*/
|
|
||||||
public void addConvertedPdfImage(String pdfFilePath, int num){
|
|
||||||
cacheService.putPdfImageCache(pdfFilePath, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取redis中压缩包内图片文件
|
|
||||||
* @param fileKey fileKey
|
|
||||||
* @return 图片文件访问url列表
|
|
||||||
*/
|
|
||||||
public List<String> getImgCache(String fileKey){
|
|
||||||
return cacheService.getImgCache(fileKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置redis中压缩包内图片文件
|
|
||||||
* @param fileKey fileKey
|
|
||||||
* @param imgs 图片文件访问url列表
|
|
||||||
*/
|
|
||||||
public void putImgCache(String fileKey,List<String> imgs){
|
|
||||||
cacheService.putImgCache(fileKey, imgs);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断文件编码格式
|
|
||||||
* @param path 绝对路径
|
|
||||||
* @return 编码格式
|
|
||||||
*/
|
|
||||||
public String getFileEncodeUTFGBK(String path){
|
|
||||||
String enc = Charset.forName("GBK").name();
|
|
||||||
File file = new File(path);
|
|
||||||
InputStream in;
|
|
||||||
try {
|
|
||||||
in = new FileInputStream(file);
|
|
||||||
byte[] b = new byte[3];
|
|
||||||
in.read(b);
|
|
||||||
in.close();
|
|
||||||
if (b[0] == -17 && b[1] == -69 && b[2] == -65) {
|
|
||||||
enc = StandardCharsets.UTF_8.name();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
System.out.println("文件编码格式为:" + enc);
|
|
||||||
return enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对转换后的文件进行操作(改变编码方式)
|
|
||||||
* @param outFilePath 文件绝对路径
|
|
||||||
*/
|
|
||||||
public void doActionConvertedFile(String outFilePath) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
try (InputStream inputStream = new FileInputStream(outFilePath);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, DEFAULT_CONVERTER_CHARSET))){
|
|
||||||
String line;
|
|
||||||
while(null != (line = reader.readLine())){
|
|
||||||
if (line.contains("charset=gb2312")) {
|
|
||||||
line = line.replace("charset=gb2312", "charset=utf-8");
|
|
||||||
}
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
// 添加sheet控制头
|
|
||||||
sb.append("<script src=\"js/jquery-3.0.0.min.js\" type=\"text/javascript\"></script>");
|
|
||||||
sb.append("<script src=\"js/excel.header.js\" type=\"text/javascript\"></script>");
|
|
||||||
sb.append("<link rel=\"stylesheet\" href=\"bootstrap/css/bootstrap.min.css\">");
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
// 重新写入文件
|
|
||||||
try(FileOutputStream fos = new FileOutputStream(outFilePath);
|
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
|
|
||||||
writer.write(sb.toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取文件后缀
|
|
||||||
* @param url url
|
|
||||||
* @return 文件后缀
|
|
||||||
*/
|
|
||||||
private String suffixFromUrl(String url) {
|
|
||||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
|
||||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
|
||||||
return suffixFromFileName(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String suffixFromFileName(String fileName) {
|
|
||||||
return fileName.substring(fileName.lastIndexOf(".") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取url中的参数
|
|
||||||
* @param url url
|
|
||||||
* @param name 参数名
|
|
||||||
* @return 参数值
|
|
||||||
*/
|
|
||||||
public String getUrlParameterReg(String url, String name) {
|
|
||||||
Map<String, String> mapRequest = new HashMap<>();
|
|
||||||
String strUrlParam = truncateUrlPage(url);
|
|
||||||
if (strUrlParam == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
//每个键值为一组
|
|
||||||
String[] arrSplit = strUrlParam.split("[&]");
|
|
||||||
for(String strSplit : arrSplit) {
|
|
||||||
String[] arrSplitEqual = strSplit.split("[=]");
|
|
||||||
//解析出键值
|
|
||||||
if(arrSplitEqual.length > 1) {
|
|
||||||
//正确解析
|
|
||||||
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
|
|
||||||
} else if (!arrSplitEqual[0].equals("")) {
|
|
||||||
//只有参数没有值,不加入
|
|
||||||
mapRequest.put(arrSplitEqual[0], "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mapRequest.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去掉url中的路径,留下请求参数部分
|
|
||||||
* @param strURL url地址
|
|
||||||
* @return url请求参数部分
|
|
||||||
*/
|
|
||||||
private String truncateUrlPage(String strURL) {
|
|
||||||
String strAllParam = null;
|
|
||||||
strURL = strURL.trim();
|
|
||||||
String[] arrSplit = strURL.split("[?]");
|
|
||||||
if(strURL.length() > 1) {
|
|
||||||
if(arrSplit.length > 1) {
|
|
||||||
if(arrSplit[1] != null) {
|
|
||||||
strAllParam=arrSplit[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strAllParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件属性
|
|
||||||
* @param url url
|
|
||||||
* @return 文件属性
|
|
||||||
*/
|
|
||||||
public FileAttribute getFileAttribute(String url) {
|
|
||||||
String fileName;
|
|
||||||
FileType type;
|
|
||||||
String suffix;
|
|
||||||
String fullFileName = getUrlParameterReg(url, "fullfilename");
|
|
||||||
if (!StringUtils.isEmpty(fullFileName)) {
|
|
||||||
fileName = fullFileName;
|
|
||||||
type = typeFromFileName(fileName);
|
|
||||||
suffix = suffixFromFileName(fileName);
|
|
||||||
} else {
|
|
||||||
fileName = getFileNameFromURL(url);
|
|
||||||
type = typeFromUrl(url);
|
|
||||||
suffix = suffixFromUrl(url);
|
|
||||||
}
|
|
||||||
return new FileAttribute(type,suffix,fileName,url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package cn.keking.utils;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
|
||||||
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class PdfUtils {
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
|
||||||
|
|
||||||
private final FileUtils fileUtils;
|
|
||||||
|
|
||||||
@Value("${server.tomcat.uri-encoding:UTF-8}")
|
|
||||||
private String uriEncoding;
|
|
||||||
|
|
||||||
public PdfUtils(FileUtils fileUtils) {
|
|
||||||
this.fileUtils = fileUtils;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String baseUrl) {
|
|
||||||
List<String> imageUrls = new ArrayList<>();
|
|
||||||
Integer imageCount = fileUtils.getConvertedPdfImage(pdfFilePath);
|
|
||||||
String imageFileSuffix = ".jpg";
|
|
||||||
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
|
|
||||||
String urlPrefix = null;
|
|
||||||
try {
|
|
||||||
urlPrefix = baseUrl + URLEncoder.encode(URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20"), uriEncoding);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
logger.error("UnsupportedEncodingException", e);
|
|
||||||
urlPrefix = baseUrl + pdfFolder;
|
|
||||||
}
|
|
||||||
if (imageCount != null && imageCount > 0) {
|
|
||||||
for (int i = 0; i < imageCount ; i++)
|
|
||||||
imageUrls.add(urlPrefix + "/" + i + imageFileSuffix);
|
|
||||||
return imageUrls;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
File pdfFile = new File(pdfFilePath);
|
|
||||||
PDDocument doc = PDDocument.load(pdfFile);
|
|
||||||
int pageCount = doc.getNumberOfPages();
|
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(doc);
|
|
||||||
|
|
||||||
int index = pdfFilePath.lastIndexOf(".");
|
|
||||||
String folder = pdfFilePath.substring(0, index);
|
|
||||||
|
|
||||||
File path = new File(folder);
|
|
||||||
if (!path.exists()) {
|
|
||||||
path.mkdirs();
|
|
||||||
}
|
|
||||||
String imageFilePath;
|
|
||||||
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
|
|
||||||
imageFilePath = folder + File.separator + pageIndex + imageFileSuffix;
|
|
||||||
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 105, ImageType.RGB);
|
|
||||||
ImageIOUtil.writeImage(image, imageFilePath, 105);
|
|
||||||
imageUrls.add(urlPrefix + "/" + pageIndex + imageFileSuffix);
|
|
||||||
}
|
|
||||||
doc.close();
|
|
||||||
fileUtils.addConvertedPdfImage(pdfFilePath, pageCount);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e);
|
|
||||||
}
|
|
||||||
return imageUrls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,56 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
|
||||||
<title>普通文本预览</title>
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id = "text"></div>
|
|
||||||
<script src="js/jquery-3.0.0.min.js" type="text/javascript"></script>
|
|
||||||
<script src="js/watermark.js" type="text/javascript"></script>
|
|
||||||
<script>
|
|
||||||
/*初始化水印*/
|
|
||||||
window.onload = function() {
|
|
||||||
var watermarkTxt = '${watermarkTxt}';
|
|
||||||
if (watermarkTxt !== '') {
|
|
||||||
watermark.init({
|
|
||||||
watermark_txt: '${watermarkTxt}',
|
|
||||||
watermark_x: 0,
|
|
||||||
watermark_y: 0,
|
|
||||||
watermark_rows: 0,
|
|
||||||
watermark_cols: 0,
|
|
||||||
watermark_x_space: ${watermarkXSpace},
|
|
||||||
watermark_y_space: ${watermarkYSpace},
|
|
||||||
watermark_font: '${watermarkFont}',
|
|
||||||
watermark_fontsize: '${watermarkFontsize}',
|
|
||||||
watermark_color:'${watermarkColor}',
|
|
||||||
watermark_alpha: ${watermarkAlpha},
|
|
||||||
watermark_width: ${watermarkWidth},
|
|
||||||
watermark_height: ${watermarkHeight},
|
|
||||||
watermark_angle: ${watermarkAngle},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: 'GET',
|
|
||||||
url: '${ordinaryUrl}',
|
|
||||||
success: function (data) {
|
|
||||||
$("#text").html("<pre>" + data + "</pre>");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>cn.keking</groupId>
|
<groupId>cn.keking</groupId>
|
||||||
<artifactId>jodconverter-core</artifactId>
|
<artifactId>office-plugin</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -19,6 +19,7 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.artofsolving.jodconverter.util.ConfigUtils;
|
||||||
import org.artofsolving.jodconverter.util.PlatformUtils;
|
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||||
|
|
||||||
import com.sun.star.beans.PropertyValue;
|
import com.sun.star.beans.PropertyValue;
|
||||||
@@ -55,7 +56,7 @@ public class OfficeUtils {
|
|||||||
Map<String,Object> subProperties = (Map<String,Object>) value;
|
Map<String,Object> subProperties = (Map<String,Object>) value;
|
||||||
value = toUnoProperties(subProperties);
|
value = toUnoProperties(subProperties);
|
||||||
}
|
}
|
||||||
propertyValues[i++] = property((String) entry.getKey(), value);
|
propertyValues[i++] = property(entry.getKey(), value);
|
||||||
}
|
}
|
||||||
return propertyValues;
|
return propertyValues;
|
||||||
}
|
}
|
||||||
@@ -68,7 +69,7 @@ public class OfficeUtils {
|
|||||||
|
|
||||||
public static File getDefaultOfficeHome() {
|
public static File getDefaultOfficeHome() {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
String customizedConfigPath = getCustomizedConfigPath();
|
String customizedConfigPath = ConfigUtils.getCustomizedConfigPath();
|
||||||
try {
|
try {
|
||||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
|
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
|
||||||
properties.load(bufferedReader);
|
properties.load(bufferedReader);
|
||||||
@@ -80,7 +81,7 @@ public class OfficeUtils {
|
|||||||
}
|
}
|
||||||
if (PlatformUtils.isWindows()) {
|
if (PlatformUtils.isWindows()) {
|
||||||
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
|
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
|
||||||
String homePath = OfficeUtils.getHomePath();
|
String homePath = ConfigUtils.getHomePath();
|
||||||
String programFiles = System.getenv("ProgramFiles(x86)");
|
String programFiles = System.getenv("ProgramFiles(x86)");
|
||||||
if (programFiles == null) {
|
if (programFiles == null) {
|
||||||
programFiles = System.getenv("ProgramFiles");
|
programFiles = System.getenv("ProgramFiles");
|
||||||
@@ -127,30 +128,7 @@ public class OfficeUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getHomePath() {
|
|
||||||
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
|
|
||||||
if (userDir == null) {
|
|
||||||
userDir = System.getProperty("user.dir");
|
|
||||||
}
|
|
||||||
if (userDir.endsWith("bin")) {
|
|
||||||
userDir = userDir.substring(0, userDir.length() - 4);
|
|
||||||
} else {
|
|
||||||
String separator = File.separator;
|
|
||||||
if (userDir.contains("jodconverter-web")) {
|
|
||||||
userDir = userDir + separator + "src" + separator + "main";
|
|
||||||
} else {
|
|
||||||
userDir = userDir + separator + "jodconverter-web" + separator + "src" + separator + "main";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return userDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getCustomizedConfigPath() {
|
|
||||||
String homePath = OfficeUtils.getHomePath();
|
|
||||||
String separator = java.io.File.separator;
|
|
||||||
String configFilePath = homePath + separator + "config" + separator + "application.properties";
|
|
||||||
return configFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SpringBoot application.properties 支持从环境变量获取值
|
* SpringBoot application.properties 支持从环境变量获取值
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user