我得到了这样的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方法。
一个kotlin版本
由马提亚提供的答案
fun decomposeQueryString(query: String, charset: Charset): Map<String, String?> {
return if (query.split("?").size <= 1)
emptyMap()
else {
query.split("?")[1]
.split("&")
.map { it.split(Pattern.compile("="), 2) }
.associate {
Pair(
URLDecoder.decode(it[0], charset.name()),
if (it.size > 1) URLDecoder.decode(it[1], charset.name()) else null
)
}
}
}
这需要问号'?’。
纯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);
}
当查询只有单个参数定义时,有很多答案可以用于您的查询。在一些应用程序中,处理一些额外的查询参数边缘情况可能是有用的,例如:
如param1¶m1=value¶m1=等参数值的列表,意味着param1被设置为list。Of ("", "value", "")
无效的排列,例如querypath?&=&&=noparamname&。
在maps中使用非空字符串a=意味着“a”是List.of(“”)来匹配web servlet处理
它使用一个带有过滤器和groupingBy的流来收集到Map<String, List<String>>:
public static Map<String, List<String>> getParameterValues(URL url) {
return Arrays.stream(url.getQuery().split("&"))
.map(s -> s.split("="))
// filter out empty parameter names (as in Tomcat) "?&=&&=value&":
.filter(arr -> arr.length > 0 && arr[0].length() > 0)
.collect(Collectors.groupingBy(arr -> URLDecoder.decode(arr[0], StandardCharsets.UTF_8),
// drop this line for not-name definition order Map:
LinkedHashMap::new,
Collectors.mapping(arr -> arr.length < 2 ? "" : URLDecoder.decode(arr[1], StandardCharsets.UTF_8), Collectors.toList())));
}
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}