Selaa lähdekoodia

文件url采用base64加encodeURI双重编码,彻底解决各种奇葩文件名导致的下载异常

chenkailing 4 vuotta sitten
vanhempi
commit
486c09b24a

+ 1 - 0
server/src/main/config/freemarker_implicit.ftl

@@ -1,5 +1,6 @@
 [#ftl]
 [#-- @implicitly included --]
+[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
 [#-- @ftlvariable name="imgUrls" type="String" --]
 [#-- @ftlvariable name="textData" type="java.lang.String" --]
 [#-- @ftlvariable name="xmlContent" type="java.lang.String" --]

+ 0 - 388
server/src/main/java/cn/keking/hutool/HexUtil.java

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

+ 0 - 283
server/src/main/java/cn/keking/hutool/StrUtil.java

@@ -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, &quot;default&quot;)  = &quot;default&quot;
-	 * nullToDefault(&quot;&quot;, &quot;default&quot;)    = &quot;&quot;
-	 * nullToDefault(&quot;  &quot;, &quot;default&quot;)  = &quot;  &quot;
-	 * nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;
-	 * </pre>
-	 *
-	 * @param str 要转换的字符串
-	 * @param defaultStr 默认字符串
-	 *
-	 * @return 字符串本身或指定的默认字符串
-	 */
-	public static String nullToDefault(CharSequence str, String defaultStr) {
-		return (str == null) ? defaultStr : str.toString();
-	}
-
-	/**
-	 * 当给定字符串为null时,转换为Empty
-	 *
-	 * @param str 被转换的字符串
-	 * @return 转换后的字符串
-	 */
-	public static String nullToEmpty(CharSequence str) {
-		return nullToDefault(str, EMPTY);
-	}
-}

+ 0 - 232
server/src/main/java/cn/keking/hutool/URLEncoder.java

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

+ 0 - 74
server/src/main/java/cn/keking/hutool/URLUtil.java

@@ -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);
-	}
-}

+ 2 - 51
server/src/main/java/cn/keking/service/FileHandlerService.java

@@ -4,13 +4,13 @@ import cn.keking.config.ConfigConstants;
 import cn.keking.model.FileAttribute;
 import cn.keking.model.FileType;
 import cn.keking.service.cache.CacheService;
+import cn.keking.utils.WebUtils;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.*;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -189,55 +189,6 @@ public class FileHandlerService {
         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;
         FileType type;
         String fileName;
-        String fullFileName = this.getUrlParameterReg(url, "fullfilename");
+        String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
         if (StringUtils.hasText(fullFileName)) {
             fileName = fullFileName;
             type = this.typeFromFileName(fullFileName);

+ 2 - 10
server/src/main/java/cn/keking/service/impl/CadFilePreviewImpl.java

@@ -23,19 +23,11 @@ import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
 public class CadFilePreviewImpl implements FilePreview {
 
     private final FileHandlerService fileHandlerService;
-
-    private final DownloadUtils downloadUtils;
-
     private final CadUtils cadUtils;
-
     private final PdfUtils pdfUtils;
 
-    public CadFilePreviewImpl(FileHandlerService fileHandlerService,
-                              DownloadUtils downloadUtils,
-                              CadUtils cadUtils,
-                              PdfUtils pdfUtils) {
+    public CadFilePreviewImpl(FileHandlerService fileHandlerService, CadUtils cadUtils, PdfUtils pdfUtils) {
         this.fileHandlerService = fileHandlerService;
-        this.downloadUtils = downloadUtils;
         this.cadUtils = cadUtils;
         this.pdfUtils = pdfUtils;
 
@@ -58,7 +50,7 @@ public class CadFilePreviewImpl implements FilePreview {
         // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
         if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
             String filePath;
-            ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
+            ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
             if (0 != response.getCode()) {
                 model.addAttribute("fileType", suffix);
                 model.addAttribute("msg", response.getMsg());

+ 2 - 4
server/src/main/java/cn/keking/service/impl/CompressFilePreviewImpl.java

@@ -19,12 +19,10 @@ import org.springframework.util.StringUtils;
 public class CompressFilePreviewImpl implements FilePreview {
 
     private final FileHandlerService fileHandlerService;
-    private final DownloadUtils downloadUtils;
     private final CompressFileReader compressFileReader;
 
-    public CompressFilePreviewImpl(FileHandlerService fileHandlerService, DownloadUtils downloadUtils, CompressFileReader compressFileReader) {
+    public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader) {
         this.fileHandlerService = fileHandlerService;
-        this.downloadUtils = downloadUtils;
         this.compressFileReader = compressFileReader;
     }
 
@@ -35,7 +33,7 @@ public class CompressFilePreviewImpl implements FilePreview {
         String fileTree = null;
         // 判断文件名是否存在(redis缓存读取)
         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()) {
                 model.addAttribute("fileType", suffix);
                 model.addAttribute("msg", response.getMsg());

+ 2 - 6
server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java

@@ -17,13 +17,9 @@ import org.springframework.ui.Model;
 @Service
 public class MediaFilePreviewImpl implements FilePreview {
 
-    private final DownloadUtils downloadUtils;
-
     private final FileHandlerService fileHandlerService;
 
-    public MediaFilePreviewImpl(DownloadUtils downloadUtils,
-                                FileHandlerService fileHandlerService) {
-        this.downloadUtils = downloadUtils;
+    public MediaFilePreviewImpl(FileHandlerService fileHandlerService) {
         this.fileHandlerService = fileHandlerService;
     }
 
@@ -31,7 +27,7 @@ public class MediaFilePreviewImpl implements FilePreview {
     public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
         // 不是http开头,浏览器不能直接访问,需下载到本地
         if (url != null && !url.toLowerCase().startsWith("http")) {
-            ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileAttribute.getName());
+            ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
             if (0 != response.getCode()) {
                 model.addAttribute("fileType", fileAttribute.getSuffix());
                 model.addAttribute("msg", response.getMsg());

+ 2 - 4
server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java

@@ -24,13 +24,11 @@ public class OfficeFilePreviewImpl implements FilePreview {
 
     private final FileHandlerService fileHandlerService;
     private final PdfUtils pdfUtils;
-    private final DownloadUtils downloadUtils;
     private final OfficeToPdfService officeToPdfService;
 
-    public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils, DownloadUtils downloadUtils, OfficeToPdfService officeToPdfService) {
+    public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils, OfficeToPdfService officeToPdfService) {
         this.fileHandlerService = fileHandlerService;
         this.pdfUtils = pdfUtils;
-        this.downloadUtils = downloadUtils;
         this.officeToPdfService = officeToPdfService;
     }
 
@@ -51,7 +49,7 @@ public class OfficeFilePreviewImpl implements FilePreview {
         // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
         if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
             String filePath;
-            ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, null);
+            ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
             if (0 != response.getCode()) {
                 model.addAttribute("fileType", suffix);
                 model.addAttribute("msg", response.getMsg());

+ 3 - 10
server/src/main/java/cn/keking/service/impl/PdfFilePreviewImpl.java

@@ -21,19 +21,12 @@ import java.util.List;
 public class PdfFilePreviewImpl implements FilePreview {
 
     private final FileHandlerService fileHandlerService;
-
     private final PdfUtils pdfUtils;
-
-    private final DownloadUtils downloadUtils;
-
     private static final String FILE_DIR = ConfigConstants.getFileDir();
 
-    public PdfFilePreviewImpl(FileHandlerService fileHandlerService,
-                              PdfUtils pdfUtils,
-                              DownloadUtils downloadUtils) {
+    public PdfFilePreviewImpl(FileHandlerService fileHandlerService, PdfUtils pdfUtils) {
         this.fileHandlerService = fileHandlerService;
         this.pdfUtils = pdfUtils;
-        this.downloadUtils = downloadUtils;
     }
 
     @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 (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
-                ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
+                ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
                 if (0 != response.getCode()) {
                     model.addAttribute("fileType", suffix);
                     model.addAttribute("msg", response.getMsg());
@@ -76,7 +69,7 @@ public class PdfFilePreviewImpl implements FilePreview {
             // 不是http开头,浏览器不能直接访问,需下载到本地
             if (url != null && !url.toLowerCase().startsWith("http")) {
                 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()) {
                         model.addAttribute("fileType", suffix);
                         model.addAttribute("msg", response.getMsg());

+ 2 - 6
server/src/main/java/cn/keking/service/impl/PictureFilePreviewImpl.java

@@ -20,12 +20,8 @@ public class PictureFilePreviewImpl implements FilePreview {
 
     private final FileHandlerService fileHandlerService;
 
-    private final DownloadUtils downloadUtils;
-
-    public PictureFilePreviewImpl(FileHandlerService fileHandlerService,
-                                  DownloadUtils downloadUtils) {
+    public PictureFilePreviewImpl(FileHandlerService fileHandlerService) {
         this.fileHandlerService = fileHandlerService;
-        this.downloadUtils = downloadUtils;
     }
 
     @Override
@@ -39,7 +35,7 @@ public class PictureFilePreviewImpl implements FilePreview {
         }
         // 不是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()) {
                 model.addAttribute("fileType", fileAttribute.getSuffix());
                 model.addAttribute("msg", response.getMsg());

+ 1 - 7
server/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java

@@ -23,16 +23,10 @@ public class SimTextFilePreviewImpl implements FilePreview {
     public static final String TEXT_TYPE = "textType";
     public static final String DEFAULT_TEXT_TYPE = "simText";
 
-    private final DownloadUtils downloadUtils;
-
-    public SimTextFilePreviewImpl(DownloadUtils downloadUtils) {
-        this.downloadUtils = downloadUtils;
-    }
-
     @Override
     public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
         String fileName = fileAttribute.getName();
-        ReturnResponse<String> response = downloadUtils.downLoad(fileAttribute, fileName);
+        ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
         if (0 != response.getCode()) {
             model.addAttribute("msg", response.getMsg());
             model.addAttribute("fileType", fileAttribute.getSuffix());

+ 12 - 22
server/src/main/java/cn/keking/utils/DownloadUtils.java

@@ -1,14 +1,11 @@
 package cn.keking.utils;
 
 import cn.keking.config.ConfigConstants;
-import cn.keking.hutool.URLUtil;
 import cn.keking.model.FileAttribute;
 import cn.keking.model.FileType;
 import cn.keking.model.ReturnResponse;
-import cn.keking.service.FileHandlerService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
 
 import java.io.*;
 import java.net.*;
@@ -18,27 +15,20 @@ import java.util.UUID;
 /**
  * @author yudian-it
  */
-@Component
 public class DownloadUtils {
 
     private final static Logger logger = LoggerFactory.getLogger(DownloadUtils.class);
-    private final String fileDir = ConfigConstants.getFileDir();
+    private static final String fileDir = ConfigConstants.getFileDir();
     private static final String URL_PARAM_FTP_USERNAME = "ftp.username";
     private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
     private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
 
-    private final FileHandlerService fileHandlerService;
-
-    public DownloadUtils(FileHandlerService fileHandlerService) {
-        this.fileHandlerService = fileHandlerService;
-    }
-
     /**
      * @param fileAttribute fileAttribute
      * @param fileName      文件名
      * @return 本地文件绝对路径
      */
-    public ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
+    public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
         String urlStr = fileAttribute.getUrl();
         String type = fileAttribute.getSuffix();
         ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
@@ -60,9 +50,9 @@ public class DownloadUtils {
                 OutputStream os = new FileOutputStream(realPath);
                 saveBytesToOutStream(bytes, os);
             } else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
-                String ftpUsername = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
-                String ftpPassword = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
-                String ftpControlEncoding = fileHandlerService.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
+                String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
+                String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
+                String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
                 FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
             } else {
                 response.setCode(1);
@@ -72,7 +62,7 @@ public class DownloadUtils {
             response.setContent(realPath);
             response.setMsg(fileName);
             if (FileType.simText.equals(fileAttribute.getType())) {
-                this.convertTextPlainFileCharsetToUtf8(realPath);
+                convertTextPlainFileCharsetToUtf8(realPath);
             }
             return response;
         } catch (IOException e) {
@@ -88,10 +78,10 @@ public class DownloadUtils {
         }
     }
 
-    public byte[] getBytesFromUrl(String urlStr) throws IOException {
+    public static byte[] getBytesFromUrl(String urlStr) throws IOException {
         InputStream is = getInputStreamFromUrl(urlStr);
         if (is == null) {
-            urlStr = URLUtil.normalize(urlStr, true, true);
+         //   urlStr = URLUtil.normalize(urlStr, true, true);
             is = getInputStreamFromUrl(urlStr);
             if (is == null) {
                 logger.error("文件下载异常:url:{}", urlStr);
@@ -101,12 +91,12 @@ public class DownloadUtils {
         return getBytesFromStream(is);
     }
 
-    public void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
+    public static void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
         os.write(b);
         os.close();
     }
 
-    private InputStream getInputStreamFromUrl(String urlStr) {
+    private static InputStream getInputStreamFromUrl(String urlStr) {
         try {
             URL url = new URL(urlStr);
             URLConnection connection = url.openConnection();
@@ -120,7 +110,7 @@ public class DownloadUtils {
         }
     }
 
-    private byte[] getBytesFromStream(InputStream is) throws IOException {
+    private static byte[] getBytesFromStream(InputStream is) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         byte[] buffer = new byte[1024];
         int len;
@@ -139,7 +129,7 @@ public class DownloadUtils {
      *
      * @param filePath 文件路径
      */
-    private void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
+    private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
         File sourceFile = new File(filePath);
         if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
             String encoding = FileUtils.getFileEncode(filePath);

+ 60 - 0
server/src/main/java/cn/keking/utils/WebUtils.java

@@ -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;
+    }
+}

+ 5 - 5
server/src/main/java/cn/keking/web/controller/FileController.java

@@ -52,8 +52,8 @@ public class FileController {
             return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "存在同名文件,请先删除原有文件再次上传", null));
         }
         File outFile = new File(fileDir + demoPath);
-        if (!outFile.exists()) {
-            outFile.mkdirs();
+        if (!outFile.exists() && !outFile.mkdirs()) {
+            logger.error("创建文件夹【{}】失败,请检查目录权限!",fileDir + demoPath);
         }
         logger.info("上传文件:{}", fileDir + demoPath + fileName);
         try(InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileDir + demoPath + fileName)) {
@@ -72,8 +72,8 @@ public class FileController {
         }
         File file = new File(fileDir + demoPath + fileName);
         logger.info("删除文件:{}", file.getAbsolutePath());
-        if (file.exists()) {
-            file.delete();
+        if (file.exists() && !file.delete()) {
+           logger.error("删除文件【{}】失败,请检查目录权限!",file.getPath());
         }
         return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
     }
@@ -84,7 +84,7 @@ public class FileController {
         File file = new File(fileDir + demoPath);
         if (file.exists()) {
             Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(file1 -> {
-                Map<String, String> fileName = new HashMap();
+                Map<String, String> fileName = new HashMap<>();
                 fileName.put("fileName", demoDir + "/" + file1.getName());
                 list.add(fileName);
             });

+ 9 - 9
server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java

@@ -7,10 +7,12 @@ import cn.keking.service.FilePreviewFactory;
 import cn.keking.service.cache.CacheService;
 import cn.keking.utils.DownloadUtils;
 import cn.keking.service.FileHandlerService;
+import com.thoughtworks.xstream.core.util.Base64JavaUtilCodec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
+import org.springframework.util.Base64Utils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -33,22 +35,20 @@ public class OnlinePreviewController {
     private final FilePreviewFactory previewFactory;
     private final CacheService cacheService;
     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.fileHandlerService = fileHandlerService;
         this.cacheService = cacheService;
-        this.downloadUtils = downloadUtils;
     }
 
-
     @RequestMapping(value = "/onlinePreview")
     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);
-        logger.info("预览文件url:{},previewType:{}", url, fileAttribute.getType());
-        return filePreview.filePreviewHandle(url, model, fileAttribute);
+        logger.info("预览文件url:{},previewType:{}", fileUrl, fileAttribute.getType());
+        return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
     }
 
     @RequestMapping(value = "/picturesPreview")
@@ -78,8 +78,8 @@ public class OnlinePreviewController {
     public void getCorsFile(String urlPath, HttpServletResponse response) {
         logger.info("下载跨域pdf文件url:{}", urlPath);
         try {
-            byte[] bytes = downloadUtils.getBytesFromUrl(urlPath);
-            downloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
+            byte[] bytes = DownloadUtils.getBytesFromUrl(urlPath);
+            DownloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
         } catch (IOException e) {
             logger.error("下载跨域pdf文件异常,url:{}", urlPath, e);
         }

+ 1 - 1
server/src/main/java/cn/keking/web/filter/BaseUrlFilter.java

@@ -38,7 +38,7 @@ public class BaseUrlFilter implements Filter {
         pathBuilder.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
                 .append(request.getServerPort()).append(((HttpServletRequest) request).getContextPath()).append("/");
         String baseUrlTmp = ConfigConstants.getBaseUrl();
-        if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equals(baseUrlTmp.toLowerCase())) {
+        if (baseUrlTmp != null && !ConfigConstants.DEFAULT_BASE_URL.equalsIgnoreCase(baseUrlTmp)) {
             if (!baseUrlTmp.endsWith("/")) {
                 baseUrlTmp = baseUrlTmp.concat("/");
             }

+ 5 - 2
server/src/main/resources/web/compress.ftl

@@ -38,8 +38,11 @@
 <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.ztree.core.js"></script>
+<script type="text/javascript" src="js/base64.min.js" ></script>
+
 <script type="text/javascript">
     var data = JSON.parse('${fileTree}');
+    var baseUrl = "${baseUrl}";
     var setting = {
         view: {
             fontCss : {"color":"blue"},
@@ -71,8 +74,8 @@
                     } else {
                         fulls += ",resizable"; // 对于不支持screen属性的浏览器,可以手工进行最大化。 manually
                     }
-                    window.open("onlinePreview?url="
-                            + encodeURIComponent("${baseUrl}" + treeNode.fileName)+"&fileKey="+ encodeURIComponent(treeNode.fileKey), "_blank",fulls);
+                    var previewUrl = baseUrl + treeNode.fileName +"&fileKey="+ treeNode.fileKey;
+                    window.open("onlinePreview?url=" + encodeURIComponent(Base64.encode(previewUrl)), "_blank",fulls);
                 }
             }
         }

+ 4 - 3
server/src/main/resources/web/index.ftl

@@ -15,6 +15,7 @@
     <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="gitalk/gitalk.min.js"></script>
+    <script type="text/javascript" src="js/base64.min.js" ></script>
 </head>
 
 <body>
@@ -36,14 +37,14 @@
                     成功实现:
                     <pre style="background-color: #2f332a;color: #cccccc">
 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>
                 </div>
                 <div>
                     新增多图片同时预览功能,接口如下:
                     <pre style="background-color: #2f332a;color: #cccccc">
 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>
                 </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) {
             // 每个data添加一列用来操作
             $(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>";
             });
             return data;