我得到了这样的URI:
https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback
我需要一个包含已解析元素的集合:
NAME VALUE
------------------------
client_id SS
response_type code
scope N_FULL
access_type offline
redirect_uri http://localhost/Callback
确切地说,我需要一个与c# /等价的Java。净HttpUtility。ParseQueryString方法。
另外,我建议使用基于正则表达式的URLParser实现
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class URLParser {
private final String query;
public URLParser(String query) {
this.query = query;
}
public String get(String name) {
String regex = "(?:^|\\?|&)" + name + "=(.*?)(?:&|$)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(this.query);
if (matcher.find()) {
return matcher.group(1);
}
return "";
}
}
这个类很容易使用。它只需要初始化时的URL或查询字符串,并根据给定的键解析值。
class Main {
public static void main(String[] args) {
URLParser parser = new URLParser("https://www.google.com/search?q=java+parse+url+params&oq=java+parse+url+params&aqs=chrome..69i57j0i10.18908j0j7&sourceid=chrome&ie=UTF-8");
System.out.println(parser.get("q")); // java+parse+url+params
System.out.println(parser.get("sourceid")); // chrome
System.out.println(parser.get("ie")); // UTF-8
}
}
如果只是想从字符串URL后的参数。然后下面的代码将工作。我只是假设简单的Url。我的意思是没有严格和快速的检查和解码。就像在我的一个测试案例中,我得到了Url,我知道我只需要参数的值。url很简单。不需要编码解码。
String location = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
String location1 = "https://stackoverflow.com?param1=value1¶m2=value2¶m3=value3";
String location2 = "https://stackoverflow.com?param1=value1¶m2=¶m3=value3¶m3";
Map<String, String> paramsMap = Stream.of(location)
.filter(l -> l.indexOf("?") != -1)
.map(l -> l.substring(l.indexOf("?") + 1, l.length()))
.flatMap(q -> Pattern.compile("&").splitAsStream(q))
.map(s -> s.split("="))
.filter(a -> a.length == 2)
.collect(Collectors.toMap(
a -> a[0],
a -> a[1],
(existing, replacement) -> existing + ", " + replacement,
LinkedHashMap::new
));
System.out.println(paramsMap);
谢谢
纯Java 11
给定要分析的URL:
URL url = new URL("https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback");
这个解决方案收集了一个对列表:
List<Map.Entry<String, String>> list = Pattern.compile("&")
.splitAsStream(url.getQuery())
.map(s -> Arrays.copyOf(s.split("=", 2), 2))
.map(o -> Map.entry(decode(o[0]), decode(o[1])))
.collect(Collectors.toList());
另一方面,这个解决方案收集一个映射(假设在url中可以有更多具有相同名称但不同值的参数)。
Map<String, List<String>> list = Pattern.compile("&")
.splitAsStream(url.getQuery())
.map(s -> Arrays.copyOf(s.split("=", 2), 2))
.collect(groupingBy(s -> decode(s[0]), mapping(s -> decode(s[1]), toList())));
这两种解决方案都必须使用实用函数来正确解码参数。
private static String decode(final String encoded) {
return Optional.ofNullable(encoded)
.map(e -> URLDecoder.decode(e, StandardCharsets.UTF_8))
.orElse(null);
}
Kotlin的答案,最初参考https://stackoverflow.com/a/51024552/3286489,但通过整理代码和提供2个版本的改进版本,并使用不可变的集合操作
使用java.net.URI提取查询。然后使用下面提供的扩展函数
假设你只想要查询的最后一个值,即page2&page3将得到{page=3},使用下面的扩展函数
fun URI.getQueryMap(): Map<String, String> {
if (query == null) return emptyMap()
return query.split("&")
.mapNotNull { element -> element.split("=")
.takeIf { it.size == 2 && it.none { it.isBlank() } } }
.associateBy({ it[0].decodeUTF8() }, { it[1].decodeUTF8() })
}
private fun String.decodeUTF8() = URLDecoder.decode(this, "UTF-8") // decode page=%22ABC%22 to page="ABC"
假设你想要查询所有值的列表,即page2&page3将得到{page=[2,3]}
fun URI.getQueryMapList(): Map<String, List<String>> {
if (query == null) return emptyMap()
return query.split("&")
.distinct()
.mapNotNull { element -> element.split("=")
.takeIf { it.size == 2 && it.none { it.isBlank() } } }
.groupBy({ it[0].decodeUTF8() }, { it[1].decodeUTF8() })
}
private fun String.decodeUTF8() = URLDecoder.decode(this, "UTF-8") // decode page=%22ABC%22 to page="ABC"
使用方法如下
val uri = URI("schema://host/path/?page=&page=2&page=2&page=3")
println(uri.getQueryMapList()) // Result is {page=[2, 3]}
println(uri.getQueryMap()) // Result is {page=3}