最近在研究java原生方法实现http服务,但网上一直没有找到可靠的x-www-form-urlencoded编码/解码代码,要么找到的就是简单的一维key-value转换,无法实现复杂对象的转换,例如提交以下参数:
我写的代码提供两个静态方法,分别是实现编码的方法public static String urlencode(Object params, String key),和实现解码的方法public static Map<String, Object> urldecode(String param)。
编码方法传入的params参数支持包含String、Number、Map、List或者上述类型的数组对象。
解码方法输出统一是map对象,如传入的参数包含有数组或者list对象,则输出时统一转化为list对象。
代码中已经提供了测试方法,运行main方法即可看到结果。
package com.util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.ArrayUtils;
public class HttpUrlParams {
public static void main(String args[]) {
Map<String, Object> map = new HashMap<String, Object>();
List<Object> list = new ArrayList<Object>();
list.add("aa");
list.add(123);
list.add(new Object[] {"qq", 11});
map.put("list", list);
Map<String, Object> childMap = new HashMap<String, Object>();
childMap.put("num", 78);
childMap.put("str", "str?!+-str");
childMap.put("array", new int[] {44,55});
map.put("childMap", childMap);
map.put("array", new String[] {"ss", "Kk"});
System.out.println(map);
String encodeStr = urlencode(map, "");
System.out.println(encodeStr);
Object decodeObj = urldecode(encodeStr);
System.out.println(decodeObj);
}
public static String urlencode(Object params, String key) {
String res = "";
if(params instanceof Map) {
Map<String, Object> _params = (Map<String, Object>) params;
for(String i : _params.keySet()) {
String k = key.isEmpty() ? i : (key +"["+ i +"]");
String encodeValue = urlencode(_params.get(i), k);
if(!encodeValue.isEmpty()) {
res += '&'+ encodeValue;
}
}
}
else if(params instanceof List) {
List<Object> _params = (List<Object>) params;
for(Integer i = 0; i < _params.size(); i++) {
String k = key.isEmpty() ? i.toString() : (key +"["+ i.toString() +"]");
String encodeValue = urlencode(_params.get(i), k);
if(!encodeValue.isEmpty()) {
res += '&'+ encodeValue;
}
}
}
else if(params.getClass().isArray()) {
Object[] _params;
if(params instanceof Object[]) {
_params = (Object[]) params;
}
else if(params instanceof String[]) {
_params = (String[]) params;
}
else if(params instanceof int[]) {
_params = ArrayUtils.toObject((int[]) params);
}
else if(params instanceof double[]) {
_params = ArrayUtils.toObject((double[]) params);
}
else {
_params = new Object[] {};
}
for(Integer i = 0; i < _params.length; i++) {
String k = key.isEmpty() ? i.toString() : (key +"["+ i.toString() +"]");
String encodeValue = urlencode(_params[i], k);
if(!encodeValue.isEmpty()) {
res += '&'+ encodeValue;
}
}
}
else if(params instanceof String) {
String _params = (String) params;
try {
res += '&'+ URLEncoder.encode(key, "UTF-8") +'='+ URLEncoder.encode(_params, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
else if(params instanceof Number) {
Number _params = (Number) params;
try {
res += '&'+ URLEncoder.encode(key, "UTF-8") +'='+ URLEncoder.encode(_params.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
else {
return "";
}
return res.substring(1);
}
public static Map<String, Object> urldecode(String param) {
if(param == null || param.isEmpty()) {
return null;
}
//解码
String[] params = param.split("&");
Map<String, String> key2value = new TreeMap<String, String>();
for(int i = 0; i < params.length; i++) {
String[] p = params[i].split("=");
if(p.length == 0) {
continue;
}
try {
String keyStr = URLDecoder.decode(p[0], "UTF-8");
if(keyStr.isBlank()) {
continue;
}
String valueStr;
if(p.length == 2) {
valueStr = URLDecoder.decode(p[1], "UTF-8");
} else {
valueStr = "";
}
key2value.put(keyStr, valueStr);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//遍历每一行传参
Map<String, Object> map = new HashMap<String, Object>();
for(Map.Entry<String, String> entry : key2value.entrySet()) {
String keyStr = entry.getKey();
String value = entry.getValue();
//根目录的key
Matcher keyMatcher = Pattern.compile("^[a-zA-Z\\_]{1}[\\w]*").matcher(keyStr);
if(!keyMatcher.find()) {
continue;
}
String key = keyMatcher.group(0);
if(!map.containsKey(key)) {
map.put(key, new HashMap<String, Object>());
}
//二级以及二级目录以上的key
String pattern = "\\[([\\w]+?)\\]";
Matcher filterMatcher = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(keyStr);
//获取所有的patternKey
List<String> patternKeyList = new ArrayList<String>();
while(filterMatcher.find()) {
String patternKey = filterMatcher.group(1);
patternKeyList.add(patternKey);
}
//有子元素
if(!patternKeyList.isEmpty()) {
//遍历并写入
Object childMap = map.get(key);
int patternKeyListSize = patternKeyList.size();
for(int j = 0; j < patternKeyListSize; j++) {
String patternKey = patternKeyList.get(j);
Map<String, Object> _childMap = (HashMap<String, Object>) childMap;
if(!_childMap.containsKey(patternKey)) {
//是否是最后一个节点,是的话直接赋值
if(j == patternKeyListSize-1) {
_childMap.put(patternKey, value);
break;
}
_childMap.put(patternKey, new HashMap<String, Object>());
}
childMap = _childMap.get(patternKey);
}
}
//只有一级元素
else {
map.put(key, value);
}
}
map = (Map<String, Object>) map2list(map);
return map;
}
private static Object map2list(Map<String, Object> map) {
Set<String> keySet = map.keySet();
boolean all_is_number = true;
for(String key : keySet) {
//不是数字
if(!Pattern.matches("^[0-9]+$", key)) {
all_is_number = false;
}
Object childNode = map.get(key);
if(childNode instanceof Map) {
childNode = map2list((Map<String, Object>) childNode);
map.put(key, childNode);
}
}
Object res;
if(all_is_number) {
res = new ArrayList<Object>();
for(String key : keySet) {
Object value = map.get(key);
((List<Object>) res).add(value);
}
} else {
res = map;
}
return res;
}
}