背景:
网上签名大部分用的到了阿里的fastjon,奈何有些项目不能使用这个jar包,只能另寻方法
签名规则说明:
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
编码:
很多接口文档都是安装这个来签名,以下方法为生成复杂字符串的编码。原始字符串为:
{"code":1000,"msg":"成功","sign":"1c87a66dc889f660b4d6f689da44fbc5f5a4cbfa1616a62829b9518f74a12e27","data":{"taskId":94,"taskVersion":1605859691729,"sessionId":"1630582279605eh3qPMCG","isDelete":0,"diagnosisEndTime":1633108878,"taskInfo":{"taskType":1,"diagnoseType":1,"diagnoseConfig":{"executeNumber":0},"otxInfo":[{"id":118,"strategyId":94,"otxId":39,"otxFileName":"fileName.ttb","ttbFileName":"fileName.ttb","ttbFilePath":"filePath","diagnosisFun":"测试功能2"},{"id":119,"strategyId":94,"otxId":38,"otxFileName":"fileName.ttb","ttbFileName":"fileName.ttb","ttbFilePath":"filePath","diagnosisFun":"测试功能"}]}}}
字符串转Map:
使用的是gson,也可以替换成jackson
Gson gson = new Gson();
Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> tmpMap = gson.fromJson(jsonStr, map.getClass());
map转Sting字符串:
public static String getSignContent(Map<String, Object> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Map<String, String> datas = new HashMap<>(16);
params.remove("sign");
buildMapData("", params, datas);
Set<String> strings = datas.keySet();
List<String> keyList = new ArrayList<>(strings);
Collections.sort(keyList);
StringBuffer sb = new StringBuffer();
for (String key : keyList) {
sb.append("&");
sb.append(key.replaceFirst(".", ""));
sb.append("=");
sb.append(datas.get(key));
}
String content = sb.toString().replaceFirst("&", "");
return content;
}
排序方法:
public static void buildMapData(String prefix, Object object, Map<String, String> datas) {
if (object instanceof List) {
List arrayList = (List) object;
for (int k = 0; k < arrayList.size(); k++) {
String pre = prefix.replaceFirst(".", "");
pre = prefix + "[" + k + "]";
Map<String, Object> map = (Map<String, Object>) arrayList.get(k);
Set<String> keySet = map.keySet();
List<String> result = new ArrayList<>(keySet);
for (String mapKey : result) {
Object value = map.get(mapKey);
String key = pre + "." + mapKey;
buildMapData(key, value, datas);
}
}
} else if (object instanceof Map) {
Map linkedHashMap = (Map) object;
Set<String> keySet = linkedHashMap.keySet();
List<String> result = new ArrayList<>(keySet);
for (String mapKey : result) {
Object value = linkedHashMap.get(mapKey);
String pre = prefix + "." + mapKey;
buildMapData(pre, value, datas);
}
} else {
datas.put(prefix, object.toString());
}
}
结果:
用这个方法生成的签名串:
code=1000.0&data.diagnosisEndTime=1.633108878E9&data.isDelete=0.0&data.sessionId=1630582279605eh3qPMCG&data.taskId=94.0&data.taskInfo.diagnoseConfig.executeNumber=0.0&data.taskInfo.diagnoseType=1.0&data.taskInfo.otxInfo[0].diagnosisFun=测试功能2&data.taskInfo.otxInfo[0].id=118.0&data.taskInfo.otxInfo[0].otxFileName=fileName.ttb&data.taskInfo.otxInfo[0].otxId=39.0&data.taskInfo.otxInfo[0].strategyId=94.0&data.taskInfo.otxInfo[0].ttbFileName=fileName.ttb&data.taskInfo.otxInfo[0].ttbFilePath=filePath&data.taskInfo.otxInfo[1].diagnosisFun=测试功能&data.taskInfo.otxInfo[1].id=119.0&data.taskInfo.otxInfo[1].otxFileName=fileName.ttb&data.taskInfo.otxInfo[1].otxId=38.0&data.taskInfo.otxInfo[1].strategyId=94.0&data.taskInfo.otxInfo[1].ttbFileName=fileName.ttb&data.taskInfo.otxInfo[1].ttbFilePath=filePath&data.taskInfo.taskType=1.0&data.taskVersion=1.605859691729E12&msg=成功
结束:
这个方法基本满足所有的场景,支持各种嵌套模式!