Analyser une chaîne D'URI dans la Collection nom-valeur
J'ai L'URI comme ceci:
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, j'ai besoin D'un équivalent Java pour C # HttpUtility.Méthode ParseQueryString. S'il vous plaît, me donner un conseil sur ce. Grâce.
13 réponses
Si vous cherchez un moyen d'y parvenir sans utiliser une 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 retournée en utilisant <map>.get("client_id")
, avec l'URL donnée dans votre question, cela retournerait "SS".
Mise à jour URL-décodage ajouté
UPDATE Comme cette réponse est toujours très populaire, j'ai fait une version améliorée de la méthode ci-dessus, qui gère plusieurs paramètres avec la même clé et les paramètres sans valeur comme Bien.
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 à jour Version 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]}
Org.Apache.http.client.utils.URLEncodedUtils
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());
}
Sorties
one : 1
two : 2
three : 3
three : 3a
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));
}
, Vous obtiendrez:
param1: abc
param2: def,ghi
Utilisez google goyave 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);
}
}
Ce qui vous 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();
Mise À JOUR: UriComponentsBuilder
ça vient du printemps. Ici le lien.
Si vous utilisez Java 8 et que vous êtes prêt à é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.
Pour Android, si vous utilisez OkHttp dans votre projet. Vous pourriez obtenir un coup d'oeil à ce. Il 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");
}
Java 8 une instruction
Compte tenu de 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 d'autre part recueille une carte (étant donné que dans une url il peut y avoir plus de paramètres avec 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.La carte des paramètres de cette demande.
retours: un java immuable.util.Carte contenant des noms de paramètres en tant que clés et des valeurs de paramètres en tant que valeurs de carte. Les clés de la carte des paramètres sont de type String. Les valeurs de la carte des paramètres sont de type String array.
(Java doc)
En utilisant les commentaires et les solutions mentionnés ci-dessus, je stocke tous les paramètres de requête en utilisant Map
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;
}
}
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 qui n'ont pas été mentionnés dans la réponse supérieure. Sinon, il lancerait une erreur de compilation dans IDE
Si vous utilisez Spring, ajoutez un argument de type @RequestParam Map<String,String>
à votre méthode de contrôleur, et Spring construira la carte pour vous!
J'ai essayé une version Kotlin en voyant comment c'est le meilleur résultat dans 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")
}