從 https://host/path?key1=val1&key2=val2 中提取參數部分並解析為 Map<String, String>,處理無參數、無值、重複 Key、編碼等邊界情況。
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
public class UrlParamParser {
/**
* 解析 URL 參數為 Map
* @param url 完整 URL 或僅查詢字符串
* @return 參數鍵值對,重複 Key 後覆蓋前
*/
public static Map parse(String url) {
Map params = new HashMap<>();
if (url == null || url.isEmpty()) return params;
String query = extractQuery(url);
if (query == null || query.isEmpty()) return params;
String[] pairs = query.split("&");
for (String pair : pairs) {
if (pair.isEmpty()) continue;
String[] kv = pair.split("=", 2); // 限制分割 2 段,值可含 =
String key = decode(kv[0]);
String value = kv.length > 1 ? decode(kv[1]) : "";
params.put(key, value);
}
return params;
}
/** 截取 ? 後的查詢字符串 */
private static String extractQuery(String url) {
int idx = url.indexOf('?');
return idx >= 0 ? url.substring(idx + 1) : url; // 無 ? 視為純查詢串
}
/** UTF-8 解碼,失敗返回原值 */
private static String decode(String s) {
try {
return URLDecoder.decode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
return s; // 不會發生
}
}
// 測試
public static void main(String[] args) {
String url = "https://api.example.com/search?q=java+8&lang=zh_CN&tag=java&tag=stream";
Map map = parse(url);
map.forEach((k, v) -> System.out.println(k + " = " + v));
/* 輸出:
q = java 8
lang = zh_CN
tag = stream (重複 Key 後覆蓋)
*/
}
}
import java.net.URLDecoder;
import java.util.*;
public class MultiValueUrlParser {
public static Map> parseMulti(String url) {
Map> params = new LinkedHashMap<>(); // 保留順序
if (url == null) return params;
String query = extractQuery(url);
if (query == null) return params;
for (String pair : query.split("&")) {
if (pair.isEmpty()) continue;
String[] kv = pair.split("=", 2);
String key = decodeSafe(kv[0]);
String value = kv.length > 1 ? decodeSafe(kv[1]) : "";
params.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}
return params;
}
private static String decodeSafe(String s) {
try {
return URLDecoder.decode(s, "UTF-8");
} catch (Exception e) {
return s; // 記錄日志可選
}
}
// extractQuery 同前
}
| 場景 | 問題 | 對策 |
|---|---|---|
| URL 編碼不一致 | GBK 編碼參數 UTF-8 解碼亂碼 | 嘗試 UTF-8 失敗回退 GBK,或強制指定編碼 |
| 參數值包含 & 或 = | 簡單 split 截斷 | 前端 encodeURIComponent 編碼,後端按標準解析 |
| 重複參數名 | Map 覆蓋丟失 | 用 Map<String, List<String>> 或 MultiValueMap |
空值參數 key= | 解析為空字符串 | 業務層判斷 isEmpty() |
| 大數據量 URL | 字符串分割性能 | 手寫狀態機解析或用 UriComponentsBuilder (Spring) |
@RequestParam Map<String, String> params 自動綁定。Apache HttpClient UrlEncodedUtils.parse() 或 Spring Web UriComponentsBuilder,避免重複造輪子。