Analyser une chaîne D'URI dans la Collection nom-valeur

J'ai L'URI comme ceci:

Https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback

J'ai besoin d'une collection avec des éléments analysés:

NAME               VALUE
------------------------
client_id          SS
response_type      code
scope              N_FULL
access_type        offline
redirect_uri       http://localhost/Callback

Pour être exact, j'ai besoin D'un équivalent Java pour C # HttpUtility.Méthode ParseQueryString. S'il vous plaît, me donner un conseil sur ce. Grâce.

192
demandé sur Nathan 2012-11-28 00:11:58

13 réponses

Si vous cherchez un moyen d'y parvenir sans utiliser une bibliothèque externe, le code suivant vous aidera.

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

Vous pouvez accéder à la carte retournée en utilisant <map>.get("client_id"), avec l'URL donnée dans votre question, cela retournerait "SS".

Mise à jour URL-décodage ajouté

UPDATE Comme cette réponse est toujours très populaire, j'ai fait une version améliorée de la méthode ci-dessus, qui gère plusieurs paramètres avec la même clé et les paramètres sans valeur comme Bien.

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

Mise à jour Version 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);
}

Exécuter la méthode ci-dessus avec L'URL

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

Renvoie cette carte:

{param1=["value1"], param2=[null], param3=["value3", null]}
270
répondu Pr0gr4mm3r 2017-06-16 08:38:55

Org.Apache.http.client.utils.URLEncodedUtils

Est une bibliothèque bien connue qui peut le faire pour vous

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), Charset.forName("UTF-8"));

for (NameValuePair param : params) {
  System.out.println(param.getName() + " : " + param.getValue());
}

Sorties

one : 1
two : 2
three : 3
three : 3a
240
répondu Juan Mendes 2018-05-31 14:23:58

Si vous utilisez 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));
}

, Vous obtiendrez:

param1: abc
param2: def,ghi
58
répondu xxg 2017-08-19 07:45:47

Utilisez google goyave et faites-le en 2 lignes:

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

Ce qui vous donne

{client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback}
39
répondu Amin Abbaspour 2014-08-15 05:04:33

Le chemin Le plus court que j'ai trouvé est celui-ci:

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

Mise À JOUR: UriComponentsBuilder ça vient du printemps. Ici le lien.

13
répondu Dmitry Senkovich 2017-11-06 12:09:48

Si vous utilisez Java 8 et que vous êtes prêt à écrire quelques méthodes réutilisables, vous pouvez le faire en une seule ligne.

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

Mais c'est une ligne assez brutale.

8
répondu Fuwjax 2015-05-15 22:19:08

Pour Android, si vous utilisez OkHttp dans votre projet. Vous pourriez obtenir un coup d'oeil à ce. Il est simple et utile.

final HttpUrl url = HttpUrl.parse(query);
if (url != null) {
    final String target = url.queryParameter("target");
    final String id = url.queryParameter("id");
}
6
répondu THANN Phearum 2018-02-03 06:01:28

Java 8 une instruction

Compte tenu de L'URL à analyser:

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

Cette solution collecte une liste de paires:

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

Cette solution d'autre part recueille une carte (étant donné que dans une url il peut y avoir plus de paramètres avec le même nom mais des valeurs différentes).

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

Les deux solutions doivent utiliser une fonction utilitaire pour décoder correctement les paramètres.

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);
    }
}
5
répondu freedev 2018-05-07 16:38:57

Si vous utilisez servlet doGet essayez ceci

request.getParameterMap()

retourne un java.util.La carte des paramètres de cette demande.

retours: un java immuable.util.Carte contenant des noms de paramètres en tant que clés et des valeurs de paramètres en tant que valeurs de carte. Les clés de la carte des paramètres sont de type String. Les valeurs de la carte des paramètres sont de type String array.

(Java doc)

4
répondu Ansar Ozden 2018-05-31 14:10:49

En utilisant les commentaires et les solutions mentionnés ci-dessus, je stocke tous les paramètres de requête en utilisant Map où les objets peuvent être string ou Set. La solution est donnée ci-dessous. Il est recommandé d'utiliser une sorte de validateur d'url pour valider l'url d'abord, puis appeler la méthode 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;
    }
}
2
répondu SUMIT 2016-06-02 19:10:06

Juste une mise à jour de la version Java 8

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())));
}
Les méthodes

Mapping et toList() doivent être utilisées avec des collecteurs qui n'ont pas été mentionnés dans la réponse supérieure. Sinon, il lancerait une erreur de compilation dans IDE

1
répondu Aarish Ramesh 2018-06-07 18:04:20

Si vous utilisez Spring, ajoutez un argument de type @RequestParam Map<String,String> à votre méthode de contrôleur, et Spring construira la carte pour vous!

0
répondu mancini0 2018-01-19 03:13:36

J'ai essayé une version Kotlin en voyant comment c'est le meilleur résultat dans Google.

@Throws(UnsupportedEncodingException::class)
fun splitQuery(url: URL): Map<String, List<String>> {

    val queryPairs = LinkedHashMap<String, ArrayList<String>>()

    url.query.split("&".toRegex())
            .dropLastWhile { it.isEmpty() }
            .map { it.split('=') }
            .map { it.getOrEmpty(0).decodeToUTF8() to it.getOrEmpty(1).decodeToUTF8() }
            .forEach { (key, value) ->

                if (!queryPairs.containsKey(key)) {
                    queryPairs[key] = arrayListOf(value)
                } else {

                    if(!queryPairs[key]!!.contains(value)) {
                        queryPairs[key]!!.add(value)
                    }
                }
            }

    return queryPairs
}

Et les méthodes d'extension

fun List<String>.getOrEmpty(index: Int) : String {
    return getOrElse(index) {""}
}

fun String.decodeToUTF8(): String { 
    URLDecoder.decode(this, "UTF-8")
}
0
répondu Graham Smith 2018-06-25 13:23:19