Ontleed een URI-tekenreeks in Name-Value Collection

Ik heb de URI als volgt:

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

Ik heb een verzameling nodig met geparseerde elementen:

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

Om precies te zijn, ik heb een Java-equivalent nodig voor de C#/.NET HttpUtility.ParseQueryString-methode.


Antwoord 1, autoriteit 100%

Als u op zoek bent naar een manier om dit te bereiken zonder een externe bibliotheek te gebruiken, zal de volgende code u helpen.

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

Je kunt de geretourneerde kaart openen met <map>.get("client_id"), met de URL die in je vraag is gegeven, zou dit “SS” opleveren.

UPDATEURL-decodering toegevoegd

UPDATEOmdat dit antwoord nog steeds behoorlijk populair is, heb ik een verbeterde versie van de bovenstaande methode gemaakt, die meerdere parameters met dezelfde sleutel en ook parameters zonder waarde verwerkt.

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

UPDATEJava8-versie

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<>(
        URLDecoder.decode(key, "UTF-8"),
        URLDecoder.decode(value, "UTF-8")
    );
}

De bovenstaande methode uitvoeren met de URL

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

retourneert deze kaart:

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

Antwoord 2, autoriteit 90%

org. apache.http.client.utils.URLEncodedUtils

is een bekende bibliotheek die dit voor u kan doen

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

Uitgangen

one : 1
two : 2
three : 3
three : 3a

Antwoord 3, autoriteit 35%

Als je Spring Framework gebruikt:

public static void main(String[] args) {
    String uri = "http://my.test.com/test?param1=ab&param2=cd&param2=ef";
    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));
}

Je krijgt:

param1: ab
param2: cd,ef

Antwoord 4, autoriteit 14%

gebruik google Guava en doe het in 2 regels:

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

waardoor je

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

Antwoord 5, autoriteit 11%

De kortste manier die ik heb gevonden is deze:

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

UPDATE:UriComponentsBuilderkomt uit Spring. Hier de link.


Antwoord 6, autoriteit 6%

Voor Android, als je OkHttpgebruikt in je project. Hier kun je misschien naar kijken. Het is eenvoudig en nuttig.

final HttpUrl url = HttpUrl.parse(query);
if (url != null) {
    final String target = url.queryParameter("target");
    final String id = url.queryParameter("id");
}

Antwoord 7, autoriteit 5%

GEWONE Java 11

Gegeven de te analyseren 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");

Deze oplossing verzamelt een lijst met paren:

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

Deze oplossing daarentegen verzamelt een kaart (aangezien er in een url meer parameters kunnen zijn met dezelfde naam maar met verschillende waarden).

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

Beide oplossingen moeten een hulpprogramma gebruiken om de parameters correct te decoderen.

private static String decode(final String encoded) {
    return Optional.ofNullable(encoded)
                   .map(e -> URLDecoder.decode(e, StandardCharsets.UTF_8))
                   .orElse(null);
}

Antwoord 8, autoriteit 3%

Als je servlet doGet gebruikt, probeer dit dan

request.getParameterMap()

Retourneert een java.util.Map van de parameters van dit verzoek.

Retouren:
een onveranderlijke java.util.Map met parameternamen als sleutels en parameterwaarden als kaartwaarden. De toetsen in de parametermap zijn van het type String. De waarden in de parametermap zijn van het type String array.

(Java-document)


Antwoord 9, autoriteit 3%

Op Android is er een Uri-klasse in pakket android.net. Merk op dat Urideel uitmaakt van android.net, terwijl URIdeel uitmaakt van java.net.

Uri-klasse heeft veel functies om sleutel-waardeparen uit een query te extraheren.

De volgende functie retourneert sleutel-waardeparen in de vorm van 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
    }

Antwoord 10, autoriteit 2%

Als je Java 8 gebruikt en bereid bent een paar herbruikbare methoden te schrijven, kun je dat in één regel doen.

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

Maar dat is een behoorlijk brute regel.


Antwoord 11, autoriteit 2%

Nettybiedt ook een mooie query-string-parser genaamd QueryStringDecoder.
In één regel code kan het de URL in de vraag ontleden.
Ik vind het leuk omdat het niet nodig is om java.net.MalformedURLExceptionte vangen of te gooien.

In één regel:

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

Bekijk javadocs hier: https://netty. io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html

Hier is een kort, op zichzelf staand, correct voorbeeld:

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

die genereert

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

Antwoord 12

Met behulp van bovengenoemde opmerkingen en oplossingen sla ik alle queryparameters op met behulp van Map<String, Object> waar Objecten een string of Set<String> kunnen zijn. De oplossing wordt hieronder gegeven. Het wordt aanbevolen om een ​​soort url-validator te gebruiken om de url eerst te valideren en vervolgens de methode convertQueryStringToMap aan te roepen.

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

Antwoord 13

Ik heb een Kotlin-versie geprobeerd om te zien hoe dit het beste resultaat in Google is.

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

En de extensiemethoden

fun List<String>.getOrEmpty(index: Int) : String {
    return getOrElse(index) {""}
}
fun String.decodeToUTF8(): String { 
    URLDecoder.decode(this, "UTF-8")
}

Antwoord 14

Een kant-en-klare oplossing voor het decoderen van URI-querygedeelte (incl. decodering en multiparameterwaarden)

Opmerkingen

Ik was niet blij met de code van @Pr0gr4mm3r in https://stackoverflow.com/a/13592567/1211082. De op Stream gebaseerde oplossing doet geen URLDecoding, de veranderlijke versie is onhandig.

Zo heb ik een oplossing uitgewerkt die

  • Kan een URI-querygedeelte ontleden in een Map<String, List<Optional<String>>>
  • Kan meerdere waarden verwerkenvoor dezelfde parameternaam
  • Kan parameters zonder waarde correct weergeven(Optional.empty()in plaats van null)
  • Decodeert parameternamenen waarden correctvia URLdecode
  • Is gebaseerd op Java 8-streams
  • Is direct bruikbaar (zie code inclusief import hieronder)
  • Maakt een juiste foutafhandeling mogelijk (hier door een gecontroleerde uitzondering UnsupportedEncodingExceptionin een runtime-uitzondering RuntimeUnsupportedEncodingExceptionte veranderen die interactie met stream mogelijk maakt. (De reguliere functie verpakken in functies die gecontroleerde uitzonderingen weggooien) is lastig. En Scala Tryis niet beschikbaar in de standaard Java-taal.)

Java-code

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import static java.util.stream.Collectors.*;
public class URIParameterDecode {
    /**
     * Decode parameters in query part of a URI into a map from parameter name to its parameter values.
     * For parameters that occur multiple times each value is collected.
     * Proper decoding of the parameters is performed.
     * 
     * Example
     *   <pre>a=1&b=2&c=&a=4</pre>
     * is converted into
     *   <pre>{a=[Optional[1], Optional[4]], b=[Optional[2]], c=[Optional.empty]}</pre>
     * @param query the query part of an URI 
     * @return map of parameters names into a list of their values.
     *         
     */
    public static Map<String, List<Optional<String>>> splitQuery(String query) {
        if (query == null || query.isEmpty()) {
            return Collections.emptyMap();
        }
        return Arrays.stream(query.split("&"))
                    .map(p -> splitQueryParameter(p))
                    .collect(groupingBy(e -> e.get0(), // group by parameter name
                            mapping(e -> e.get1(), toList())));// keep parameter values and assemble into list
    }
    public static Pair<String, Optional<String>> splitQueryParameter(String parameter) {
        final String enc = "UTF-8";
        List<String> keyValue = Arrays.stream(parameter.split("="))
                .map(e -> {
                    try {
                        return URLDecoder.decode(e, enc);
                    } catch (UnsupportedEncodingException ex) {
                        throw new RuntimeUnsupportedEncodingException(ex);
                    }
                }).collect(toList());
        if (keyValue.size() == 2) {
            return new Pair(keyValue.get(0), Optional.of(keyValue.get(1)));
        } else {
            return new Pair(keyValue.get(0), Optional.empty());
        }
    }
    /** Runtime exception (instead of checked exception) to denote unsupported enconding */
    public static class RuntimeUnsupportedEncodingException extends RuntimeException {
        public RuntimeUnsupportedEncodingException(Throwable cause) {
            super(cause);
        }
    }
    /**
     * A simple pair of two elements
     * @param <U> first element
     * @param <V> second element
     */
    public static class Pair<U, V> {
        U a;
        V b;
        public Pair(U u, V v) {
            this.a = u;
            this.b = v;
        }
        public U get0() {
            return a;
        }
        public V get1() {
            return b;
        }
    }
}

Scala-code

… en voor de volledigheid kan ik het niet laten om in Scala de oplossing te bieden die overheerst door beknoptheid en schoonheid

import java.net.URLDecoder
object Decode {
  def main(args: Array[String]): Unit = {
    val input = "a=1&b=2&c=&a=4";
    println(separate(input))
  }
  def separate(input: String) : Map[String, List[Option[String]]] = {
    case class Parameter(key: String, value: Option[String])
    def separateParameter(parameter: String) : Parameter =
      parameter.split("=")
               .map(e => URLDecoder.decode(e, "UTF-8")) match {
      case Array(key, value) =>  Parameter(key, Some(value))
      case Array(key) => Parameter(key, None)
    }
    input.split("&").toList
      .map(p => separateParameter(p))
      .groupBy(p => p.key)
      .mapValues(vs => vs.map(p => p.value))
  }
}

Antwoord 15

Antwoord van Kotlin met initiële referentie van https://stackoverflow.com/a/51024552/3286489, maar met verbeterde versie door codes op te ruimen en 2 versies ervan te bieden, en onveranderlijke verzamelingsbewerkingen te gebruiken

Gebruik java.net.URIom de query uit te pakken. Gebruik dan de onderstaande uitbreidingsfuncties

  1. Ervan uitgaande dat u alleen de laatste waarde van de zoekopdracht wilt, d.w.z. page2&page3krijgt {page=3}, gebruik dan de onderstaande extensiefunctie
   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"
  1. Ervan uitgaande dat u een lijst met alle waarden voor de zoekopdracht wilt, d.w.z. page2&page3krijgt {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"

De manier om het te gebruiken zoals hieronder

   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}

Antwoord 16

Er zijn tal van antwoorden die geschikt zijn voor uw zoekopdracht, zoals u hebt aangegeven wanneer deze definities van één enkele parameter heeft. In sommige toepassingen kan het handig zijn om een ​​paar extra randgevallen van queryparameters af te handelen, zoals:

  • lijst met parameterwaarden zoals param1&param1=value&param1=wat betekent dat param1is ingesteld op List.of("", "value", "")
  • ongeldige permutaties zoals querypath?&=&&=noparamname&.
  • gebruik een lege tekenreeks die niet null is in kaarten a=betekent dat “a” List.of("")is om overeen te komen met de verwerking van webservlet’s

Dit gebruikt een Stream met filters en groupingBy om te verzamelen naar 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())));
}

Antwoord 17

Als je Spring gebruikt, voeg dan een argument van het type @RequestParam Map<String,String>toe aan je controllermethode, en Spring zal de kaart voor je samenstellen!


Antwoord 18

Gewoon een update naar de Java 8-versie

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- en toList()-methoden moeten worden gebruikt met Collectors, wat niet werd genoemd in het bovenste antwoord. Anders zou het een compilatiefout in IDE veroorzaken


Antwoord 19

Ik reageer hier omdat dit een populaire thread is. Dit is een schone oplossing in Kotlin die de aanbevolen api UrlQuerySanitizergebruikt. Zie de officiële documentatie. Ik heb een stringbuilder toegevoegd om de parameters samen te voegen en weer te geven.

   var myURL: String? = null
    if (intent.hasExtra("my_value")) {
        myURL = intent.extras.getString("my_value")
    } else {
        myURL = intent.dataString
    }
    val sanitizer = UrlQuerySanitizer(myURL)
    // We don't want to manually define every expected query *key*, so we set this to true
    sanitizer.allowUnregisteredParamaters = true
    val parameterNamesToValues: List<UrlQuerySanitizer.ParameterValuePair> = sanitizer.parameterList
    val parameterIterator: Iterator<UrlQuerySanitizer.ParameterValuePair> = parameterNamesToValues.iterator()
    // Helper simply so we can display all values on screen
    val stringBuilder = StringBuilder()
    while (parameterIterator.hasNext()) {
        val parameterValuePair: UrlQuerySanitizer.ParameterValuePair = parameterIterator.next()
        val parameterName: String = parameterValuePair.mParameter
        val parameterValue: String = parameterValuePair.mValue
        // Append string to display all key value pairs
        stringBuilder.append("Key: $parameterName\nValue: $parameterValue\n\n")
    }
    // Set a textView's text to display the string
    val paramListString = stringBuilder.toString()
    val textView: TextView = findViewById(R.id.activity_title) as TextView
    textView.text = "Paramlist is \n\n$paramListString"
    // to check if the url has specific keys
    if (sanitizer.hasParameter("type")) {
        val type = sanitizer.getValue("type")
        println("sanitizer has type param $type")
    }

Antwoord 20

Hier is mijn oplossing met reduceen Optioneel:

private Optional<SimpleImmutableEntry<String, String>> splitKeyValue(String text) {
    String[] v = text.split("=");
    if (v.length == 1 || v.length == 2) {
        String key = URLDecoder.decode(v[0], StandardCharsets.UTF_8);
        String value = v.length == 2 ? URLDecoder.decode(v[1], StandardCharsets.UTF_8) : null;
        return Optional.of(new SimpleImmutableEntry<String, String>(key, value));
    } else
        return Optional.empty();
}
private HashMap<String, String> parseQuery(URI uri) {
    HashMap<String, String> params = Arrays.stream(uri.getQuery()
            .split("&"))
            .map(this::splitKeyValue)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .reduce(
                // initial value
                new HashMap<String, String>(), 
                // accumulator
                (map, kv) -> {
                     map.put(kv.getKey(), kv.getValue()); 
                     return map;
                }, 
                // combiner
                (a, b) -> {
                     a.putAll(b); 
                     return a;
                });
    return params;
}
  • Ik negeer dubbele parameters (ik neem de laatste).
  • Ik gebruik Optional<SimpleImmutableEntry<String, String>>om later rommel te negeren
  • De reductie begint met een lege kaart en vult deze vervolgens op elke SimpleImmutableEntry

Als je het vraagt, reducevereist deze rare combinator in de laatste parameter, die alleen wordt gebruikt in parallelle streams. Het doel is om twee tussenresultaten samen te voegen (hier HashMap).


Antwoord 21

Als je toevallig cxf-core op het klassenpad hebt staan ​​en je weet dat je geen herhaalde queryparameters hebt, wil je misschien UrlUtils.parseQueryString.


Antwoord 22

Het Eclipse Jersey REST-frameworkondersteunt dit via UriComponent. Voorbeeld:

import org.glassfish.jersey.uri.UriComponent;
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";
MultivaluedMap<String, String> params = UriComponent.decodeQuery(URI.create(uri), true);
for (String key : params.keySet()) {
  System.out.println(key + ": " + params.getFirst(key));
}

Antwoord 23

Als je alleen de parameters na de URL van een String wilt. Dan werkt de volgende code. Ik ga uit van de simpele URL. Ik bedoel geen hard en snel controleren en decoderen. Zoals in een van mijn testcases kreeg ik de URL en ik weet dat ik alleen de waarde van de parameters nodig heb. De url was simpel. Geen codering en decodering nodig.

String location = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
String location1 = "https://stackoverflow.com?param1=value1&param2=value2&param3=value3";
String location2 = "https://stackoverflow.com?param1=value1&param2=&param3=value3&param3";
    Map<String, String> paramsMap = Stream.of(location)
        .filter(l -> l.indexOf("?") != -1)
        .map(l -> l.substring(l.indexOf("?") + 1, l.length()))
        .flatMap(q -> Pattern.compile("&").splitAsStream(q))
        .map(s -> s.split("="))
        .filter(a -> a.length == 2)
        .collect(Collectors.toMap(
            a -> a[0], 
            a -> a[1],
            (existing, replacement) -> existing + ", " + replacement,
            LinkedHashMap::new
        ));
    System.out.println(paramsMap);

bedankt

Other episodes