将URI字符串解析为名称 – 值集合

我有这样的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#HttpUtility.ParseQueryString方法的Java等价物。 请给我一个这方面的建议。 谢谢。

    如果您正在寻找一种方法来实现它,而不使用外部库,下面的代码将帮助你。

     public static Map<String, String> splitQuery(URL url) throws UnsupportedEncodingException { Map<String, String> query_pairs = new LinkedHashMap<String, String>(); String query = url.getQuery(); String[] pairs = query.split("&"); for (String pair : pairs) { int idx = pair.indexOf("="); query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); } return query_pairs; } 

    你可以使用<map>.get("client_id")来访问返回的Map,在你的问题中给出的URL将返回“SS”。

    更新网址解码添加

    更新由于这个答案仍然相当流行,我做了上述方法的改进版本,它使用相同的键和参数处理多个参数,也没有值。

     public static Map<String, List<String>> splitQuery(URL url) throws UnsupportedEncodingException { final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>(); final String[] pairs = url.getQuery().split("&"); for (String pair : pairs) { final int idx = pair.indexOf("="); final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; if (!query_pairs.containsKey(key)) { query_pairs.put(key, new LinkedList<String>()); } final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; query_pairs.get(key).add(value); } return query_pairs; } 

    更新 Java8版本

     public Map<String, List<String>> splitQuery(URL url) { if (Strings.isNullOrEmpty(url.getQuery())) { return Collections.emptyMap(); } return Arrays.stream(url.getQuery().split("&")) .map(this::splitQueryParameter) .collect(Collectors.groupingBy(SimpleImmutableEntry::getKey, LinkedHashMap::new, mapping(Map.Entry::getValue, toList()))); } public SimpleImmutableEntry<String, String> splitQueryParameter(String it) { final int idx = it.indexOf("="); final String key = idx > 0 ? it.substring(0, idx) : it; final String value = idx > 0 && it.length() > idx + 1 ? it.substring(idx + 1) : null; return new SimpleImmutableEntry<>(key, value); } 

    用URL运行上面的方法

    https://stackoverflow.com?param1=value1&param2=&param3=value3&param3

    返回这个地图:

     {param1=["value1"], param2=[null], param3=["value3", null]} 

    http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URLEncodedUtils.html是一个众所周知的库,可以为你&#x505A;

     import org.apache.hc.client5.http.utils.URLEncodedUtils String url = "http://www.example.com/something.html?one=1&two=2&three=3&three=3a"; List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), "UTF-8"); for (NameValuePair param : params) { System.out.println(param.getName() + " : " + param.getValue()); } 

    输出

    一:1

    二:2

    三:三

    三:3a

    使用谷歌番石榴,并在2行:

     import java.util.Map; import com.google.common.base.Splitter; public class Parser { public static void main(String... args) { String uri = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback"; String query = uri.split("\\?")[1]; final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(query); System.out.println(map); } } 

    这给你

     {client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback} 

    如果您使用的是Spring Framework:

     public static void main(String[] args) { String uri = "http://youhost.com/test?param1=abc&param2=def&param2=ghi"; MultiValueMap<String, String> parameters = UriComponentsBuilder.fromUriString(uri).build().getQueryParams(); List<String> param1 = parameters.get("param1"); List<String> param2 = parameters.get("param2"); System.out.println("param1: " + param1.get(0)); System.out.println("param2: " + param2.get(0) + "," + param2.get(1)); } 

    你会得到:

     param1: abc param2: def,ghi 

    如果您使用的是Java 8,并且您愿意编写一些可重用的方法,则可以在一行中完成。

     private Map<String, List<String>> parse(final String query) { return Arrays.asList(query.split("&")).stream().map(p -> p.split("=")).collect(Collectors.toMap(s -> decode(index(s, 0)), s -> Arrays.asList(decode(index(s, 1))), this::mergeLists)); } private <T> List<T> mergeLists(final List<T> l1, final List<T> l2) { List<T> list = new ArrayList<>(); list.addAll(l1); list.addAll(l2); return list; } private static <T> T index(final T[] array, final int index) { return index >= array.length ? null : array[index]; } private static String decode(final String encoded) { try { return encoded == null ? null : URLDecoder.decode(encoded, "UTF-8"); } catch(final UnsupportedEncodingException e) { throw new RuntimeException("Impossible: UTF-8 is a required encoding", e); } } 

    但这是一个非常残酷的路线。

    Java 8 oneliner

    给定要分析的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<AbstractMap.SimpleEntry<String, String>> list = Pattern.compile("&").splitAsStream(url.getQuery()) .map(s -> Arrays.copyOf(s.split("="), 2)) .map(o -> new AbstractMap.SimpleEntry<String, String>(decode(o[0]), decode(o[1]))) .collect(toList()); 

    另一方面,这个解决方案收集一个地图(假设在一个url中可以有更多的参数,但名称相同但值不同)。

     Map<String, List<String>> list = Pattern.compile("&").splitAsStream(url.getQuery()) .map(s -> Arrays.copyOf(s.split("="), 2)) .collect(groupingBy(s -> decode(s[0]), mapping(s -> decode(s[1]), toList()))); 

    这两个解决方案都必须使用效用函数来正确解码参数。

     private static String decode(final String encoded) { try { return encoded == null ? null : URLDecoder.decode(encoded, "UTF-8"); } catch(final UnsupportedEncodingException e) { throw new RuntimeException("Impossible: UTF-8 is a required encoding", e); } } 

    使用上面提到的注释和解决方案,我将使用Map <String,Object>存储所有查询参数,其中对象可以是字符串,也可以是Set <String>。 解决方案如下。 建议使用某种URL验证器来首先验证url,然后调用convertQueryStringToMap方法。

     private static final String DEFAULT_ENCODING_SCHEME = "UTF-8"; public static Map<String, Object> convertQueryStringToMap(String url) throws UnsupportedEncodingException, URISyntaxException { List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), DEFAULT_ENCODING_SCHEME); Map<String, Object> queryStringMap = new HashMap<>(); for(NameValuePair param : params){ queryStringMap.put(param.getName(), handleMultiValuedQueryParam(queryStringMap, param.getName(), param.getValue())); } return queryStringMap; } private static Object handleMultiValuedQueryParam(Map responseMap, String key, String value) { if (!responseMap.containsKey(key)) { return value.contains(",") ? new HashSet<String>(Arrays.asList(value.split(","))) : value; } else { Set<String> queryValueSet = responseMap.get(key) instanceof Set ? (Set<String>) responseMap.get(key) : new HashSet<String>(); if (value.contains(",")) { queryValueSet.addAll(Arrays.asList(value.split(","))); } else { queryValueSet.add(value); } return queryValueSet; } } 

    我发现的最短的方法是这样的:

     MultiValueMap<String, String> queryParams = UriComponentsBuilder.fromUriString(url).build().getQueryParams(); 

    更新: UriComponentsBuilder来自春天。 这里的链接 。