mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2025-04-05 17:37:49 +08:00
文件url采用base64加encodeURI双重编码,彻底解决各种奇葩文件名导致的下载异常
This commit is contained in:
parent
aaf396fbc8
commit
486c09b24a
@ -1,5 +1,6 @@
|
|||||||
[#ftl]
|
[#ftl]
|
||||||
[#-- @implicitly included --]
|
[#-- @implicitly included --]
|
||||||
|
[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
|
||||||
[#-- @ftlvariable name="imgUrls" type="String" --]
|
[#-- @ftlvariable name="imgUrls" type="String" --]
|
||||||
[#-- @ftlvariable name="textData" type="java.lang.String" --]
|
[#-- @ftlvariable name="textData" type="java.lang.String" --]
|
||||||
[#-- @ftlvariable name="xmlContent" type="java.lang.String" --]
|
[#-- @ftlvariable name="xmlContent" type="java.lang.String" --]
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,13 +4,13 @@ import cn.keking.config.ConfigConstants;
|
|||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.model.FileType;
|
import cn.keking.model.FileType;
|
||||||
import cn.keking.service.cache.CacheService;
|
import cn.keking.service.cache.CacheService;
|
||||||
|
import cn.keking.utils.WebUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -189,55 +189,6 @@ public class FileHandlerService {
|
|||||||
return fileName.substring(fileName.lastIndexOf(".") + 1);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文件属性
|
* 获取文件属性
|
||||||
*
|
*
|
||||||
@ -249,7 +200,7 @@ public class FileHandlerService {
|
|||||||
String suffix;
|
String suffix;
|
||||||
FileType type;
|
FileType type;
|
||||||
String fileName;
|
String fileName;
|
||||||
String fullFileName = this.getUrlParameterReg(url, "fullfilename");
|
String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
|
||||||
if (StringUtils.hasText(fullFileName)) {
|
if (StringUtils.hasText(fullFileName)) {
|
||||||
fileName = fullFileName;
|
fileName = fullFileName;
|
||||||
type = this.typeFromFileName(fullFileName);
|
type = this.typeFromFileName(fullFileName);
|
||||||
|
@ -23,19 +23,11 @@ import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
|
|||||||
public class CadFilePreviewImpl implements FilePreview {
|
public class CadFilePreviewImpl implements FilePreview {
|
||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
|
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
|
|
||||||
private final CadUtils cadUtils;
|
private final CadUtils cadUtils;
|
||||||
|
|
||||||
private final PdfUtils pdfUtils;
|
private final PdfUtils pdfUtils;
|
||||||
|
|
||||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService,
|
public CadFilePreviewImpl(FileHandlerService fileHandlerService, CadUtils cadUtils, PdfUtils pdfUtils) {
|
||||||
DownloadUtils downloadUtils,
|
|
||||||
CadUtils cadUtils,
|
|
||||||
PdfUtils pdfUtils) {
|
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
this.cadUtils = cadUtils;
|
this.cadUtils = cadUtils;
|
||||||
this.pdfUtils = pdfUtils;
|
this.pdfUtils = pdfUtils;
|
||||||
|
|
||||||
@ -58,7 +50,7 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
String filePath;
|
String filePath;
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", suffix);
|
model.addAttribute("fileType", suffix);
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -19,12 +19,10 @@ import org.springframework.util.StringUtils;
|
|||||||
public class CompressFilePreviewImpl implements FilePreview {
|
public class CompressFilePreviewImpl implements FilePreview {
|
||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
private final CompressFileReader compressFileReader;
|
private final CompressFileReader compressFileReader;
|
||||||
|
|
||||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, DownloadUtils downloadUtils, CompressFileReader compressFileReader) {
|
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
this.compressFileReader = compressFileReader;
|
this.compressFileReader = compressFileReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +33,7 @@ public class CompressFilePreviewImpl implements FilePreview {
|
|||||||
String fileTree = null;
|
String fileTree = null;
|
||||||
// 判断文件名是否存在(redis缓存读取)
|
// 判断文件名是否存在(redis缓存读取)
|
||||||
if (!StringUtils.hasText(fileHandlerService.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) {
|
if (!StringUtils.hasText(fileHandlerService.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) {
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", suffix);
|
model.addAttribute("fileType", suffix);
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -17,13 +17,9 @@ import org.springframework.ui.Model;
|
|||||||
@Service
|
@Service
|
||||||
public class MediaFilePreviewImpl implements FilePreview {
|
public class MediaFilePreviewImpl implements FilePreview {
|
||||||
|
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
|
|
||||||
public MediaFilePreviewImpl(DownloadUtils downloadUtils,
|
public MediaFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||||
FileHandlerService fileHandlerService) {
|
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +27,7 @@ public class MediaFilePreviewImpl implements FilePreview {
|
|||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileAttribute.getName());
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -24,13 +24,11 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final PdfUtils pdfUtils;
|
private final PdfUtils pdfUtils;
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
private final OfficeToPdfService officeToPdfService;
|
private final OfficeToPdfService officeToPdfService;
|
||||||
|
|
||||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils, DownloadUtils downloadUtils, OfficeToPdfService officeToPdfService) {
|
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils, OfficeToPdfService officeToPdfService) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.pdfUtils = pdfUtils;
|
this.pdfUtils = pdfUtils;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
this.officeToPdfService = officeToPdfService;
|
this.officeToPdfService = officeToPdfService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +49,7 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
String filePath;
|
String filePath;
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", suffix);
|
model.addAttribute("fileType", suffix);
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -21,19 +21,12 @@ import java.util.List;
|
|||||||
public class PdfFilePreviewImpl implements FilePreview {
|
public class PdfFilePreviewImpl implements FilePreview {
|
||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
|
|
||||||
private final PdfUtils pdfUtils;
|
private final PdfUtils pdfUtils;
|
||||||
|
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
|
|
||||||
private static final String FILE_DIR = ConfigConstants.getFileDir();
|
private static final String FILE_DIR = ConfigConstants.getFileDir();
|
||||||
|
|
||||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService,
|
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils) {
|
||||||
PdfUtils pdfUtils,
|
|
||||||
DownloadUtils downloadUtils) {
|
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.pdfUtils = pdfUtils;
|
this.pdfUtils = pdfUtils;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -47,7 +40,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
||||||
//当文件不存在时,就去下载
|
//当文件不存在时,就去下载
|
||||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", suffix);
|
model.addAttribute("fileType", suffix);
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
@ -76,7 +69,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, pdfName);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", suffix);
|
model.addAttribute("fileType", suffix);
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -20,12 +20,8 @@ public class PictureFilePreviewImpl implements FilePreview {
|
|||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
|
|
||||||
private final DownloadUtils downloadUtils;
|
public PictureFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||||
|
|
||||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService,
|
|
||||||
DownloadUtils downloadUtils) {
|
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -39,7 +35,7 @@ public class PictureFilePreviewImpl implements FilePreview {
|
|||||||
}
|
}
|
||||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
|
@ -23,16 +23,10 @@ public class SimTextFilePreviewImpl implements FilePreview {
|
|||||||
public static final String TEXT_TYPE = "textType";
|
public static final String TEXT_TYPE = "textType";
|
||||||
public static final String DEFAULT_TEXT_TYPE = "simText";
|
public static final String DEFAULT_TEXT_TYPE = "simText";
|
||||||
|
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
|
|
||||||
public SimTextFilePreviewImpl(DownloadUtils downloadUtils) {
|
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
String fileName = fileAttribute.getName();
|
String fileName = fileAttribute.getName();
|
||||||
ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||||
if (0 != response.getCode()) {
|
if (0 != response.getCode()) {
|
||||||
model.addAttribute("msg", response.getMsg());
|
model.addAttribute("msg", response.getMsg());
|
||||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package cn.keking.utils;
|
package cn.keking.utils;
|
||||||
|
|
||||||
import cn.keking.config.ConfigConstants;
|
import cn.keking.config.ConfigConstants;
|
||||||
import cn.keking.hutool.URLUtil;
|
|
||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.model.FileType;
|
import cn.keking.model.FileType;
|
||||||
import cn.keking.model.ReturnResponse;
|
import cn.keking.model.ReturnResponse;
|
||||||
import cn.keking.service.FileHandlerService;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
@ -18,27 +15,20 @@ import java.util.UUID;
|
|||||||
/**
|
/**
|
||||||
* @author yudian-it
|
* @author yudian-it
|
||||||
*/
|
*/
|
||||||
@Component
|
|
||||||
public class DownloadUtils {
|
public class DownloadUtils {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(DownloadUtils.class);
|
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_USERNAME = "ftp.username";
|
||||||
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
|
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
|
||||||
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
|
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 fileAttribute fileAttribute
|
||||||
* @param fileName 文件名
|
* @param fileName 文件名
|
||||||
* @return 本地文件绝对路径
|
* @return 本地文件绝对路径
|
||||||
*/
|
*/
|
||||||
public ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||||
String urlStr = fileAttribute.getUrl();
|
String urlStr = fileAttribute.getUrl();
|
||||||
String type = fileAttribute.getSuffix();
|
String type = fileAttribute.getSuffix();
|
||||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||||
@ -60,9 +50,9 @@ public class DownloadUtils {
|
|||||||
OutputStream os = new FileOutputStream(realPath);
|
OutputStream os = new FileOutputStream(realPath);
|
||||||
saveBytesToOutStream(bytes, os);
|
saveBytesToOutStream(bytes, os);
|
||||||
} else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
|
} else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
|
||||||
String ftpUsername = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||||
String ftpPassword = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||||
String ftpControlEncoding = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||||
} else {
|
} else {
|
||||||
response.setCode(1);
|
response.setCode(1);
|
||||||
@ -72,7 +62,7 @@ public class DownloadUtils {
|
|||||||
response.setContent(realPath);
|
response.setContent(realPath);
|
||||||
response.setMsg(fileName);
|
response.setMsg(fileName);
|
||||||
if (FileType.simText.equals(fileAttribute.getType())) {
|
if (FileType.simText.equals(fileAttribute.getType())) {
|
||||||
this.convertTextPlainFileCharsetToUtf8(realPath);
|
convertTextPlainFileCharsetToUtf8(realPath);
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
} catch (IOException e) {
|
} 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);
|
InputStream is = getInputStreamFromUrl(urlStr);
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
urlStr = URLUtil.normalize(urlStr, true, true);
|
// urlStr = URLUtil.normalize(urlStr, true, true);
|
||||||
is = getInputStreamFromUrl(urlStr);
|
is = getInputStreamFromUrl(urlStr);
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
logger.error("文件下载异常:url:{}", urlStr);
|
logger.error("文件下载异常:url:{}", urlStr);
|
||||||
@ -101,12 +91,12 @@ public class DownloadUtils {
|
|||||||
return getBytesFromStream(is);
|
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.write(b);
|
||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getInputStreamFromUrl(String urlStr) {
|
private static InputStream getInputStreamFromUrl(String urlStr) {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(urlStr);
|
URL url = new URL(urlStr);
|
||||||
URLConnection connection = url.openConnection();
|
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();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int len;
|
int len;
|
||||||
@ -139,7 +129,7 @@ public class DownloadUtils {
|
|||||||
*
|
*
|
||||||
* @param filePath 文件路径
|
* @param filePath 文件路径
|
||||||
*/
|
*/
|
||||||
private void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
|
private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
|
||||||
File sourceFile = new File(filePath);
|
File sourceFile = new File(filePath);
|
||||||
if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
|
if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
|
||||||
String encoding = FileUtils.getFileEncode(filePath);
|
String encoding = FileUtils.getFileEncode(filePath);
|
||||||
|
60
server/src/main/java/cn/keking/utils/WebUtils.java
Normal file
60
server/src/main/java/cn/keking/utils/WebUtils.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -52,8 +52,8 @@ public class FileController {
|
|||||||
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "存在同名文件,请先删除原有文件再次上传", null));
|
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "存在同名文件,请先删除原有文件再次上传", null));
|
||||||
}
|
}
|
||||||
File outFile = new File(fileDir + demoPath);
|
File outFile = new File(fileDir + demoPath);
|
||||||
if (!outFile.exists()) {
|
if (!outFile.exists() && !outFile.mkdirs()) {
|
||||||
outFile.mkdirs();
|
logger.error("创建文件夹【{}】失败,请检查目录权限!",fileDir + demoPath);
|
||||||
}
|
}
|
||||||
logger.info("上传文件:{}", fileDir + demoPath + fileName);
|
logger.info("上传文件:{}", fileDir + demoPath + fileName);
|
||||||
try(InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileDir + demoPath + fileName)) {
|
try(InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileDir + demoPath + fileName)) {
|
||||||
@ -72,8 +72,8 @@ public class FileController {
|
|||||||
}
|
}
|
||||||
File file = new File(fileDir + demoPath + fileName);
|
File file = new File(fileDir + demoPath + fileName);
|
||||||
logger.info("删除文件:{}", file.getAbsolutePath());
|
logger.info("删除文件:{}", file.getAbsolutePath());
|
||||||
if (file.exists()) {
|
if (file.exists() && !file.delete()) {
|
||||||
file.delete();
|
logger.error("删除文件【{}】失败,请检查目录权限!",file.getPath());
|
||||||
}
|
}
|
||||||
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
|
return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ public class FileController {
|
|||||||
File file = new File(fileDir + demoPath);
|
File file = new File(fileDir + demoPath);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(file1 -> {
|
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());
|
fileName.put("fileName", demoDir + "/" + file1.getName());
|
||||||
list.add(fileName);
|
list.add(fileName);
|
||||||
});
|
});
|
||||||
|
@ -7,10 +7,12 @@ import cn.keking.service.FilePreviewFactory;
|
|||||||
import cn.keking.service.cache.CacheService;
|
import cn.keking.service.cache.CacheService;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.DownloadUtils;
|
||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
|
import com.thoughtworks.xstream.core.util.Base64JavaUtilCodec;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.util.Base64Utils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@ -33,22 +35,20 @@ public class OnlinePreviewController {
|
|||||||
private final FilePreviewFactory previewFactory;
|
private final FilePreviewFactory previewFactory;
|
||||||
private final CacheService cacheService;
|
private final CacheService cacheService;
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final DownloadUtils downloadUtils;
|
|
||||||
|
|
||||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService, DownloadUtils downloadUtils) {
|
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService) {
|
||||||
this.previewFactory = filePreviewFactory;
|
this.previewFactory = filePreviewFactory;
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.cacheService = cacheService;
|
this.cacheService = cacheService;
|
||||||
this.downloadUtils = downloadUtils;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@RequestMapping(value = "/onlinePreview")
|
@RequestMapping(value = "/onlinePreview")
|
||||||
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
||||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url,req);
|
String fileUrl = new String(Base64Utils.decodeFromString(url));
|
||||||
|
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl,req);
|
||||||
FilePreview filePreview = previewFactory.get(fileAttribute);
|
FilePreview filePreview = previewFactory.get(fileAttribute);
|
||||||
logger.info("预览文件url:{},previewType:{}", url, fileAttribute.getType());
|
logger.info("预览文件url:{},previewType:{}", fileUrl, fileAttribute.getType());
|
||||||
return filePreview.filePreviewHandle(url, model, fileAttribute);
|
return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/picturesPreview")
|
@RequestMapping(value = "/picturesPreview")
|
||||||
@ -78,8 +78,8 @@ public class OnlinePreviewController {
|
|||||||
public void getCorsFile(String urlPath, HttpServletResponse response) {
|
public void getCorsFile(String urlPath, HttpServletResponse response) {
|
||||||
logger.info("下载跨域pdf文件url:{}", urlPath);
|
logger.info("下载跨域pdf文件url:{}", urlPath);
|
||||||
try {
|
try {
|
||||||
byte[] bytes = downloadUtils.getBytesFromUrl(urlPath);
|
byte[] bytes = DownloadUtils.getBytesFromUrl(urlPath);
|
||||||
downloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
|
DownloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("下载跨域pdf文件异常,url:{}", urlPath, e);
|
logger.error("下载跨域pdf文件异常,url:{}", urlPath, e);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ public class BaseUrlFilter implements Filter {
|
|||||||
pathBuilder.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
|
pathBuilder.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
|
||||||
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
.append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
|
||||||
String baseUrlTmp = ConfigConstants.getBaseUrl();
|
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("/")) {
|
if (!baseUrlTmp.endsWith("/")) {
|
||||||
baseUrlTmp = baseUrlTmp.concat("/");
|
baseUrlTmp = baseUrlTmp.concat("/");
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,11 @@
|
|||||||
<script src="js/watermark.js" type="text/javascript"></script>
|
<script src="js/watermark.js" type="text/javascript"></script>
|
||||||
<script type="text/javascript" src="js/jquery-3.0.0.min.js"></script>
|
<script type="text/javascript" src="js/jquery-3.0.0.min.js"></script>
|
||||||
<script type="text/javascript" src="js/jquery.ztree.core.js"></script>
|
<script type="text/javascript" src="js/jquery.ztree.core.js"></script>
|
||||||
|
<script type="text/javascript" src="js/base64.min.js" ></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var data = JSON.parse('${fileTree}');
|
var data = JSON.parse('${fileTree}');
|
||||||
|
var baseUrl = "${baseUrl}";
|
||||||
var setting = {
|
var setting = {
|
||||||
view: {
|
view: {
|
||||||
fontCss : {"color":"blue"},
|
fontCss : {"color":"blue"},
|
||||||
@ -71,8 +74,8 @@
|
|||||||
} else {
|
} else {
|
||||||
fulls += ",resizable"; // 对于不支持screen属性的浏览器,可以手工进行最大化。 manually
|
fulls += ",resizable"; // 对于不支持screen属性的浏览器,可以手工进行最大化。 manually
|
||||||
}
|
}
|
||||||
window.open("onlinePreview?url="
|
var previewUrl = baseUrl + treeNode.fileName +"&fileKey="+ treeNode.fileKey;
|
||||||
+ encodeURIComponent("${baseUrl}" + treeNode.fileName)+"&fileKey="+ encodeURIComponent(treeNode.fileKey), "_blank",fulls);
|
window.open("onlinePreview?url=" + encodeURIComponent(Base64.encode(previewUrl)), "_blank",fulls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
||||||
<script type="text/javascript" src="bootstrap-table/bootstrap-table.min.js"></script>
|
<script type="text/javascript" src="bootstrap-table/bootstrap-table.min.js"></script>
|
||||||
<script type="text/javascript" src="gitalk/gitalk.min.js"></script>
|
<script type="text/javascript" src="gitalk/gitalk.min.js"></script>
|
||||||
|
<script type="text/javascript" src="js/base64.min.js" ></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -36,14 +37,14 @@
|
|||||||
成功实现:
|
成功实现:
|
||||||
<pre style="background-color: #2f332a;color: #cccccc">
|
<pre style="background-color: #2f332a;color: #cccccc">
|
||||||
var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
|
var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
|
||||||
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(url));
|
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(base64Encode(url)));
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
新增多图片同时预览功能,接口如下:
|
新增多图片同时预览功能,接口如下:
|
||||||
<pre style="background-color: #2f332a;color: #cccccc">
|
<pre style="background-color: #2f332a;color: #cccccc">
|
||||||
var fileUrl =url1+"|"+"url2";//多文件使用“|”字符隔开
|
var fileUrl =url1+"|"+"url2";//多文件使用“|”字符隔开
|
||||||
window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(fileUrl));
|
window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(base64Encode(fileUrl)));
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -195,7 +196,7 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(fil
|
|||||||
}).on('pre-body.bs.table', function (e,data) {
|
}).on('pre-body.bs.table', function (e,data) {
|
||||||
// 每个data添加一列用来操作
|
// 每个data添加一列用来操作
|
||||||
$(data).each(function (index, item) {
|
$(data).each(function (index, item) {
|
||||||
item.action = "<a class='btn btn-default' target='_blank' href='${baseUrl}onlinePreview?url="+ encodeURIComponent('${baseUrl}' + item.fileName) +"'>预览</a>" +
|
item.action = "<a class='btn btn-default' target='_blank' href='${baseUrl}onlinePreview?url="+ encodeURIComponent(Base64.encode('${baseUrl}' + item.fileName)) +"'>预览</a>" +
|
||||||
"<a class='btn btn-default' href='javascript:void(0);' onclick='deleteFile(\""+item.fileName+"\")'>删除</a>";
|
"<a class='btn btn-default' href='javascript:void(0);' onclick='deleteFile(\""+item.fileName+"\")'>删除</a>";
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
|
Loading…
Reference in New Issue
Block a user