Java URL文字列からクエリストリングを取得


URL文字列からクエリストリングを取得するのに、どうしてよいかわからず、調べた結果をメモします。

参考サイト


stackoverflow

実装結果

参考サイトに記載あるように以下の通り実装しました。

    String url = "http://www.example.com/something.html?one=1&two=2&three=3&three=3a";
    List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), "UTF-8");

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

NameValuePair#getName()でクエリストリングのkey値が
NameValuePair#getValue()でvalue値が取得可能です。

補足(逆パターン)

URLの組み立てには、 javax.ws.rs.core.UriBuilderを使用しました。 使用例は以下の通りです。 ※UriBuilder#queryParam()でクエリストリングを追加しています。

    String urlParts = "1234567"
    String embedUrl = "https://www.youtube.com/embed/" + urlParts;
    String returnValue = UriBuilder.fromUri(embedUrl)
            .queryParam("autohide", "2")
            .queryParam("autoplay", "0")
            .queryParam("cc_load_policy", "0")
            .queryParam("controls", "1")
            .queryParam("disablekb", "0")
            .queryParam("enablejsapi", "0")
            .queryParam("fs", "1")
            .queryParam("iv_load_policy", "1")
            .queryParam("loop", "0")
            .queryParam("modestbranding", "0").toString();

感想

Android の Uri とか、Uri.Builder がいい感じに使える気がするので、
なんだか面倒だなという気になりました。 ※もっといい方法があるのかもしれません。


クエリストリングのキー値に重複がある場合

気になり始めたため、以下のようなプログラムを作成して、
戻りを確認してみました。

  • NameValuePairGetQueryStringFromUrlExample.java

    import org.apache.http.NameValuePair;
    import org.apache.http.client.utils.URLEncodedUtils;
    
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.List;
    
    /**
     * NameValuePairGetQueryStringFromUrlExample
     */
    public class NameValuePairGetQueryStringFromUrlExample {
        public static void main(String... args) {
            // Use Guava
            String uri1 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
            List<NameValuePair> params1 = null;
            try {
                params1 = URLEncodedUtils.parse(new URI(uri1), "UTF-8");
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            for (NameValuePair param : params1) {
                System.out.println(param.getName() + " : " + param.getValue());
            }
    
            String uri2 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&access_type=online&redirect_uri=http://localhost/Callback";
    
            List<NameValuePair> params2 = null;
            try {
                params2 = URLEncodedUtils.parse(new URI(uri2), "UTF-8");
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            for (NameValuePair param : params2) {
                System.out.println(param.getName() + " : " + param.getValue());
            }
    
        }
    }
    

  • Output
    access_type をキー値に持つ、NameValuePair が2つ取得されました。

    ############
    client_id : SS
    response_type : code
    scope : N_FULL
    access_type : offline
    redirect_uri : http://localhost/Callback
    ############
    client_id : SS
    response_type : code
    scope : N_FULL
    access_type : offline
    access_type : online
    redirect_uri : http://localhost/Callback
    


その他の方法

上記以外の取得方法についての記載です。

Guavaを使う

  • GuavaGetQueryStringFromUrlExample.java
    import com.google.common.base.Splitter;
    
    import java.util.Map;
    
    import static java.lang.System.out;
    
    /**
     * GuavaGetQueryStringFromUrlExample
     */
    public class GuavaGetQueryStringFromUrlExample {
    
        public static void main(String... args) {
            // Use Guava
            String uri1 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
            String query1 = uri1.split("\\?")[1];
            final Map<String, String> useGuavaOutputMap1 = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(query1);
            out.println("Use Guave START>>>");
            out.println(useGuavaOutputMap1);
            out.println("<<<END");
    
            String uri2 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&access_type=online&redirect_uri=http://localhost/Callback";
            String query2 = uri2.split("\\?")[1];
            final Map<String, String> useGuavaOutputMap2 = Splitter.on('&').trimResults().withKeyValueSeparator("=").split(query2);
            out.println("Use Guave START>>>");
            out.println(useGuavaOutputMap2);
            out.println("<<<END");
    
        }
    }
    
  • Output キー値に重複があると、例外がスローされます。
    Exception in thread "main" java.lang.IllegalArgumentException: Duplicate key [access_type] found.
    Use Guave START>>>
    {client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback}
        at com.google.common.base.Preconditions.checkArgument(Preconditions.java:148)
    <<<END
        at com.google.common.base.Splitter$MapSplitter.split(Splitter.java:506)
        at xyz.monotalk.google.webmaster.cli.getquerystringfromurl.GuavaGetQueryStringFromUrlExample.main(GuavaGetQueryStringFromUrlExample.java:25)
    
    Process finished with exit code 1
    

Java の標準API で処理する

  • JavaNativeGetQueryStringFromUrlExample.java クエリストリングとキー値を保持するMapを返します。

    mport java.io.UnsupportedEncodingException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.util.LinkedHashMap;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    
    import static java.lang.System.out;
    
    /**
     * JavaNativeGetQueryStringFromUrlExample
     */
    public class JavaNativeGetQueryStringFromUrlExample {
        public static void main(String... args) {
            String uri1 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
            // Java Native
            final Map<String, List<String>> useJavaNativeOutputMap1 = splitQuery(uri1);
            out.println("Use Java Native START>>>");
            out.println(useJavaNativeOutputMap1);
            out.println("<<<END");
    
            String uri2 = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&access_type=online&redirect_uri=http://localhost/Callback";
            // Java Native
            final Map<String, List<String>> useJavaNativeOutputMap2 = splitQuery(uri2);
            out.println("Use Java Native START>>>");
            out.println(useJavaNativeOutputMap2);
            out.println("<<<END");
    
        }
    
        public static Map<String, List<String>> splitQuery(String url) {
            URL urlObject = null;
            try {
                urlObject = new URL(url);
            } catch (MalformedURLException e) {
                throw new IllegalArgumentException(e);
            }
            final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
            final String[] pairs = urlObject.getQuery().split("&");
            try {
                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);
                }
            } catch (UnsupportedEncodingException e) {
                throw new IllegalStateException(e);
            }
            return query_pairs;
        }
    }
    

  • Output キー値 access_type に、2つにVlalue値が設定されました。

    Use Java Native START>>>
    {client_id=[SS], response_type=[code], scope=[N_FULL], access_type=[offline], redirect_uri=[http://localhost/Callback]}
    <<<END
    Use Java Native START>>>
    {client_id=[SS], response_type=[code], scope=[N_FULL], access_type=[offline, online], redirect_uri=[http://localhost/Callback]}
    <<<END
    

POST送信などだと、キー値が複数の場合もざらにあるので、想定しとくべきパターンなのだと思います。
以上です。

コメント