MaxPay 支付接口文档
本文档提供了MaxPay支付平台所有接口的详细说明和使用方法,包括代收、代付、订单查询及回调处理等核心功能。
6. 代付订单回调
POST
application/json
注意: 商户接收到系统的异步回调请求后,如成功处理订单,请在接口响应纯文本字符串 'success'。
回调参数
| 参数名 | 类型 | 描述 |
|---|---|---|
transferno |
string | 订单号 |
outtransferno |
string | 商户订单号 |
tradeamount |
string | 商户账户扣除金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000) |
transferamount |
string | 代付金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000) |
endtime |
string | 支付时间 |
remark |
string | 备注 |
status |
string | 订单状态:1已结算 4撤销结算(代付成功和取消代付为最终状态,均会回调通知) |
sign |
string | 签名 |
Java 示例
Java 示例代码
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
public class TransferCallback {
private static final String SECRET = "your_secret_key"; // 替换成你自己的密钥
// 回调处理入口
public static String handleCallback(String jsonData) {
JsonObject params = JsonParser.parseString(jsonData).getAsJsonObject();
// 签名验证
if (!verifySign(params, SECRET)) {
return "sign_error";
}
// 提取字段
String transferNo = getAsString(params, "transferno");
String outTransferNo = getAsString(params, "outtransferno");
String status = getAsString(params, "status");
String tradeAmount = getAsString(params, "tradeamount");
String transferAmount = getAsString(params, "transferamount");
System.out.println("处理代付订单: " + outTransferNo);
System.out.println("平台订单号: " + transferNo);
System.out.println("订单状态: " + status);
System.out.println("扣除金额: " + tradeAmount);
System.out.println("代付金额: " + transferAmount);
return "success";
}
private static boolean verifySign(JsonObject params, String secret) {
String receivedSign = getAsString(params, "sign");
Map signMap = new HashMap<>();
for (Map.Entry entry : params.entrySet()) {
String key = entry.getKey();
if (!"sign".equals(key)) {
signMap.put(key, getAsString(params, key));
}
}
String generatedSign = generateSign(signMap, secret);
return generatedSign.equalsIgnoreCase(receivedSign);
}
private static String generateSign(Map params, String secret) {
TreeMap sortedParams = new TreeMap<>();
for (Map.Entry entry : params.entrySet()) {
String value = entry.getValue();
if (value != null && !value.trim().isEmpty()) {
sortedParams.put(entry.getKey(), value.trim());
}
}
StringBuilder paramBuilder = new StringBuilder();
for (Map.Entry entry : sortedParams.entrySet()) {
if (paramBuilder.length() > 0) paramBuilder.append("&");
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
paramBuilder.append(entry.getKey()).append("=").append(encodedValue.toLowerCase());
}
paramBuilder.append("&secret=").append(secret);
return md5(paramBuilder.toString());
}
private static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(b & 0xff);
if (hex.length() == 1) sb.append('0');
sb.append(hex);
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("MD5计算失败", e);
}
}
private static String getAsString(JsonObject obj, String key) {
return obj.has(key) && !obj.get(key).isJsonNull() ? obj.get(key).getAsString() : "";
}
// ?? 测试用 main 方法
public static void main(String[] args) {
Map mock = new HashMap<>();
mock.put("transferno", "P123456789");
mock.put("outtransferno", "T987654321");
mock.put("tradeamount", "100.000");
mock.put("transferamount", "100.000");
mock.put("endtime", "2024-01-01 12:00:00");
mock.put("remark", "测试回调");
mock.put("status", "1"); // 1=成功
// ➕ 生成签名
String sign = generateSign(mock, SECRET);
mock.put("sign", sign);
// 转为 JSON 字符串
JsonObject json = new JsonObject();
mock.forEach(json::addProperty);
String jsonStr = json.toString();
// ✅ 测试 handleCallback
String result = handleCallback(jsonStr);
System.out.println("handleCallback 返回结果: " + result);
}
}