Parsing query strings on Android
Java EE servletrequest.getparametervalues(HAS)。P></
非url.getquery EE的在线平台,简单的在()返回的字符串。P></
什么是正常的方式properly to the the URL查询字符串中解析Java EE when not在线?P></
咆哮>
它是流行在the answers to尝试和使你自己的解析器。This is甚微的兴趣和激励项目编码,但不能说它是好主意,:(P></
generally below are the code代码片断flawed或破断,BTW。them is an for the阅读器运动的兴趣。黑客的攻击和to the the网站,使用他们。P></
查询字符串是parsing问题出发,但阅读和理解上帝is the the spec不平凡。它是使图书馆更好的让一些平台式编码器和硬盘做工作,做修复,为你!P></
></咆哮P></
安卓:
1 2 3 4 5 6 | import android.net.Uri; [...] Uri uri=Uri.parse(url_string); uri.getQueryParameter("para1"); |
在Android上,Apache库提供了一个查询解析器:
http://developer.android.com/reference/org/apache/http/client/utils/urlencodedutils.html和http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/urlencodedutils.html
自从安卓M以来,事情变得更复杂了。android.net.uri.getQueryParameter()的答案有一个bug,它会在jellbean之前破坏空格。apache urlencodedutils.parse()起作用,但在L中被否决,在M中被删除。
所以现在最好的答案是urlquerysanitizer。这从API 1级开始就存在,并且仍然存在。它还让您思考一些棘手的问题,比如如何处理特殊字符或重复值。
最简单的代码是
1 2 3 4 5 | 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 |
以下是Balusc的答案,但它编译并返回结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } |
如果类路径上有jetty(服务器或客户端)libs,则可以使用jetty-util类(请参见javadoc),例如:
1 2 3 4 5 6 7 |
如果您使用的是Spring3.1或更高版本(Yikes,希望支持能再进一步),您可以使用
1 2 | UriComponents components = UriComponentsBuilder.fromUri(uri).build(); List<String> myParam = components.getQueryParams().get("myParam"); |
这里还有一些文档。
对于servlet或JSP页面,可以使用request.getParameter("paramname")获取queryString键/值对。
1 |
还有其他的方法可以做到这一点,但我在创建的所有servlet和jsp页面中都是这样做的。
分析查询字符串比看起来要复杂一些,这取决于您希望的宽容程度。
首先,查询字符串是ASCII字节。您一次读取一个字节,然后将其转换为字符。如果角色是?或者&;然后它指示参数名称的开头。如果字符为=则表示参数值的开始。如果字符为%,则表示编码字节的开始。这就是问题的症结所在。
当你读取一个%char时,你必须读取接下来的两个字节,并将它们解释为十六进制数字。这意味着接下来的两个字节将是0-9、a-f或a-f。将这两个十六进制数字粘合在一起以获得字节值。但请记住,字节不是字符。你必须知道用什么编码来编码字符。字符_在UTF-8中的编码与在ISO-8859-1中的编码不同。一般来说,不可能知道给定字符集使用了什么编码。我总是使用UTF-8,因为我的网站被配置为总是使用UTF-8为所有内容提供服务,但实际上你不能确定。一些用户代理会告诉您请求中的字符编码;如果您有完整的HTTP请求,您可以尝试读取它。如果你只有一个单独的网址,祝你好运。
不管怎样,假设您使用的是UTF-8或其他一些多字节字符编码,既然您已经解码了一个已编码的字节,那么在捕获下一个字节之前,必须将它放在一边。您需要将所有编码的字节放在一起,因为您不能一次正确地对一个字节进行URL解码。将所有的字节放在一起,然后一次对它们进行解码,以重建您的角色。
另外,如果你想宽容一点,并且考虑到用户代理会破坏URL的话,这会变得更有趣。例如,一些Webmail客户机对事物进行双重编码。还是加倍?&;=chars(例如:
我有办法做到这一点:
1):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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类:
1 2 3 4 5 6 7 8 9 |
这是一个如何使用以下两种方法之一的示例:
1 2 |
tagvalue的值为
在Android上,我尝试使用@diyism answer,但遇到了@rpetrich提出的空格字符问题,例如:我填写了一个表单,其中
1 | http://somewhere?username=us%2Bus&password=pw+pw |
但是,@diyism code返回
1 | http://somewhere?username=us%2Bus&password=pw%20pw |
这将导致以下修复:
1 2 | Uri uri = Uri.parse(url_string.replace("+","%20")); uri.getQueryParameter("para1"); |
这对我有用……我不知道为什么每个人都在地图后面,list>我只需要一个简单的名称-值映射。
为了简单起见,我使用了内置的uri.getquery();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } |
在android上,可以使用android.net.uri类的uri.parse静态方法来完成繁重的工作。如果你对uris和intent做了什么,你无论如何都会想使用它。
仅供参考,这是我最后得出的结论(基于urlencodedutils,并返回一张地图)。
特征:
- 它接受URL的查询字符串部分(您可以使用
request.getQueryString() ) - 空查询字符串将产生空的
Map 。 - 没有值(?测试)将映射到空的
List 。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; } |
兼容性助手(值存储在字符串数组中,就像servletrequest.getParameterMap()中一样):
1 2 3 4 5 6 7 8 9 10 | 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; } |
在Android上,其简单代码如下:
1 2 | UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url); String value = sanitzer.getValue("your_get_parameter"); |
另外,如果不想注册每个预期的查询键,请使用:
1 | sanitzer.setAllowUnregisteredParamaters(true) |
打电话之前:
1 | sanitzer.parseUrl(yourUrl) |
番石榴的多重地图更适合这个。下面是一个简短的清晰版本:
1 2 3 4 5 6 7 8 9 10 11 | 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); } } |
ApacheAxis2有一个独立的queryStringParser.java实现。如果您不使用axis2,只需从这里下载源代码和测试用例。-
http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/src/org/apache/axis2/transport/http/util/querystringparser.java
http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/test/org/apache/axis2/transport/http/util/querystringparsertest.java
奥利加纳利在这里回答
在android上,包android.net中有uri类。请注意,uri是android.net的一部分,而uri是java.net的一部分。
URI类有许多函数来提取查询键值对。
下面的函数以hashmap的形式返回键值对。
在Java中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |
使用apache httpcomponents并将其与一些收集代码连接起来,以便按值访问参数:http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-java-and-accessing-values-by-key/
番石榴:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } |
基于BalusC的答案,我编写了一些Java代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } } } |
我觉得JRE里没有。您可以在其他包中找到类似的函数,如ApacheHTTPClient。如果你不使用任何其他软件包,你只需要自己写。这并不难。这是我用的,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 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; } } |
回答这里是因为这是一个流行的话题。这是Kotlin中使用推荐的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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 Value: $parameterValue ") } // 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 $paramListString" // to check if the url has specific keys if (sanitizer.hasParameter("type")) { val type = sanitizer.getValue("type") println("sanitizer has type param $type") } |
此方法获取par名称和par值的uri和返回映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static Map<String, String> getQueryMap(String uri) { String queryParms[] = uri.split("\\?"); Map<String, String> map = new HashMap<>();// if (queryParms == null || queryParms.length == 0) return map; String[] params = queryParms[1].split("&"); for (String param : params) { String name = param.split("=")[0]; String value = param.split("=")[1]; map.put(name, value); } return map; } |
你说的是"Java",而不是"Java EE"。您的意思是使用JSP和/或servlet,而不是完整的JavaEE堆栈?如果是这样,那么您应该仍然可以使用request.getParameter()。
如果你的意思是你正在编写Java,但是你不是在写JSP和servlet,或者你只是用Java作为你的参考点,但是你在其他没有内置参数解析的平台上…哇,这听起来不太可能,但如果是这样,原则是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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可用,你可以只使用请求。