java在android上解析查询字符串

bzzcjhmw  于 2021-07-05  发布在  Java
关注(0)|答案(25)|浏览(420)

java ee拥有 ServletRequest.getParameterValues() .
在非ee平台上, URL.getQuery() 只返回一个字符串。
当不在javaee上时,正确解析url中的查询字符串的正常方法是什么?
在答案中,尝试创建自己的解析器是很流行的。这是一个非常有趣和令人兴奋的微编码项目,但我不能说这是一个好主意。
下面的代码片段通常是有缺陷或损坏的。打破它们对读者来说是一个有趣的练习。以及攻击使用它们的网站的黑客。
解析查询字符串是一个定义良好的问题,但是阅读规范并理解其中的细微差别是非常重要的。最好让一些平台库编码人员来为您做艰苦的工作,并进行修复!

vcirk6k6

vcirk6k616#

我有办法做到这一点:
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) 最简单的方法是使用uri类:

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

这是一个如何使用两种方法之一的例子:

String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";      
String tagValue = getQueryString(url,"awidth");

tagvalue的值为 800

30byixjq

30byixjq17#

在android上,其简单代码如下:

UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");

另外,如果不想注册每个预期的查询键,请使用:

sanitzer.setAllowUnregisteredParamaters(true)

打电话前:

sanitzer.parseUrl(yourUrl)
1sbrub3j

1sbrub3j18#

回答这里因为这是一个流行的线程。这是kotlin的清洁溶液,使用推荐的 UrlQuerySanitizer 应用程序编程接口。见官方文件。我添加了一个字符串生成器来连接和显示参数。

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")
    }
qyzbxkaa

qyzbxkaa19#

你说的是“java”,但不是“javaee”。您的意思是说您使用的是jsp和/或servlet,而不是完整的javaee堆栈?如果是这样的话,那么您应该仍然可以使用request.getparameter()。
如果您的意思是您正在编写java,但是您没有编写JSP或servlet,或者您只是使用java作为参考点,但是您在其他没有内置参数解析的平台上。。。哇,这听起来是个不太可能的问题,但如果是这样,原则是:

xparm=0
word=""
loop
  get next char
  if no char
    exit loop
  if char=='='
    param_name[xparm]=word
    word=""
  else if char=='&'
    param_value[xparm]=word
    word=""
    xparm=xparm+1
  else if char=='%'
    read next two chars
    word=word+interpret the chars as hex digits to make a byte
  else
    word=word+char

(我可以编写java代码,但那是毫无意义的,因为如果您有可用的java,您可以只使用request.getparameters。)

jqjz2hbq

jqjz2hbq20#

自从android m以来,事情变得更复杂了。答案 android.net.URI.getQueryParameter() 有一只虫子在果冻豆前打破空格。Apache URLEncodedUtils.parse() 工作,但在l中被弃用,在m中被删除。
所以现在最好的答案是 UrlQuerySanitizer . 这从api级别1开始就存在,现在仍然存在。它还让您思考一些棘手的问题,如如何处理特殊字符或重复值。
最简单的代码是

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");

如果您对默认解析行为满意,可以执行以下操作:

new UrlQuerySanitizer(url).getValue("paramName")

但是您应该确保了解默认的解析行为是什么,因为它可能不是您想要的。

4jb9z9bj

4jb9z9bj21#

原汁原味地回答这里
在android上,android.net包中有uri类。注意,uri是android.net的一部分,而uri是java.net的一部分。
uri类有许多函数来提取查询键值对。

下面的函数以hashmap的形式返回键值对。
在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
    }
gk7wooem

gk7wooem22#

在android上,可以使用android.net.uri类的uri.parse静态方法来完成繁重的工作。如果您正在使用uri和意图做任何事情,那么您无论如何都会希望使用它。

ycggw6v2

ycggw6v223#

如果您使用的是Spring3.1或更高版本(yikes希望支持能更进一步),那么可以使用 UriComponents 以及 UriComponentsBuilder :

UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");
``` `components.getQueryParams()` 返回一个 `MultiValueMap<String, String>` 这里有更多的文档。
iqxoj9l9

iqxoj9l924#

解析查询字符串比看起来要复杂一些,这取决于您想要的宽容程度。
首先,查询字符串是ascii字节。你一次读入一个字节,然后把它们转换成字符。如果角色是?or&然后它表示参数名的开始。如果字符为=则表示参数值的开始。如果字符为%,则表示编码字节的开始。这就是它变得棘手的地方。
当你读入一个%char时,你必须读入下两个字节并将它们解释为十六进制数字。这意味着接下来的两个字节将是0-9,a-f或a-f。把这两个十六进制数字粘在一起得到字节值。但请记住,字节不是字符。你必须知道什么编码被用来编码字符。人物é 在utf-8中的编码与在iso-8859-1中的编码不同。一般来说,不可能知道给定字符集使用了什么编码。我总是使用utf-8,因为我的网站配置为总是使用utf-8为所有内容提供服务,但实际上你不能确定。一些用户代理会告诉您请求中的字符编码;如果您有一个完整的http请求,您可以尝试阅读它。如果你只是有一个孤立的网址,祝你好运。
无论如何,假设您正在使用utf-8或其他一些多字节字符编码,现在您已经解码了一个编码字节,您必须将它放在一边,直到捕获下一个字节。您需要所有编码的字节,因为您不能一次正确解码一个字节。把所有在一起的字节放在一边,然后一次将它们全部解码以重建您的角色。
另外,如果你想宽大一点,并且考虑到用户代理会破坏url,它会变得更有趣。例如,一些webmail客户机对东西进行双重编码。或将?&=字符加倍(例如: http://yoursite.com/blah??p1==v1&&p2==v2 ). 如果您想优雅地处理这个问题,您需要向解析器添加更多的逻辑。

6qqygrtg

6qqygrtg25#

使用Guava:

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

相关问题