372 Stimmen

Parsen einer URI-Zeichenkette in eine Name-Werte-Sammlung

Ich habe die URI so eingestellt:

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

Ich brauche eine Sammlung mit geparsten Elementen:

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

Um genau zu sein, brauche ich ein Java-Äquivalent für die C#/.NET HttpUtility.ParseQueryString Methode.

2voto

SUMIT Punkte 480

Mit oben genannten Kommentare und Lösungen, ich speichere alle Abfrageparameter mit Map<String, Object> wo Objekte entweder Zeichenfolge oder Set<String> sein kann. Die Lösung ist unten angegeben. Es wird empfohlen, eine Art Url-Validator zu verwenden, um die Url zuerst zu validieren und dann die Methode convertQueryStringToMap aufzurufen.

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

2voto

DuncG Punkte 8029

Es gibt viele Antworten, die für Ihre Abfrage funktionieren, wie Sie angegeben haben, wenn sie einzelne Parameterdefinitionen hat. In einigen Anwendungen kann es nützlich sein, ein paar zusätzliche Abfrageparameter zu behandeln, wie z. B.:

  • Liste von Parameterwerten wie param1&param1=value&param1= Bedeutung param1 wird eingestellt auf List.of("", "value", "")
  • ungültige Permutationen wie querypath?&=&&=noparamname& .
  • leere Zeichenkette nicht null in Maps verwenden a= bedeutet "a" ist List.of("") zur Anpassung der Webservlet-Behandlung

Dies verwendet einen Stream mit Filtern und groupingBy zum Sammeln von 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())));
}

1voto

Elye Punkte 40819

Kotlins Antwort mit anfänglicher Referenz von https://stackoverflow.com/a/51024552/3286489 aber mit verbesserter Version durch Aufräumen von Codes und bietet 2 Versionen davon, und verwenden unveränderliche Sammlung Operationen

Verwenden Sie java.net.URI um die Abfrage zu extrahieren. Verwenden Sie dann die unten angegebenen Erweiterungsfunktionen

  1. Angenommen, Sie wollen nur den letzten Wert der Abfrage, d. h. page2&page3 erhalten {page=3} verwenden Sie die folgende Erweiterungsfunktion

    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"
  2. Angenommen, Sie wollen eine Liste aller Werte für die Abfrage, d. h. page2&page3 erhalten {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"

So verwenden Sie es wie folgt

    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}

1voto

Udayaditya Barua Punkte 1113

Eine Kotlin-Version

der Antwort Antwort von matthias bereitgestellt

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

Dies gilt auch für den ersten Parameter nach dem Fragezeichen '?'.

0voto

dschulten Punkte 2862

Wenn Sie zufällig cxf-core auf dem Klassenpfad haben und wissen, dass Sie keine wiederholten Abfrageparameter haben, können Sie verwenden UrlUtils.parseQueryString .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X