MaxPay 支付接口文档

本文档提供了MaxPay支付平台所有接口的详细说明和使用方法,包括代收、代付、订单查询及回调处理等核心功能。

5. 代收订单回调

POST
application/json

注意: 商户接收到系统的异步回调请求后,如成功处理订单,请在接口响应纯文本字符串 'success'。

回调参数

参数名 类型 描述
tradeno string 订单号
outtradeno string 商户订单号
amount number 订单金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000)
ramount number 实际收款金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000)
oamount number 原始下单金额(回调时默认会保留3位小数,加签时请将小数位一起加入,例如:100.000)
endtime string 支付时间
status string 订单状态:1已支付(支付成功时才会触发回调通知)
remark string 备注
sign string 签名

Java 示例

Java 示例代码
import com.google.gson.*;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class CollectionExample   {
    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 outTradeNo = getAsString(params, "outtradeno");
        String tradeNo = getAsString(params, "tradeno");
        String status = getAsString(params, "status");
        String amount = getAsString(params, "amount");
        String ramount = getAsString(params, "ramount");

        System.out.println("处理代收订单: " + outTradeNo);
        System.out.println("平台订单号: " + tradeNo);
        System.out.println("订单状态: " + status);
        System.out.println("金额: " + amount + ", 实收: " + ramount);

        return "success";
    }

    private static boolean verifySign(JsonObject params, String secret) {
        String receivedSign = params.get("sign").getAsString();
        Map signMap = new HashMap<>();

        for (Map.Entry entry : params.entrySet()) {
            String key = entry.getKey();
            if (!"sign".equals(key) && !entry.getValue().isJsonNull()) {
                signMap.put(key, entry.getValue().getAsString());
            }
        }

        String generatedSign = generateSign(signMap, secret);
        return generatedSign.equalsIgnoreCase(receivedSign);
    }

    private static String generateSign(Map params, String secret) {
        Map sorted = new TreeMap<>();
        for (Map.Entry entry : params.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().trim().isEmpty()) {
                sorted.put(entry.getKey(), entry.getValue().trim());
            }
        }

        StringBuilder sb = new StringBuilder();
        for (Map.Entry entry : sorted.entrySet()) {
            if (sb.length() > 0) sb.append("&");
            sb.append(entry.getKey()).append("=")
                .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8).toLowerCase());
        }
        sb.append("&secret=").append(secret);

        return md5(sb.toString());
    }

    private static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder hex = new StringBuilder();
            for (byte b : hash) {
                String h = Integer.toHexString(0xff & b);
                if (h.length() == 1) hex.append("0");
                hex.append(h);
            }
            return hex.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() : "";
    }

    // ✅ 测试方法
    public static void main(String[] args) {
        Map mock = new HashMap<>();
        mock.put("tradeno", "TRADE123456");
        mock.put("outtradeno", "ORDER123456");
        mock.put("amount", "100.000");
        mock.put("ramount", "99.000");
        mock.put("oamount", "100.000");
        mock.put("endtime", "2024-07-21 12:30:00");
        mock.put("status", "1");
        mock.put("remark", "测试回调");

        // ➕ 生成签名
        String sign = generateSign(mock, SECRET);
        mock.put("sign", sign);

        // 构建 JSON
        JsonObject json = new JsonObject();
        for (Map.Entry entry : mock.entrySet()) {
            json.addProperty(entry.getKey(), entry.getValue());
        }

        String jsonStr = json.toString();

        // 测试回调
        String result = handleCallback(jsonStr);
        System.out.println("回调处理结果: " + result);
    }
}