Parse a URI String into Name-Value Collection

前端 未结 19 2502
难免孤独
难免孤独 2020-11-22 01:34

I\'ve got the URI like this:

https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_         


        
相关标签:
19条回答
  • 2020-11-22 01:47

    On Android, there is a Uri class in package android.net . Note that Uri is part of android.net, while URI is part of java.net .

    Uri class has many functions to extract key-value pairs from a query.

    Following function returns key-value pairs in the form of HashMap.

    In Java:

    Map<String, String> getQueryKeyValueMap(Uri uri){
        HashMap<String, String> keyValueMap = new HashMap();
        String key;
        String value;
    
        Set<String> keyNamesList = uri.getQueryParameterNames();
        Iterator iterator = keyNamesList.iterator();
    
        while (iterator.hasNext()){
            key = (String) iterator.next();
            value = uri.getQueryParameter(key);
            keyValueMap.put(key, value);
        }
        return keyValueMap;
    }
    

    In Kotlin:

    fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
            val keyValueMap = HashMap<String, String>()
            var key: String
            var value: String
    
            val keyNamesList = uri.queryParameterNames
            val iterator = keyNamesList.iterator()
    
            while (iterator.hasNext()) {
                key = iterator.next() as String
                value = uri.getQueryParameter(key) as String
                keyValueMap.put(key, value)
            }
            return keyValueMap
        }
    
    0 讨论(0)
  • 2020-11-22 01:49

    If you are using Spring, add an argument of type @RequestParam Map<String,String> to your controller method, and Spring will construct the map for you!

    0 讨论(0)
  • 2020-11-22 01:52

    Just an update to the Java 8 version

    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, **Collectors**.mapping(Map.Entry::getValue, **Collectors**.toList())));
    }
    

    mapping and toList() methods have to be used with Collectors which was not mentioned in the top answer. Otherwise it would throw compilation error in IDE

    0 讨论(0)
  • 2020-11-22 01:54

    Netty also provides a nice query string parser called QueryStringDecoder. In one line of code, it can parse the URL in the question. I like because it doesn't require catching or throwing java.net.MalformedURLException.

    In one line:

    Map<String, List<String>> parameters = new QueryStringDecoder(url).parameters();
    

    See javadocs here: https://netty.io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html

    Here is a short, self contained, correct example:

    import io.netty.handler.codec.http.QueryStringDecoder;
    import org.apache.commons.lang3.StringUtils;
    
    import java.util.List;
    import java.util.Map;
    
    public class UrlParse {
    
      public static void main(String... args) {
        String url = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
        QueryStringDecoder decoder = new QueryStringDecoder(url);
        Map<String, List<String>> parameters = decoder.parameters();
        print(parameters);
      }
    
      private static void print(final Map<String, List<String>> parameters) {
        System.out.println("NAME               VALUE");
        System.out.println("------------------------");
        parameters.forEach((key, values) ->
            values.forEach(val ->
                System.out.println(StringUtils.rightPad(key, 19) + val)));
      }
    }
    

    which generates

    NAME               VALUE
    ------------------------
    client_id          SS
    response_type      code
    scope              N_FULL
    access_type        offline
    redirect_uri       http://localhost/Callback
    
    0 讨论(0)
  • 2020-11-22 01:56

    If you're using Java 8 and you're willing to write a few reusable methods, you can do it in one line.

    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);
        }
    }
    

    But that's a pretty brutal line.

    0 讨论(0)
  • 2020-11-22 01:58

    The shortest way I've found is this one:

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

    UPDATE: UriComponentsBuilder comes from Spring. Here the link.

    0 讨论(0)
提交回复
热议问题