URI 문자열을 이름-값 컬렉션으로 구문 분석


274

다음과 같은 URI가 있습니다.

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

구문 분석 된 요소가있는 컬렉션이 필요합니다.

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

정확히 말하면 C # /. NET HttpUtility.ParseQueryString 메서드에 해당하는 Java가 필요합니다 .

제발, 이것에 대한 조언을 해주세요.

감사.



@MattBall OP가 Android를 사용하는 경우
Juan Mendes

156
이것이 java.net.URI/ API의 핵심 API의 일부가 아니라는 점이 마음에 들지 java.net.URL않습니까?
Dilum Ranatunga

이 솔루션을 확인하십시오-구문 분석 및 형식 작업에 대한 견고한 라이브러리 및 작업 예 : stackoverflow.com/a/37744000/1882064
arcseldon

답변:


342

외부 라이브러리를 사용하지 않고 달성 할 수있는 방법을 찾고 있다면 다음 코드가 도움이 될 것입니다.

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")질문에 제공된 URL을 사용 하면 "SS"가 반환됩니다.

업데이트 URL 디코딩 추가

업데이트이 답변은 여전히 ​​인기이므로 위의 방법의 향상된 버전을 만들었습니다.이 방법은 동일한 키로 여러 매개 변수를 처리하고 값이없는 매개 변수도 처리합니다.

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 버전 업데이트

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

URL로 위의 메소드 실행

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

이지도를 반환합니다 :

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

13
라이브러리가 일반적인 작업을 수행하도록하는 것이 더 좋은 이유 중 하나 인 이름과 매개 변수를 해독하는 것을 잊고 있습니다.
Juan Mendes

10
실제로, 당신은 옳습니다 ...하지만 개인적으로 내가해야 할 모든 단일 작업에 대해 자체 라이브러리를 사용하는 대신 직접 "쉬운"작업을 작성하는 것을 선호합니다.
Pr0gr4mm3r

2
이름 / 키가 동일한 여러 개의 매개 변수가있는 경우이 기능을 사용하면 비슷한 키를 가진 값이 무시됩니다.
snowball147

4
@Chris xml / html 이스케이프를 URL 인코딩과 혼동하고 있습니다. 예시 URL은 다음과 같아야합니다. a.com/q?1=a%26b&2=b%26c
sceaj

3
Collectors.mapping (...) 및 Collectors.toList (...)
Thomas Rebele

311

org.apache.http.client.utils.URLEncodedUtils

당신을 위해 그것을 할 수있는 잘 알려진 라이브러리입니다

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

출력

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

모든 요소를 ​​전달하지 않고 이름으로 값을받을 수 있습니까? 다음과 같은 의미입니다. System.out.print (params [ "one"]);
Sergey Shafiev

3
@SergeyShafiev 변환하는 사소한 List<NameValuePair>Map<String,String>그것의 모습, 해시 맵의 브래킷에 액세스 할 수 없습니다 자바 map.get("one")는 또 다른 질문해야한다, 당신이 방법을 모르는 경우 (단, 자신의 첫 번째에 그것을 시도) . 우리는 여기에서 질문을 날씬하게 유지하는 것을 선호합니다
Juan Mendes

6
URL에 동일한 매개 변수가 두 배 (예 :? a = 1 & a = 2)있는 경우 URLEncodedUtils에서 IllegalArgumentException
Crystark

10
@Crystark httpclient 4.3.3부터 이름이 중복 된 쿼리 문자열에는 예외가 발생하지 않습니다. 예상대로 작동합니다. [foo = bar, foo = baz]System.out.println(URLEncodedUtils.parse(new URI("http://example.com/?foo=bar&foo=baz"), "UTF-8")); 인쇄 합니다.
Akihiro HARAI

4
Android 6부터 Apache HTTP 클라이언트 라이브러리가 제거되었습니다. 이것은 URLEncodedUtils and NameValuePair를 더 이상 사용할 수 없음을 의미 합니다 ( 여기에 설명 된대로 레거시 Apache 라이브러리에 종속성을 추가하지 않는 한 ).
Ted Hopp

108

Spring Framework를 사용하는 경우 :

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

당신은 얻을 것이다 :

param1: ab
param2: cd,ef

1
URL 사용UriComponentsBuilder.fromHttpUrl(url)
Lu55

51

구글 구아바를 사용하고 두 줄로하십시오 :

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

너에게주는

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

18
선택한 답변에 설명 된 URL 디코딩은 어떻습니까?
클린트 이스트우드

7
또한 이름이 같은 여러 키가 의심됩니다. JavaDoc을 따르면이는 IllegalArgumentException가 발생합니다
jontro

5
수동으로 분할하는 대신 URL에 대한 무료 입력 유효성 검사를 구매할 uri때 사용해야합니다 new java.net.URL(uri).getQuery().
avgvstvs

1
디코딩을 위해 : final Map <String, String> queryVars = Maps.transformValues ​​(map, new Function <String, String> () {@Override public String apply (String value) {try {return URLDecoder.decode (value, "UTF- 8 ");} catch (UnsupportedEncodingException e) {// TODO 자동 생성 된 catch 블록 e.printStackTrace ();} 반환 값;}});
phreakhead

11
경고!! 쿼리 문자열에 중복 키가 있으면 splitter.split()throw 되므로이 작업을 수행하는 것이 안전하지 않습니다 IllegalArgumentException. 참조 stackoverflow.com/questions/1746507/...
앤더슨

31

내가 찾은 가장 짧은 방법은 다음과 같습니다.

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

업데이트 : UriComponentsBuilder 봄에서 온다. 여기 에 링크가 있습니다.


3
이 UriComponentsBuilder 클래스의 출처를 모르면별로 유용하지 않습니다.
토마스 모타 뉴

3
이미 Spring을 사용하고 있다면 이것이 좋은 아이디어라는 점에 주목할 가치가 있습니다. Spring을 사용하지 않는다면 피하고 싶을 것이다. samatkinson.com/why-i-hate-spring
Nick

1
NB URI를받습니다. Java 버전의 URI는 URL의 상위 집합이 아닙니다 (toURI가 예외를 발생시킬 수있는 이유).
Adam Gent

18

Android의 경우 프로젝트에서 OkHttp 를 사용하는 경우 당신은 이것을 볼 수 있습니다. 간단하고 도움이됩니다.

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

HttpUrl은 이상한 이름이지만 이것이 바로 내가 필요한 것입니다. 감사.
GuiSim 2016 년

10

자바 8 원문

분석 할 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");

이 솔루션은 쌍의 목록을 수집합니다.

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

반면 에이 솔루션은 맵을 수집합니다 (URL에는 이름은 같지만 값이 다른 매개 변수가 더 많을 수 있음).

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

두 솔루션 모두 유틸리티 기능을 사용하여 매개 변수를 올바르게 디코딩해야합니다.

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
이것은 Java 8 oneliner가 아닌 Java 8 방식 입니다.
Stephan

@ Stephan well :) 아마 둘 다. 그러나이 솔루션이 마음에 든다면 더 관심이 있습니다.
freedev

3
oneliner는 짧아야하며 여러 줄에 걸쳐서는 ​​안됩니다.
Stephan

1
여기에는 여러 가지 진술이 있습니다.
Stephan

2
한 줄에 전체 클래스를 작성할 수있을 것 같지만 일반적으로 "한 줄짜리"라는 문구가 아닙니다.
Abhijit Sarkar

10

서블릿 doGet을 사용하는 경우 이것을 시도하십시오

request.getParameterMap()

이 요구의 파라미터의 java.util.Map를 돌려줍니다.

매개 변수 이름을 키로, 매개 변수 값을 맵 값으로 포함하는 변경 불가능한 java.util.Map 매개 변수 맵의 키는 문자열 유형입니다. 매개 변수 맵의 값은 문자열 배열 유형입니다.

( 자바 문서 )


이것은 Spring Web 및 컨트롤러에서 HttpServletRequest작동 하며 매개 변수 유형을 가질 수 있으며 MockHttpServletRequestMock MVC 단위 테스트에서도 작동 합니다.
GameSalutes

8

Java 8을 사용하고 있고 재사용 가능한 몇 가지 메소드를 기꺼이 작성하려는 경우 한 줄로 수행 할 수 있습니다.

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

그러나 그것은 꽤 잔인한 선입니다.


3

안드로이드에는 android.net 패키지에 Uri 클래스가 있습니다. 하는 것으로 열린 우리당은 의 일부입니다 android.net 동안, URI가 의 일부입니다 java.net .

Uri 클래스에는 쿼리에서 키-값 쌍을 추출하는 많은 기능이 있습니다. 여기에 이미지 설명을 입력하십시오

다음 함수는 키-값 쌍을 HashMap 형식으로 반환합니다.

자바에서 :

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

코 틀린에서 :

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

위에서 언급 한 주석과 솔루션을 사용하여 Map <String, Object>를 사용하여 모든 쿼리 매개 변수를 저장합니다. 여기서 Objects는 string 또는 Set <String> 일 수 있습니다. 해결책은 다음과 같습니다. 어떤 종류의 URL 유효성 검사기를 사용하여 먼저 URL을 확인한 다음 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

Kotlin 버전으로 이동하여 이것이 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
}

그리고 확장 방법

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 노력과 동등한 크레딧 이지만 공동 저자는 할 수 없습니다.
Graham Smith

2

URI 쿼리 부분의 디코딩을위한 즉시 사용 가능한 솔루션 (디코딩 및 다중 매개 변수 값 포함)

코멘트

https://stackoverflow.com/a/13592567/1211082의 @ Pr0gr4mm3r에서 제공 한 코드에 만족하지 않았습니다. . 스트림 기반 솔루션은 변경 가능한 버전 덩어리 인 URLDecoding을 수행하지 않습니다.

따라서 나는 해결책을 정교하게 만들었습니다.

  • URI 쿼리 부분을 Map<String, List<Optional<String>>>
  • 여러 값을 처리 할있습니다동일한 매개 변수 이름에 대해 을
  • 값없이 매개 변수를 올바르게 나타낼 수 있음 ( Optional.empty()대신 null)
  • 다음을 통해 매개 변수 이름값을 올바르게 디코딩 합니다URLdecode
  • Java 8 Streams 기반
  • 직접 사용할 수 있습니다 (아래의 수입품을 포함한 코드 참조)
  • 적절한 오류 처리 (여기서 확인 된 예외 UnsupportedEncodingExceptionRuntimeUnsupportedEncodingException스트림과의 상호 작용을 허용 하는 런타임 예외 로 전환하여 Try)

자바 코드

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

스칼라 코드

... 완전성을 위해 스칼라에서 간결함과 아름다움으로 우세한 솔루션을 제공하는 것에 저항 할 수 없습니다.

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 버전 만 업데이트

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

맵핑 및 toList () 메소드는 최상위 답변에서 언급되지 않은 수집기와 함께 사용해야합니다. 그렇지 않으면 IDE에서 컴파일 오류가 발생합니다.


splitQueryParameters()분석법 도 공유해야 합니까? 그리고 무엇 **Collectors**입니까?
커비

1

Kotlin의 답변 https://stackoverflow.com/a/51024552/3286489 에서 처음 참조 하지만 코드를 정리하여 버전을 개선하고 2 가지 버전을 제공하며 불변 콜렉션 작업을 사용합니다

java.net.URI쿼리를 추출하는 데 사용 합니다. 그런 다음 아래 제공된 확장 기능을 사용하십시오.

  1. 당신은 단지 즉 쿼리의 마지막 값을 원하는 가정 page2&page3얻을 것이다 {page=3}, 확장 기능 아래의 사용
    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. 당신은 즉, 쿼리에 대한 모든 값의 목록을 원하는 가정 page2&page3얻을 것이다는{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"

아래와 같이 사용하는 방법

    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 는이라는 멋진 쿼리 문자열 파서를 제공합니다 QueryStringDecoder. 한 줄의 코드에서 질문의 URL을 구문 분석 할 수 있습니다. 나는 잡거나 던질 필요가 없기 때문에 좋아합니다 java.net.MalformedURLException.

한 줄로 :

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

여기에서 javadocs를 참조하십시오 : https://netty.io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html

다음은 짧고 독립적이며 올바른 예입니다.

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

어떤 생성

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

0

이것은 인기있는 스레드이기 때문에 여기에 대답하십시오. 이것은 권장 UrlQuerySanitizerAPI 를 사용하는 Kotlin의 깨끗한 솔루션입니다 . 공식 문서를 참조하십시오 . 매개 변수를 연결하고 표시하기 위해 문자열 작성기를 추가했습니다.

    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

다음은 reduceOptional 이있는 솔루션입니다 .

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;
}
  • 중복 매개 변수를 무시합니다 (마지막 매개 변수를 사용합니다).
  • Optional<SimpleImmutableEntry<String, String>>나중에 쓰레기를 무시 하는 데 사용 합니다
  • 축소는 빈 맵으로 시작한 다음 각 SimpleImmutableEntry에 채 웁니다.

요청하는 경우 reduce 에는 마지막 매개 변수 에서이 이상한 결합기가 필요하며 병렬 스트림에서만 사용됩니다. 목표는 두 개의 중간 결과 (여기서는 HashMap)를 병합하는 것입니다.


-1

Spring을 사용하는 경우 @RequestParam Map<String,String> 컨트롤러 메소드 에 type 인수를 추가하면 Spring이 맵을 생성합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.