personalizar - progressbar java thread
Analizar una cadena URI en la colección de nombre-valor (14)
Tengo el URI de esta manera:
https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback
Necesito una colección con elementos analizados:
NAME VALUE
------------------------
client_id SS
response_type code
scope N_FULL
access_type offline
redirect_uri http://localhost/Callback
Para ser exactos, necesito un equivalente de Java para C # HttpUtility.ParseQueryString Method. Por favor, dame un consejo sobre esto. Gracias.
org.apache.http.client.utils.URLEncodedUtils
Es una biblioteca muy conocida que puede hacerlo por ti.
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());
}
Salidas
one : 1
two : 2
three : 3
three : 3a
Java 8 una declaración
Dada la URL a analizar:
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");
Esta solución recoge una lista de pares:
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());
Esta solución, por otro lado, recopila un mapa (dado que en una url puede haber más parámetros con el mismo nombre pero diferentes valores).
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())));
Ambas soluciones deben usar una función de utilidad para decodificar adecuadamente los parámetros.
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);
}
}
El camino más corto que he encontrado es este:
MultiValueMap<String, String> queryParams =
UriComponentsBuilder.fromUriString(url).build().getQueryParams();
ACTUALIZACIÓN: UriComponentsBuilder
viene de Spring. Aquí el enlace .
Para Android, si está utilizando OkHttp en su proyecto. Usted puede echar un vistazo a esto. Es simple y útil.
final HttpUrl url = HttpUrl.parse(query);
if (url != null) {
final String target = url.queryParameter("target");
final String id = url.queryParameter("id");
}
Probé una versión de Kotlin al ver que este es el mejor resultado en 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
}
Y los métodos de extensión.
fun List<String>.getOrEmpty(index: Int) : String {
return getOrElse(index) {""}
}
fun String.decodeToUTF8(): String {
URLDecoder.decode(this, "UTF-8")
}
Respondiendo aquí porque este es un hilo popular. Esta es una solución limpia en Kotlin que utiliza la API UrlQuerySanitizer
recomendada. Consulte la documentación oficial . He añadido un generador de cadenas para concatenar y mostrar los parámetros.
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")
}
Si está buscando una manera de lograrlo sin usar una biblioteca externa, el siguiente código lo ayudará.
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;
}
Puede acceder al Mapa devuelto usando <map>.get("client_id")
, con la URL que figura en su pregunta, esto devolvería "SS".
ACTUALIZACIÓN de decodificación de URL añadida
ACTUALIZACIÓN Como esta respuesta sigue siendo bastante popular, hice una versión mejorada del método anterior, que maneja múltiples parámetros con la misma clave y parámetros sin valor también.
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;
}
ACTUALIZAR la versión de 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);
}
Ejecutando el método anterior con la URL
https://.com?param1=value1¶m2=¶m3=value3¶m3
devuelve este mapa:
{param1=["value1"], param2=[null], param3=["value3", null]}
Si está utilizando Java 8 y está dispuesto a escribir algunos métodos reutilizables, puede hacerlo en una línea.
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);
}
}
Pero esa es una línea bastante brutal.
Si está utilizando 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));
}
Conseguirás:
param1: abc
param2: def,ghi
Si está utilizando Spring, agregue un argumento de tipo @RequestParam Map<String,String>
a su método de controlador, ¡y Spring construirá el mapa por usted!
Si está utilizando el servlet doGet intente esto
request.getParameterMap()
Devuelve un java.util.Map de los parámetros de esta solicitud.
Devuelve: un java.util.Map inmutable que contiene nombres de parámetros como claves y valores de parámetros como valores de mapa. Las claves en el mapa de parámetros son de tipo String. Los valores en el mapa de parámetros son de tipo String array.
Solo una actualización a la versión de 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())));
}
Los métodos de mapeo y toList () se deben usar con Recopiladores que no se mencionó en la respuesta principal. De lo contrario lanzaría un error de compilación en IDE.
Usa google guava y hazlo en 2 líneas:
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);
}
}
lo que te da
{client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback}
Usando los comentarios y soluciones mencionados anteriormente, estoy almacenando todos los parámetros de consulta usando Map <String, Object> donde los objetos pueden ser string o Set <String>. La solución se da a continuación. Se recomienda usar algún tipo de validador de url para validar primero la url y luego llamar al método 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;
}
}