Java EE a ServletRequest.getParameterValues () .
Sur les plates-formes non EE, RL.getQuery () renvoie simplement une chaîne.
Quelle est la méthode normale pour analyser correctement la chaîne de requête dans une URL lorsque pas sur Java EE?
< fanfaron >
Il est courant dans les réponses d'essayer de créer votre propre analyseur. C'est un projet de micro-codage très intéressant et passionnant, mais Je ne peux pas dire que c'est une bonne idée :(
Les extraits de code ci-dessous sont généralement défectueux ou cassés. Les casser est un exercice intéressant pour le lecteur. Et aux pirates informatiques attaquant les sites Web qui les utilisent .
L'analyse des chaînes de requête est un problème bien défini, mais la lecture de la spécification et la compréhension des nuances ne sont pas triviales. Il est de loin préférable de laisser un codeur de bibliothèque de plate-forme faire le travail dur et de réparer, pour vous!
</rant >
Depuis Android M les choses se sont compliquées. La réponse de Android.net.URI . GetQueryParameter () a un bogue qui casse les espaces avant JellyBean. Apache URLEncodedUtils.parse () a fonctionné, mais était obsolète en L , et supprimé en M .
La meilleure réponse est donc maintenant rlQuerySanitizer . Cela existe depuis le niveau 1 de l’API et existe toujours. Cela vous fait également penser à des questions délicates telles que la gestion des caractères spéciaux ou des valeurs répétées.
Le code le plus simple est
UrlQuerySanitizer.ValueSanitizer sanitizer = UrlQuerySanitizer.getAllButNullLegal();
// remember to decide if you want the first or last parameter with the same name
// If you want the first call setPreferFirstRepeatedParameter(true);
sanitizer.parseUrl(url);
String value = sanitizer.getValue("paramname"); // get your value
Sur Android:
import Android.net.Uri;
[...]
Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");
Sur Android, les bibliothèques Apache fournissent un analyseur de requêtes:
http://developer.Android.com/reference/org/Apache/http/client/utils/URLEncodedUtils.html et http://hc.Apache.org/httpcomponents-client -ga/httpclient/apidocs/org/Apache/http/client/utils/URLEncodedUtils.html
Voici réponse de BalusC , mais il compile et renvoie les résultats:
public static Map<String, List<String>> getUrlParameters(String url)
throws UnsupportedEncodingException {
Map<String, List<String>> params = new HashMap<String, List<String>>();
String[] urlParts = url.split("\\?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
return params;
}
Si vous avez des bibliothèques jetty (serveur ou client) sur votre chemin de classe, vous pouvez utiliser les classes jetty util (voir javadoc ), par exemple:
import org.Eclipse.jetty.util.*;
URL url = new URL("www.example.com/index.php?foo=bar&bla=blub");
MultiMap<String> params = new MultiMap<String>();
UrlEncoded.decodeTo(url.getQuery(), params, "UTF-8");
assert params.getString("foo").equals("bar");
assert params.getString("bla").equals("blub");
Si vous utilisez Spring 3.1 ou une version ultérieure (oui, espérait que le support remonterait plus loin), vous pouvez utiliser les options UriComponents
et UriComponentsBuilder
:
UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");
components.getQueryParams()
renvoie un MultiValueMap<String, String>
Pour un servlet ou une page JSP, vous pouvez obtenir des paires clé/valeur de chaîne de requête à l'aide de request.getParameter ("paramname").
String name = request.getParameter("name");
Il y a d'autres façons de le faire, mais c'est comme cela que je le fais dans toutes les servlets et les pages jsp que je crée.
J'ai des méthodes pour y parvenir:
1) :
public static String getQueryString(String url, String tag) {
String[] params = url.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
Set<String> keys = map.keySet();
for (String key : keys) {
if(key.equals(tag)){
return map.get(key);
}
System.out.println("Name=" + key);
System.out.println("Value=" + map.get(key));
}
return "";
}
2) et le moyen le plus simple de le faire en utilisant ri classe:
public static String getQueryString(String url, String tag) {
try {
Uri uri=Uri.parse(url);
return uri.getQueryParameter(tag);
}catch(Exception e){
Log.e(TAG,"getQueryString() " + e.getMessage());
}
return "";
}
et voici un exemple d'utilisation de l'une des deux méthodes suivantes:
String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";
String tagValue = getQueryString(url,"awidth");
la valeur de tagValue est 800
L'analyse de la chaîne de requête est un peu plus compliquée qu'il n'y parait, selon votre volonté de pardonner.
Premièrement, la chaîne de requête est en octets ascii. Vous lisez ces octets un à la fois et les convertissez en caractères. Si le personnage est? ou & puis il signale le début d'un nom de paramètre. Si le caractère est =, il signale le début d'une valeur de paramètre. Si le caractère est%, il signale le début d'un octet codé. Voici où cela devient difficile.
Lorsque vous lisez un caractère%, vous devez lire les deux octets suivants et les interpréter comme des chiffres hexadécimaux. Cela signifie que les deux prochains octets seront 0-9, a-f ou A-F. Collez ces deux chiffres hexadécimaux ensemble pour obtenir la valeur de votre octet. Mais rappelez-vous, les octets ne sont pas des caractères. Vous devez savoir quel encodage a été utilisé pour encoder les caractères. Le caractère é ne code pas la même chose dans UTF-8 que dans ISO-8859-1. En général, il est impossible de savoir quel encodage a été utilisé pour un jeu de caractères donné. J'utilise toujours UTF-8 car mon site Web est configuré pour tout servir en UTF-8, mais en pratique, vous ne pouvez en être sûr. Certains agents utilisateurs vous indiqueront le codage des caractères dans la demande. vous pouvez essayer de lire cela si vous avez une requête HTTP complète. Si vous avez juste une URL isolée, bonne chance.
Quoi qu'il en soit, en supposant que vous utilisez UTF-8 ou un autre encodage de caractères multi-octets, maintenant que vous avez décodé un octet encodé, vous devez le mettre de côté jusqu'à ce que vous capturiez l'octet suivant. Vous avez besoin de tous les octets codés qui sont ensemble car vous ne pouvez pas décoder correctement les URL, un octet à la fois. Mettez de côté tous les octets qui sont ensemble, puis décodez-les tous en même temps pour reconstruire votre personnage.
De plus, cela devient plus amusant si vous voulez être indulgent et prendre en compte les agents utilisateurs qui gèrent les URL. Par exemple, certains clients de messagerie Web codent les choses en double. Ou doublez les caractères? & = (Par exemple: http://yoursite.com/blah??p1==v1&&p2==v2
). Si vous voulez essayer de régler cela avec élégance, vous devrez ajouter plus de logique à votre analyseur.
Sur Android, j'ai essayé d'utiliser @diyism answer mais j'ai rencontré le problème de caractère d'espacement soulevé par @rpetrich, par exemple: je remplis un formulaire dans lequel username = "us+us"
et password = "pw pw"
provoquant l'apparence d'une chaîne URL:
http://somewhere?username=us%2Bus&password=pw+pw
Cependant, le code @diyism renvoie "us+us"
et "pw+pw"
, c’est-à-dire qu’il ne détecte pas le caractère espace. Si l'URL a été réécrite avec %20
, le caractère d'espacement est identifié:
http://somewhere?username=us%2Bus&password=pw%20pw
Cela conduit au correctif suivant:
Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");
Sur Android sa aussi simple que le code ci-dessous:
UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");
De plus, si vous ne souhaitez pas enregistrer chaque utilisation attendue de la clé de requête:
sanitzer.setAllowUnregisteredParamaters(true)
Avant d'appeler:
sanitzer.parseUrl(yourUrl)
Cela fonctionne pour moi .. Je ne suis pas sûr de savoir pourquoi tout le monde cherchait une carte, Liste> Tout ce dont j'avais besoin était une simple carte de valeur de nom.
Pour que les choses restent simples, j'ai utilisé le build dans URI.getQuery ();
public static Map<String, String> getUrlParameters(URI uri)
throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
for (String param : uri.getQuery().split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
params.put(new String(key), new String(value));
}
return params;
}
Sur Android, vous pouvez utiliser la méthode statique Uri.parse de la classe Android.net.Uri pour faire le gros du travail. Si vous faites quelque chose avec les URI et les intentions, vous voudrez quand même l'utiliser.
Juste pour référence, voici ce que j’ai obtenu (basé sur URLEncodedUtils et renvoyant une carte).
Fonctionnalités:
request.getQueryString()
)Map
videList<String>
videCode:
public static Map<String, List<String>> getParameterMapOfLists(String queryString) {
Map<String, List<String>> mapOfLists = new HashMap<String, List<String>>();
if (queryString == null || queryString.length() == 0) {
return mapOfLists;
}
List<NameValuePair> list = URLEncodedUtils.parse(URI.create("http://localhost/?" + queryString), "UTF-8");
for (NameValuePair pair : list) {
List<String> values = mapOfLists.get(pair.getName());
if (values == null) {
values = new ArrayList<String>();
mapOfLists.put(pair.getName(), values);
}
if (pair.getValue() != null) {
values.add(pair.getValue());
}
}
return mapOfLists;
}
Un assistant de compatibilité (les valeurs sont stockées dans un tableau String exactement comme dans ServletRequest.getParameterMap () ):
public static Map<String, String[]> getParameterMap(String queryString) {
Map<String, List<String>> mapOfLists = getParameterMapOfLists(queryString);
Map<String, String[]> mapOfArrays = new HashMap<String, String[]>();
for (String key : mapOfLists.keySet()) {
mapOfArrays.put(key, mapOfLists.get(key).toArray(new String[] {}));
}
return mapOfArrays;
}
Multimap de Guava est mieux adapté pour cela. Voici une version courte propre:
Multimap<String, String> getUrlParameters(String url) {
try {
Multimap<String, String> ret = ArrayListMultimap.create();
for (NameValuePair param : URLEncodedUtils.parse(new URI(url), "UTF-8")) {
ret.put(param.getName(), param.getValue());
}
return ret;
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
Apache AXIS2 a une implémentation autonome de QueryStringParser.Java. Si vous n'utilisez pas Axis2, téléchargez simplement le code source et le scénario de test à partir d'ici -
Réponse d'origine ici
Sur Android, la classe Uri est incluse dans le package Android.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
}
Basé sur la réponse de BalusC, j’ai écrit un exemple de code Java:
if (queryString != null)
{
final String[] arrParameters = queryString.split("&");
for (final String tempParameterString : arrParameters)
{
final String[] arrTempParameter = tempParameterString.split("=");
if (arrTempParameter.length >= 2)
{
final String parameterKey = arrTempParameter[0];
final String parameterValue = arrTempParameter[1];
//do something with the parameters
}
}
}
Répondre ici parce que c'est un fil populaire. Il s’agit d’une solution propre de 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 the url is sent from a different activity where you set it to a value
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")
}
public static Map <String, String> parseQueryString (final URL url)
throws UnsupportedEncodingException
{
final Map <String, String> qps = new TreeMap <String, String> ();
final StringTokenizer pairs = new StringTokenizer (url.getQuery (), "&");
while (pairs.hasMoreTokens ())
{
final String pair = pairs.nextToken ();
final StringTokenizer parts = new StringTokenizer (pair, "=");
final String name = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
final String value = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
qps.put (name, value);
}
return qps;
}
en utilisant la goyave:
Multimap<String,String> parseQueryString(String queryString, String encoding) {
LinkedListMultimap<String, String> result = LinkedListMultimap.create();
for(String entry : Splitter.on("&").omitEmptyStrings().split(queryString)) {
String pair [] = entry.split("=", 2);
try {
result.put(URLDecoder.decode(pair[0], encoding), pair.length == 2 ? URLDecoder.decode(pair[1], encoding) : null);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return result;
}
Utilisez Apache HttpComponents et connectez-le avec un code de collection pour accéder aux paramètres par valeur: http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-Java-and-accessing -values-by-key /
Je ne pense pas qu'il y en a un dans JRE. Vous pouvez trouver des fonctions similaires dans d'autres paquets, comme Apache HttpClient. Si vous n'utilisez aucun autre paquet, il vous suffit d'écrire le vôtre. Ce n'est pas si dur. Voici ce que j'utilise,
public class QueryString {
private Map<String, List<String>> parameters;
public QueryString(String qs) {
parameters = new TreeMap<String, List<String>>();
// Parse query string
String pairs[] = qs.split("&");
for (String pair : pairs) {
String name;
String value;
int pos = pair.indexOf('=');
// for "n=", the value is "", for "n", the value is null
if (pos == -1) {
name = pair;
value = null;
} else {
try {
name = URLDecoder.decode(pair.substring(0, pos), "UTF-8");
value = URLDecoder.decode(pair.substring(pos+1, pair.length()), "UTF-8");
} catch (UnsupportedEncodingException e) {
// Not really possible, throw unchecked
throw new IllegalStateException("No UTF-8");
}
}
List<String> list = parameters.get(name);
if (list == null) {
list = new ArrayList<String>();
parameters.put(name, list);
}
list.add(value);
}
}
public String getParameter(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
if (values.size() == 0)
return "";
return values.get(0);
}
public String[] getParameterValues(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
return (String[])values.toArray(new String[values.size()]);
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameters.keySet());
}
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new TreeMap<String, String[]>();
for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
List<String> list = entry.getValue();
String[] values;
if (list == null)
values = null;
else
values = (String[]) list.toArray(new String[list.size()]);
map.put(entry.getKey(), values);
}
return map;
}
}