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");

        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);
    }
}