Bir URI Dizesini Ad-Değer Koleksiyonuna Ayrıştırma


274

URI şu şekilde var:

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

Ayrıştırılmış öğeler içeren bir koleksiyona ihtiyacım var:

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

Tam olarak, C # /. NET HttpUtility.ParseQueryString yöntemi için bir Java eşdeğeri gerekir .

Lütfen, bana bu konuda bir tavsiye ver.

Teşekkürler.



@MattBall OP Android kullanıyorsa, o zaman
Juan Mendes

156
O akla durgunluk veren bu çekirdek API parçası olmadığından değil mi java.net.URI/ ' java.net.URL?
Dilum Ranatunga

Lütfen bu çözümü kontrol edin - hem Ayrıştırma hem de Biçimlendirme işlemleri için sağlam kütüphane ve çalışma örneği: stackoverflow.com/a/37744000/1882064
arcseldon

Yanıtlar:


342

Harici bir kitaplık kullanmadan bunu başarmanın bir yolunu arıyorsanız, aşağıdaki kod size yardımcı olacaktır.

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")Sorunuza verilen URL ile "SS" döndürülecek şekilde, döndürülen Haritaya erişebilirsiniz .

UPDATE URL Kod Çözme eklendi

GÜNCELLEME Bu cevap hala oldukça popüler olduğu için yukarıdaki yöntemin, aynı anahtarla birden fazla parametreyi ve değeri olmayan parametreleri işleyen gelişmiş bir sürümünü yaptım.

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 sürümünü GÜNCELLE

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

Yukarıdaki yöntemi URL ile çalıştırma

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

bu haritayı döndürür:

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

13
Adların ve parametrelerin kodunu çözmeyi unutuyorsunuz, bu nedenle kütüphanelerin ortak görevleri yapmasına izin vermek genellikle daha iyidir.
Juan Mendes

10
haklısın, haklısın ... ama kişisel olarak, yapmam gereken her bir görev için kendi kütüphanesini kullanmak yerine kendi başıma bu tür "kolay" görevleri yazmayı tercih ediyorum.
Pr0gr4mm3r

2
aynı ada / anahtara sahip birden fazla parametreniz varsa, bu işlevi kullanmak benzer anahtara sahip değeri geçersiz kılar.
snowball147

4
@Chris xml / html'den kaçmayı URL kodlamasıyla karıştırıyorsunuz. Örnek URL'niz şöyle olmalıdır: a.com/q?1=a%26b&2=b%26c
sceaj

3
hangi işlevlerin kullanıldığını belirtmek iyi olur: Collectors.mapping (...) ve Collectors.toList (...)
Thomas Rebele

311

org.apache.http.client.utils.URLEncodedUtils

sizin için yapabileceğiniz tanınmış bir kütüphanedir

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

çıktılar

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

Tüm öğeleri iletmeden değeri adına göre alabilir miyim? Bunun gibi bir şey demek istiyorum: System.out.print (params ["one"]);
Sergey Shafiev

3
@SergeyShafiev List<NameValuePair>Bir Map<String,String>Java'ya dönüştürme yapmak için karma haritalar için parantez erişimi yoktur, map.get("one")eğer bunu nasıl yapacağınızı bilmiyorsanız, başka bir soru olmalı (ama önce kendi başınıza deneyin) . SO'daki soruları burada ince tutmayı tercih ediyoruz
Juan Mendes

6
URL'nizde aynı parametrenin iki katı varsa (yani? A = 1 & a = 2) URLEncodedUtils'in
IllegalArgumentException

10
@Crystark httpclient 4.3.3 itibariyle, yinelenen adlara sahip sorgu dizesi herhangi bir istisna oluşturmaz. Beklendiği gibi çalışır. [foo = bar, foo = baz]System.out.println(URLEncodedUtils.parse(new URI("http://example.com/?foo=bar&foo=baz"), "UTF-8")); yazdıracaktır .
Akihiro HARAI

4
Android 6'dan itibaren Apache HTTP istemci kitaplığı kaldırıldı. Bu, URLEncodedUtils and NameValuePair`'in artık kullanılamayacağı anlamına gelir ( burada açıklandığı gibi eski Apache kütüphanesine bağımlılık eklemediğiniz sürece ).
Ted Hopp

109

Spring Framework kullanıyorsanız:

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

Alacaksın:

param1: ab
param2: cd,ef

1
URL kullanımı içinUriComponentsBuilder.fromHttpUrl(url)
Lu55

51

google Guava kullanın ve 2 satırda yapın:

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

hangisi sana verir

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

18
Seçilen cevapta açıklanan URL kod çözme ne olacak?
Clint Eastwood

7
Bu, aynı ada sahip birden fazla tuştan da şüphelenilir. Javadocs göre bu bir IllegalArgumentException atacak
jontro

5
Manuel olarak bölmek yerine , URL'de ücretsiz giriş doğrulaması satın aldığınız için urikullanmalısınız new java.net.URL(uri).getQuery().
avgvstvs

1
Kod çözme için: final Map <String, String> queryVars = Maps.transformValues ​​(harita, yeni İşlev <Dize, Dize> () {@Override public Dize geçerlidir (Dize değeri) {try {return URLDecoder.decode (değer, "UTF- 8 ");} catch (UnsupportedEncodingException e) {// TODO Otomatik oluşturulan catch bloğu e.printStackTrace ();} dönüş değeri;}});
phreakhead

11
UYARI!! Sorgu dizesinde yinelenen anahtar varsa splitter.split()atılacağı için bunu yapmak güvenli DEĞİLDİR IllegalArgumentException. Bkz. Stackoverflow.com/questions/1746507/…
Anderson

31

Bulduğum en kısa yol şudur:

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

GÜNCELLEME: UriComponentsBuilder İlkbahardan gelir. İşte bağlantı .


3
Bu UriComponentsBuilder sınıfının nereden geldiğini bilmeden çok kullanışlı değil.
Thomas Mortagne

3
İlkbahar kullanıyorsanız, bunun sadece iyi bir fikir olduğunu belirtmek gerekebilir. Spring kullanmıyorsanız, bundan kaçınmak isteyeceksiniz. samatkinson.com/why-i-hate-spring
Nick

1
Not URI alır. Java'nın URI'ler sürümü URL'lerin bir üst kümesi değildir (bu nedenle toURI istisnalar atabilir).
Adam Gent

18

Android için kullanıyorsanız projenizde OkHttp . Buna bir göz atabilirsiniz. Basit ve yararlı.

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

HttpUrl biraz garip bir isim ama tam da ihtiyacım olan şey bu. Teşekkürler.
GuiSim

10

Java 8 bir deyimi

Analiz edilecek URL verildi:

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

Bu çözüm bir çift listesi toplar:

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

Öte yandan bu çözüm bir harita toplar (bir url'de aynı ada ancak farklı değerlere sahip daha fazla parametre olabileceği göz önüne alındığında).

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

Her iki çözüm de parametreleri düzgün şekilde çözmek için bir yardımcı program işlevi kullanmalıdır.

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

4
Bu, bir Java 8 oneliner yerine bir Java 8 yaklaşımıdır .
Stephan

@Stephan well :) belki ikisi de. Ama bu çözümü beğenip beğenmediğinizi anlamak istiyorum.
freedev

3
IMO, bir oneliner kısa olmalı ve birden fazla satıra yayılmamalıdır.
Stephan

1
Burada birden fazla ifade var.
Stephan

2
Sanırım bütün bir sınıfı tek bir satıra yazabilirsiniz, ama genellikle "tek astar" ifadesi ile kastedilen bu değildir.
Abhijit Sarkar

10

Servlet doGet kullanıyorsanız bunu deneyin

request.getParameterMap()

Bu isteğin parametrelerinin java.util.Map değerini döndürür.

Döndürür: anahtar olarak parametre adlarını ve harita değerleri olarak parametre değerlerini içeren değişmez bir java.util.Map. Parametre eşlemesindeki anahtarlar String türündedir. Parametre eşlemesindeki değerler String dizesi türündedir.

( Java dokümanı )


Bu, Spring Web ile olduğu gibi kontrol cihazınızda da bir parametre türüne sahip olabilir HttpServletRequestve MockHttpServletRequestMock MVC birim testlerinde de çalışır .
GameSalutes

8

Java 8 kullanıyorsanız ve birkaç yeniden kullanılabilir yöntem yazmak istiyorsanız, bunu tek bir satırda yapabilirsiniz.

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

Ama bu oldukça acımasız bir çizgi.


3

Android'de android.net paketinde bir Uri sınıfı var . Not o Uri parçasıdır android.net iken, URI parçasıdır java.net .

Uri sınıfı, bir sorgudan anahtar / değer çiftlerini ayıklamak için birçok işleve sahiptir. resim açıklamasını buraya girin

Aşağıdaki işlev, anahtar / değer çiftlerini HashMap biçiminde döndürür.

Java dilinde:

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

Kotlin'de:

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
    }

2

Yukarıda belirtilen yorum ve çözümleri kullanarak, tüm sorgu parametrelerini Map <String, Object> kullanarak burada Nesnelerin dize veya Set <String> saklıyorum. Çözelti aşağıda verilmiştir. Önce url'yi doğrulamak için bir tür url doğrulayıcı kullanılması ve ardından convertQueryStringToMap yöntemini çağırmanız önerilir.

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

Bunun Google'daki en iyi sonuç olduğunu görmek için Kotlin versiyonuna gittim.

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

Ve uzatma yöntemleri

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

fun String.decodeToUTF8(): String { 
    URLDecoder.decode(this, "UTF-8")
}

1
Stackoverflow.com/users/1203812/matthew-herod 50/50 çaba için eşit kredi ama ortak yazar olamaz.
Graham Smith

2

URI sorgu parçasının kodunu çözmek için kullanıma hazır bir çözüm (kod çözme ve çoklu parametre değerleri dahil)

Yorumlar

Https://stackoverflow.com/a/13592567/1211082'de @ Pr0gr4mm3r tarafından sağlanan koddan memnun değildim . Akış tabanlı çözüm, değiştirilebilir sürüm yığını olan URLDecoding'i yapmaz.

Böylece bir çözüm geliştirdim.

  • Bir URI sorgu parçasını bir Map<String, List<Optional<String>>>
  • Can birden fazla değer işlemek aynı parametre adı için
  • Can düzgün bir değeri olmayan parametreleri temsil ( Optional.empty()yerine null)
  • Çözer parametre adları ve değerleri doğru ileURLdecode
  • Java 8 Akışlarına dayanır
  • Doğrudan kullanılabilir mi (aşağıdaki ithalatları içeren koda bakın)
  • Düzgün hata işlemeye izin verir (burada işaretli bir istisnayı akışla etkileşime izin veren UnsupportedEncodingExceptionbir çalışma zamanı istisnasına RuntimeUnsupportedEncodingExceptiondönüştürerek Try.

Java Kodu

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 Kodu

... ve tamlık uğruna Scala'da kısalık ve güzelliğin hakim olduğu çözümü sağlamaya dayanamıyorum

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

1

Java 8 sürümüne yönelik bir güncelleme

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 ve toList () yöntemleri, en üst yanıtta belirtilmeyen Koleksiyonerler ile birlikte kullanılmalıdır. Aksi takdirde IDE'ye derleme hatası verir


splitQueryParameters()yönteminizi de paylaşmanız gerekiyor gibi görünüyor ? Peki ne oluyor **Collectors**?
Kirby

1

Kotlin'in cevabı, https://stackoverflow.com/a/51024552/3286489 adresinden ilk referansla , ancak kodları toplayarak ve bunun 2 sürümünü sağlayarak geliştirilmiş sürümü ile ve değişmez toplama işlemlerini kullanarak

java.net.URISorguyu ayıklamak için kullanın . Ardından, aşağıdaki sağlanan uzantı işlevlerini kullanın

  1. Yalnızca yani sorgunun son değerini istediğiniz varsayarsak page2&page3alacak {page=3}, uzatma fonksiyonu altında kullanmak
    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. Eğer yani sorgu için tüm değerin bir liste istediğiniz varsayarsak page2&page3alacak{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"

Aşağıdaki gibi kullanmak için yolu

    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}

1

Netty ayrıca çağrılan güzel bir sorgu dizesi ayrıştırıcı sağlar QueryStringDecoder. Bir kod satırında, sorudaki URL'yi ayrıştırabilir. Seviyorum çünkü yakalama veya fırlatma gerektirmiyor java.net.MalformedURLException.

Bir satırda:

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

Javadoc'lara buradan bakın: https://netty.io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html

İşte kısa, bağımsız, doğru bir örnek:

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

hangi üretir

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

0

Buraya cevap veriyorum çünkü bu popüler bir konu. Bu Kotlin'de önerilen API'yi kullanan temiz bir çözümdür UrlQuerySanitizer. Resmi belgelere bakın . Parametre birleştirmek ve görüntülemek için bir dize oluşturucu ekledim.

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

0

İşte benim çözüm azaltmak ve İsteğe bağlı :

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;
}
  • Yinelenen parametreleri yok sayıyorum (sonuncuyu alıyorum).
  • Optional<SimpleImmutableEntry<String, String>>Çöpü daha sonra görmezden gelirim
  • İndirgeme boş bir harita ile başlar, ardından her SimpleImmutableEntry üzerine yerleştirir

Sormanız durumunda, azaltmak , yalnızca paralel akışlarda kullanılan son parametrede bu garip birleştiriciyi gerektirir. Amacı iki ara sonucu birleştirmektir (burada HashMap).


-1

Spring kullanıyorsanız, @RequestParam Map<String,String> denetleyici yönteminize bir tür argümanı ekleyin; Spring, haritayı sizin için oluşturacaktır!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.