RtMallSignMd5Utils.java
5.3 KB
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.diligrp.cashier.mall.util;
import com.diligrp.cashier.shared.util.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
import java.util.*;
/**
* @ClassName SignMd5Utils.java
* @author dengwei
* @version 1.0.0
* @Description
* 签名算法
* 参考大润发定义:https://shopex.yuque.com/hl0rrx/vlp0m4/kmcazgnimg28d8ih?singleDoc#
*/
public class RtMallSignMd5Utils {
private static final Logger log = LoggerFactory.getLogger(RtMallSignMd5Utils.class);
/**
* 生成签名
*
*/
public static String generateSign(Object data, String appSecret) {
Map<String, Object> params = JsonUtils.convertValueV2(data, new TypeReference<>() {
});
// 1. 过滤 null,转换 boolean,递归规范化并排序
String normalized = normalizeAndSort(params);
log.info("normalize: {}", normalized);
// 2. 拼接私钥
String signSource = appSecret + normalized + appSecret;
log.info("signSource: {}", signSource);
// 3. MD5 + 大写
String sign = md5ToUpper(signSource);
log.info("sign: {}", sign);
return sign;
}
/**
* 递归规范化并排序,返回拼接字符串(无分隔符)
*/
@SuppressWarnings("unchecked")
private static String normalizeAndSort(Object obj) {
switch (obj) {
case null -> {
return "";
}
case Map map1 -> {
Map<String, Object> map = (Map<String, Object>) obj;
// 过滤 null,并转换 boolean
Map<String, Object> filtered = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() == null) {
continue;
}
Object val = convertBoolean(entry.getValue());
filtered.put(entry.getKey(), val);
}
// 按 key 字典序排序
List<String> sortedKeys = new ArrayList<>(filtered.keySet());
Collections.sort(sortedKeys); // 字典序
StringBuilder sb = new StringBuilder();
for (String key : sortedKeys) {
sb.append(key).append(normalizeAndSort(filtered.get(key)));
}
return sb.toString();
}
case List list1 -> {
List<Object> list = (List<Object>) obj;
// 转为 Map<String, Object>,key 为索引字符串
Map<String, Object> indexMap = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
indexMap.put(String.valueOf(i), list.get(i));
}
// 递归处理(会自动过滤 null、转换 boolean、排序 key)
return normalizeAndSort(indexMap);
// 递归处理(会自动过滤 null、转换 boolean、排序 key)
}
case Object[] array -> {
// 处理数组类型,转换为 Map 并递归处理
Map<String, Object> arrayMap = new LinkedHashMap<>();
for (int i = 0; i < array.length; i++) {
arrayMap.put(String.valueOf(i), array[i]);
}
return normalizeAndSort(arrayMap);
}
default -> {
}
}
// 基本类型:转字符串
return obj.toString();
}
/**
* 转换 Boolean 为 "1"/"0"
*/
private static Object convertBoolean(Object obj) {
if (obj instanceof Boolean) {
return (Boolean) obj ? "1" : "0";
}
return obj;
}
/**
* MD5 并转大写
*/
private static String md5ToUpper(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString().toUpperCase();
} catch (Exception e) {
throw new RuntimeException("MD5 failed", e);
}
}
public static void main(String[] args) {
// 构建顶层参数 Map
Map<String, Object> params = new HashMap<>();
params.put("app_key", "221zzcwxee30nucj0rx1");
params.put("timestamp", 1734351194L); // 使用 Long 避免溢出
params.put("nonce_str", "cvwEv8JRNzHd3eaV");
params.put("order_id", "1234567890"); // order_id 可以是字符串或数字,这里按字符串处理更安全
// 构建 item_list
List<Map<String, Object>> itemList = new ArrayList<>();
for (int i = 1; i <= 11; i++) {
Map<String, Object> subOrder = new HashMap<>();
subOrder.put("sub_order_id", i);
subOrder.put("price", 100);
itemList.add(subOrder);
}
params.put("item_list", itemList);
// 打印验证(可选)
log.info("Params: {}", JsonUtils.toJsonString(params));
String sign = generateSign(params, "ho7ygrsrwged4zwhwpbadtdgzugmulez");
log.info("Sign: {}", sign);
}
}