MaxPay 支付接口文档
本文档提供了MaxPay支付平台所有接口的详细说明和使用方法,包括代收、代付、订单查询及回调处理等核心功能。
6. 代付订单回调
POST
application/json
注意: 商户接收到系统的异步回调请求后,如成功处理订单,请在接口响应纯文本字符串 'success'。
回调参数
参数名 | 类型 | 描述 |
---|---|---|
transferno |
string | 订单号 |
outtransferno |
string | 商户订单号 |
tradeamount |
number | 商户账户扣除金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000) |
transferamount |
number | 代付金额(回调时默认会保留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"); MapsignMap = 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); } }