J'ai l'URI comme ceci:
https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback
J'ai besoin d'une collection avec des éléments analysés:
NAME VALUE
------------------------
client_id SS
response_type code
scope N_FULL
access_type offline
redirect_uri http://localhost/Callback
Pour être exact, il me faut un équivalent Java pour la méthode C # HttpUtility.ParseQueryString . S'il vous plaît, donnez-moi un conseil à ce sujet . Merci.
Si vous cherchez un moyen de le réaliser sans utiliser de bibliothèque externe, le code suivant vous aidera.
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;
}
Vous pouvez accéder à la carte renvoyée à l'aide de <map>.get("client_id")
. L'URL indiquée dans votre question renvoie "SS".
UPDATEURL-Decoding ajouté
UPDATEComme cette réponse est encore très populaire, j'ai mis au point une version améliorée de la méthode ci-dessus, qui gère plusieurs paramètres avec la même clé et des paramètres sans valeur.
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;
}
MISE &AGRAVE; JOURversion 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);
}
Exécuter la méthode ci-dessus avec l'URL
https://stackoverflow.com?param1=value1¶m2=¶m3=value3¶m3
renvoie cette carte:
{param1=["value1"], param2=[null], param3=["value3", null]}
est une bibliothèque bien connue qui peut le faire pour vous
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());
}
Les sorties
one : 1
two : 2
three : 3
three : 3a
Remarque: fonctionne uniquement avec HTTP PUT ou HTTP POST
Si vous utilisez Spring Framework:
public static void main(String[] args) {
String uri = "http://youhost.com/test?param1=abc¶m2=def¶m2=ghi";
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));
}
Tu auras:
param1: abc
param2: def,ghi
utilisez google guava et faites le en 2 lignes:
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);
}
}
qui te donne
{client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback}
Le chemin le plus court que j'ai trouvé est celui-ci:
MultiValueMap<String, String> queryParams =
UriComponentsBuilder.fromUriString(url).build().getQueryParams();
UPDATE:UriComponentsBuilder
vient du printemps. Ici le lien .
Pour Android, si vous utilisez OkHttp dans votre projet. Vous pourriez avoir un coup d'oeil à ceci. C'est simple et utile.
final HttpUrl url = HttpUrl.parse(query);
if (url != null) {
final String target = url.queryParameter("target");
final String id = url.queryParameter("id");
}
Si vous utilisez Java 8 et que vous souhaitez écrire quelques méthodes réutilisables, vous pouvez le faire en une seule ligne.
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);
}
}
Mais c'est une ligne assez brutale.
Étant donné l'URL à analyser:
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");
Cette solution collecte une liste de paires:
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());
Cette solution, par contre, collecte une carte (étant donné que dans une URL, il peut y avoir plus de paramètres portant le même nom mais des valeurs différentes).
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())));
Les deux solutions doivent utiliser une fonction utilitaire pour décoder correctement les paramètres.
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);
}
}
Si vous utilisez servlet doGet essayez ceci
request.getParameterMap()
Retourne un Java.util.Map des paramètres de cette requête.
Résultats: une Java.util.Map immuable contenant des noms de paramètre sous forme de clés et des valeurs de paramètre sous forme de valeurs de carte Les clés de la mappe de paramètres sont de type String. Les valeurs dans la mappe de paramètres sont de type String array.
( Java doc )
En utilisant les commentaires et les solutions susmentionnées, je stocke tous les paramètres de requête en utilisant Map <String, Object>, où les objets peuvent être string ou Set <String>. La solution est donnée ci-dessous. Il est recommandé d'utiliser une sorte de validateur d'URL pour valider d'abord l'URL, puis d'appeler la méthode 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;
}
}
Je me suis essayé à une version Kotlin en voyant que c'était le meilleur résultat obtenu par 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
}
Et les méthodes d'extension
fun List<String>.getOrEmpty(index: Int) : String {
return getOrElse(index) {""}
}
fun String.decodeToUTF8(): String {
URLDecoder.decode(this, "UTF-8")
}
Juste une mise à jour de la version 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())));
}
les méthodes mapping et toList () doivent être utilisées avec des collecteurs, ce qui n'était pas mentionné dans la réponse principale. Sinon, cela provoquerait une erreur de compilation dans l'IDE
Netty fournit également un analyseur syntaxique de chaînes de requête appelé QueryStringDecoder
. Dans une ligne de code, il peut analyser l'URL de la question. J'aime parce que cela ne nécessite pas d'attraper ou de lancer Java.net.MalformedURLException
.
En une ligne:
Map<String, List<String>> parameters = new QueryStringDecoder(url).parameters();
Voir javadocs ici: https://netty.io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html
Voici un exemple court, autonome et correct:
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)));
}
}
qui génère
NAME VALUE
------------------------
client_id SS
response_type code
scope N_FULL
access_type offline
redirect_uri http://localhost/Callback
Répondre ici parce que c'est un fil populaire. Ceci est une solution propre à Kotlin qui utilise l’application recommandée UrlQuerySanitizer
Voir la documentation officielle . J'ai ajouté un constructeur de chaînes pour concaténer et afficher les paramètres.
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")
}
Voici ma solution avec réduire et Facultatif:
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>>
pour ignorer les ordures plus tardSi vous le demandez, réduire requiert cet étrange combineur dans le dernier paramètre, qui n'est utilisé que dans les flux parallèles. Son objectif est de fusionner deux résultats intermédiaires (ici HashMap).
La réponse de Kotlin avec la référence initiale de https://stackoverflow.com/a/51024552/3286489 , mais avec une version améliorée en rangeant les codes et en fournissant 2 versions, et utilisant des opérations de collecte immuables
Utilisez Java.net.URI
pour extraire la requête. Ensuite, utilisez les fonctions d'extension fournies ci-dessous
page2&page3
obtienne {page=3}
, utilisez la fonction d'extension ci-dessous. 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"
page2&page3
obtiendra {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"
La façon de l'utiliser comme ci-dessous
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}
Sur Android, la classe Uri est présente dans le packageAndroid.net. Notez que Uri fait partie d'Android.net, tandis que URI fait partie de Java.net.
La classe Uri a de nombreuses fonctions pour extraire les paires clé-valeur de requête.
La fonction suivante renvoie des paires clé-valeur sous la forme de HashMap.
En 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;
}
À 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
}