Разбирайте строку URI в коллекцию именных значений

У меня есть 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 

Если быть точным, мне нужен Java-эквивалент для метода C # HttpUtility.ParseQueryString. Пожалуйста, дайте мне совет по этому поводу. Благодарю.

Если вы ищете способ достичь этого, не используя внешнюю библиотеку, вам поможет следующий код.

 public static Map splitQuery(URL url) throws UnsupportedEncodingException { Map query_pairs = new LinkedHashMap(); 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; } 

Вы можете получить доступ к возвращенной карте с помощью

.get("client_id")

, с URL-адресом, указанным в вашем вопросе, это вернет «SS».

Добавлено расширение URL-расширений UPDATE

ОБНОВЛЕНИЕ Поскольку этот ответ по-прежнему довольно популярен, я сделал улучшенную версию вышеописанного метода, который обрабатывает несколько параметров с одним и тем же ключом и параметрами без значения.

 public static Map> splitQuery(URL url) throws UnsupportedEncodingException { final Map> query_pairs = new LinkedHashMap>(); 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()); } 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> 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 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]} 

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

Если вы используете Spring Framework:

 public static void main(String[] args) { String uri = "http://youhost.com/test?param1=abc&param2=def&param2=ghi"; MultiValueMap parameters = UriComponentsBuilder.fromUriString(uri).build().getQueryParams(); List param1 = parameters.get("param1"); List param2 = parameters.get("param2"); System.out.println("param1: " + param1.get(0)); System.out.println("param2: " + param2.get(0) + "," + param2.get(1)); } 

Ты получишь:

 param1: abc param2: def,ghi 

используйте google Guava и сделайте это в двух строках:

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

Самый короткий путь, который я нашел, это:

 MultiValueMap queryParams = UriComponentsBuilder.fromUriString(url).build().getQueryParams(); 

ОБНОВЛЕНИЕ: UriComponentsBuilder приходит с весны. Вот ссылка .

Если вы используете Java 8 и вы готовы написать несколько методов многократного использования, вы можете сделать это в одной строке.

 private Map> 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  List mergeLists(final List l1, final List l2) { List list = new ArrayList<>(); list.addAll(l1); list.addAll(l2); return list; } private static  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); } } 

Но это довольно жестокая линия.

Java 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> list = Pattern.compile("&").splitAsStream(url.getQuery()) .map(s -> Arrays.copyOf(s.split("="), 2)) .map(o -> new AbstractMap.SimpleEntry(decode(o[0]), decode(o[1]))) .collect(toList()); 

Это решение, с другой стороны, собирает карту (учитывая, что в URL-адресе может быть больше параметров с тем же именем, но с разными значениями).

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

Для Android, если вы используете OkHttp в своем проекте. Вы можете взглянуть на это. Это просто и полезно.

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

Если вы используете сервлет doGet, попробуйте это

 request.getParameterMap() 

Возвращает java.util.Map параметров этого запроса.

Возвращает: неизменяемая java.util.Map, содержащая имена параметров в качестве ключей и значений параметров в качестве значений карты. Ключи в карте параметров имеют тип String. Значения в карте параметров имеют тип String array.

( Java-документ )

Используя вышеупомянутые комментарии и решения, я сохраняю все параметры запроса, используя Map , где Objects могут быть строковыми или Set . Решение приведено ниже. Рекомендуется использовать какой-либо валидатор URL для проверки подлинности URL-адреса, а затем вызвать метод convertQueryStringToMap.

 private static final String DEFAULT_ENCODING_SCHEME = "UTF-8"; public static Map convertQueryStringToMap(String url) throws UnsupportedEncodingException, URISyntaxException { List params = URLEncodedUtils.parse(new URI(url), DEFAULT_ENCODING_SCHEME); Map 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(Arrays.asList(value.split(","))) : value; } else { Set queryValueSet = responseMap.get(key) instanceof Set ? (Set) responseMap.get(key) : new HashSet(); if (value.contains(",")) { queryValueSet.addAll(Arrays.asList(value.split(","))); } else { queryValueSet.add(value); } return queryValueSet; } } 

Если вы используете Spring, добавьте аргумент типа @RequestParam Map в свой метод controllerа, а Spring построит карту для вас!

Просто обновление версии Java 8

 public Map> 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

У меня была версия Kotlin, которая показала, что это лучший результат в Google.

 @Throws(UnsupportedEncodingException::class) fun splitQuery(url: URL): Map> { val queryPairs = LinkedHashMap>() 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.getOrEmpty(index: Int) : String { return getOrElse(index) {""} } fun String.decodeToUTF8(): String { URLDecoder.decode(this, "UTF-8") } 
  • Преобразование String в Uri
  • Как проверить, является ли строка допустимым URL-адресом HTTP?
  • Как работать с URISyntaxException
  • Как параметры отправляются в HTTP-запрос POST?
  • Android 2.2 MediaPlayer отлично работает с одним URL-адресом SHOUTcast, но не с другим
  • Создать «файл: //» URI в проводнике Windows
  • Как проверить правильность строки uri
  • В чем разница между URI, URL-адресом и URN?
  • как получить uri ресурса изображения в android
  • Легкий способ разобрать URL-адрес на кросс-платформе C ++?
  • Авторитарная позиция дублирования ключей HTTP GET
  • Давайте будем гением компьютера.