|
@@ -0,0 +1,107 @@
|
|
|
+package org.springblade.common.utils;
|
|
|
+
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+
|
|
|
+public class SafeURLEncoder {
|
|
|
+
|
|
|
+
|
|
|
+ public static String encodeFullUrl(String fullUrl) {
|
|
|
+ if (fullUrl == null || fullUrl.isEmpty()) {
|
|
|
+ return fullUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找最后一个斜杠位置
|
|
|
+ int lastSlashIndex = fullUrl.lastIndexOf('/');
|
|
|
+
|
|
|
+ // 如果没有斜杠,直接返回原URL
|
|
|
+ if (lastSlashIndex == -1) {
|
|
|
+ return fullUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分割URL为基本部分和文件名
|
|
|
+ String baseUrl = fullUrl.substring(0, lastSlashIndex + 1);
|
|
|
+ String fileName = fullUrl.substring(lastSlashIndex + 1);
|
|
|
+
|
|
|
+ // 只对文件名进行安全编码
|
|
|
+ String safeFileName = encodeURLComponent(fileName);
|
|
|
+
|
|
|
+ // 重新组合URL
|
|
|
+ return baseUrl + safeFileName;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static String encodeURLComponent(String input) {
|
|
|
+ if (input == null || input.isEmpty()) {
|
|
|
+ return input;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否只包含安全字符
|
|
|
+ if (isSafeString(input)) {
|
|
|
+ return input;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 需要编码的特殊处理
|
|
|
+ return encodeSpecial(input);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static boolean isSafeString(String input) {
|
|
|
+ for (int i = 0; i < input.length(); i++) {
|
|
|
+ char c = input.charAt(i);
|
|
|
+ if (!isSafeCharacter(c)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static boolean isSafeCharacter(char c) {
|
|
|
+ return (c >= 'a' && c <= 'z') ||
|
|
|
+ (c >= 'A' && c <= 'Z') ||
|
|
|
+ (c >= '0' && c <= '9') ||
|
|
|
+ c == '-' || c == '_' || c == '.' ||
|
|
|
+ c == '~' || c == '*';
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static String encodeSpecial(String input) {
|
|
|
+ try {
|
|
|
+ // 首先处理百分号(防止双重编码)
|
|
|
+ String percentFixed = input.replace("%", "%25");
|
|
|
+
|
|
|
+ // 执行URL编码
|
|
|
+ String encoded = URLEncoder.encode(percentFixed, StandardCharsets.UTF_8.name());
|
|
|
+
|
|
|
+ // 处理空格和修复双重编码问题
|
|
|
+ return encoded.replace("+", "%20")
|
|
|
+ .replace("%2525", "%25");
|
|
|
+ } catch (Exception e) {
|
|
|
+ return input; // 出错时返回原始输入
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试用例
|
|
|
+ public static void main(String[] args) {
|
|
|
+ // 需要编码的复杂URL
|
|
|
+ String complexUrl = "https://xinan1.zos.ctyun.cn/huazheng2021/folderFile/8035ed7caee244a09c93fb731fd2/27e5af52344e4f0baf4b0e5d53eb1406/54.G7522天峨至北海公路(平塘至天峨广西段)№1合同段碎石垫层、4%水泥稳定碎石底基层、5%水泥稳定碎石基层.pdf";
|
|
|
+ System.out.println("编码后的URL: " + encodeFullUrl(complexUrl));
|
|
|
+
|
|
|
+ // 不需要编码的简单URL
|
|
|
+ String safeUrl = "https://example.com/reports/annual_report_2025.pdf";
|
|
|
+ System.out.println("安全URL: " + encodeFullUrl(safeUrl));
|
|
|
+
|
|
|
+ // 带有空格的URL
|
|
|
+ String withSpace = "https://example.com/reports/Q1 financial report.docx";
|
|
|
+ System.out.println("带空格URL: " + encodeFullUrl(withSpace));
|
|
|
+
|
|
|
+ // 只有基础URL没有文件名
|
|
|
+ String baseOnly = "https://example.com/downloads/";
|
|
|
+ System.out.println("只有基础URL: " + encodeFullUrl(baseOnly));
|
|
|
+
|
|
|
+ // 没有斜杠的URL
|
|
|
+ String noSlash = "downloads/annual-report.pdf";
|
|
|
+ System.out.println("没有斜杠: " + encodeFullUrl(noSlash));
|
|
|
+ }
|
|
|
+}
|