1. 程式人生 > >支付寶退款java實現

支付寶退款java實現

line params _id roc 開頭 result gets .html ice

//config
public class AlipayRefundConfig {

    private final String charset    = "UTF-8";                              //參數編碼字符集
    private final String signType   = "MD5";                                //簽名方式
    private String       service    = "refund_fastpay_by_platform_nopwd";   //接口名稱
    private String       gatewayUrl = "https://mapi.alipay.com/gateway.do"; //支付寶網關
    private String       partner;                                           //合作者身份ID
    private String       notifyUrl;                                         //服務器異步通知頁面路徑
    private String       sellerId;                                          //收款支付寶賬號,以2088開頭由16位純數字組成的字符串,一般情況下收款賬號就是簽約賬號
    private String       signKey;                                           // MD5密鑰,安全檢驗碼,由數字和字母組成的32位字符串,查看地址

    public void setService(String service) {
        this.service = service;
    }

    public String getService() {
        return service;
    }

    public String getCharset() {
        return charset;
    }

    public String getSignType() {
        return signType;
    }

    public String getGatewayUrl() {
        return gatewayUrl;
    }

    public void setGatewayUrl(String gatewayUrl) {
        this.gatewayUrl = gatewayUrl;
    }

    public String getPartner() {
        return partner;
    }

    public void setPartner(String partner) {
        this.partner = partner;
    }

    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }

    public String getSellerId() {
        return sellerId;
    }

    public void setSellerId(String sellerId) {
        this.sellerId = sellerId;
    }

    public String getSignKey() {
        return signKey;
    }

    public void setSignKey(String signKey) {
        this.signKey = signKey;
    }
}

//??????
public class AlipayRefundRequest {

    private String     refundDate; // 退款請求時間 yyyy-MM-dd HH:mm:ss
    private String     batchNo;    // 退款批次號,退款日期(8位)+流水號(3~24位)
    private String     tradeNo;    // 原付款支付寶交易號
    private BigDecimal amount;     // 退款總金額
    private String     reason;     // 退款理由
    private String     notifyUrl;  //服務器異步通知頁面路徑,優先使用

    public String getRefundDate() {
        return refundDate;
    }

    public void setRefundDate(String refundDate) {
        this.refundDate = refundDate;
    }

    public String getBatchNo() {
        return batchNo;
    }

    public void setBatchNo(String batchNo) {
        this.batchNo = batchNo;
    }

    public String getTradeNo() {
        return tradeNo;
    }

    public void setTradeNo(String tradeNo) {
        this.tradeNo = tradeNo;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }
}

//??????
public class AlipayRefundHelper {

    public static String createGateway(AlipayRefundConfig config, AlipayRefundRequest request) {

        TreeMap<String, String> parameter = new TreeMap<>();

        parameter.put("_input_charset", config.getCharset());
        parameter.put("notify_url", request.getNotifyUrl() == null ? config.getNotifyUrl() : request.getNotifyUrl());
        parameter.put("partner", config.getPartner());
        parameter.put("seller_id", config.getSellerId());
        parameter.put("service", config.getService());
        parameter.put("sign_type", config.getSignType());

        parameter.put("batch_no", request.getBatchNo());
        parameter.put("refund_date", request.getRefundDate());
        parameter.put("batch_num", "1");
        StringBuilder sb = new StringBuilder(80);
        sb.append(request.getTradeNo()).append("^");
        sb.append(request.getAmount()).append("^");
        sb.append(request.getReason());
        parameter.put("detail_data", sb.toString());

        String queryString = AlipayUtil.buildQueryString(parameter, config.getSignKey());

        return config.getGatewayUrl() + queryString;
    }

    public static AlipayRefundReturn parseReturn(String xml) {
        AlipayRefundReturn r = new AlipayRefundReturn();
        r.setIsSuccess(extractXml(xml, "is_success"));
        r.setError(extractXml(xml, "error"));
        return r;
    }

    private static String extractXml(String xml, String tag) {
        int p = xml.indexOf(tag);
        if (p < 0) return null;
        int p1 = -1;
        int p2 = -1;
        for (int i = p + tag.length(); i < xml.length(); i++) {
            char c = xml.charAt(i);
            if (c == ‘ ‘ || c == ‘\t‘) continue;
            if (c != ‘>‘) return null;
            p1 = i + 1;
            p2 = xml.indexOf(‘<‘, p1);
            break;
        }
        if (p1 < 0 || p2 < 0 || p2 < p1) return null;
        return xml.substring(p1, p2);
    }
}


/**
 */
public class AlipayUtil {

    public static boolean isSuccess(String str) {
        return str != null && "T".equalsIgnoreCase(str.trim());
    }

    public static boolean isFailed(String str) {
        return str != null && "F".equalsIgnoreCase(str.trim());
    }

    public static boolean isProcess(String str) {
        return str != null && "P".equalsIgnoreCase(str.trim());
    }

    public static boolean signSkip(String k, String v) {
        return v == null || v.length() == 0 || k == null || "sign_type".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k);
    }

    public static String buildQueryString(TreeMap<String, String> parameter, String signKey) {
        StringBuilder sign = new StringBuilder();
        StringBuilder query = new StringBuilder();
        for (Map.Entry<String, String> entry : parameter.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            if (!AlipayUtil.signSkip(k, v)) {
                sign.append("&").append(k).append("=").append(v);
                try {
                    v = URLEncoder.encode(v, "UTF8");
                } catch (Exception e) {
                    // ignore
                }
                query.append("&").append(k).append("=").append(v);
            }
        }

        sign.append(signKey);
        String digest = Md5Util.sumUtf8(sign.substring(1));

        query.append("&sign=").append(digest);
        query.setCharAt(0, ‘?‘);

        return query.toString();
    }

    /**
     * @return 
     */

    public enum VerifyResult {
        UNSUPPORTED,
        NOT_PASS,
        MD5_PASS,
        ALL_PASS
    };

    public static VerifyResult verifyNotifyMd5(TreeMap<String, String> params, String signKey, String partnerId) {
        if (params == null || params.isEmpty()) return VerifyResult.UNSUPPORTED;
        if (!"md5".equalsIgnoreCase(params.get("sign_type"))) return VerifyResult.UNSUPPORTED;

        StringBuilder sign = new StringBuilder(300);
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String k = entry.getKey();
            if ("sign".equalsIgnoreCase(k) || "sign_type".equalsIgnoreCase(k)) {
                continue;
            }
            sign.append("&").append(k).append("=").append(entry.getValue());
        }
        sign.append(signKey);
        String signStr = sign.substring(1);
        String signMd5 = Md5Util.sumUtf8(signStr);
        String paraMd5 = params.get("sign");
        if (!signMd5.equalsIgnoreCase(paraMd5)) {
            return VerifyResult.NOT_PASS;
        }

        // chick notify_id
        String verifyUrl = "https://mapi.alipay.com/gateway.do?service=notify_verify&partner=";
        StringBuilder queryUrl = new StringBuilder(100);
        queryUrl.append(verifyUrl);
        queryUrl.append(partnerId);
        queryUrl.append("&notify_id=");
        queryUrl.append(params.get("notify_id"));

        BufferedReader in = null;
        try {
            URL url = new URL(queryUrl.toString());
            URLConnection urlConnection = url.openConnection();
            in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String inputLine = in.readLine();
            if (inputLine.equalsIgnoreCase("true")) {
                return VerifyResult.ALL_PASS;
            } else {
                return VerifyResult.MD5_PASS;
            }
        } catch (Exception e) {
            return VerifyResult.MD5_PASS;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }
}

/**
* 生成支付寶批次號
*
* @return
*/
public String getRandomBatchNum() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String format = dateFormat.format(new Date());
int max = 24;
int min = 3;
Random random = new Random();
int s = random.nextInt(max) % (max - min + 1) + min;
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < s; i++) {
Integer val = (int) (Math.random() * 9 + 1);
buffer.append(val.toString());
}
return format + buffer.toString();
}


//測試 public static void main(String[] args) { AlipayRefundConfig config = new AlipayRefundConfig(); config.setNotifyUrl("http://127.0.0.1:9966/alipay.html"); config.setPartner(PayConstants.PARTNER_ID); config.setSellerId(PayConstants.PARTNER_ID); config.setSignKey(PayConstants.SECURITY_KEY); AlipayRefundRequest req = new AlipayRefundRequest(); req.setBatchNo(getRandomBatchNum()); //退款流水號 SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); req.setRefundDate(dt.format(new Date())); //退款請求時間 req.setAmount(new BigDecimal("0.01")); req.setReason("測試"); req.setTradeNo("888888888"); //交易號 String payUrl = AlipayRefundHelper.createGateway(config, req); System.out.println(payUrl); String xml = PayUtil.request(payUrl); AlipayRefundReturn r = AlipayRefundHelper.parseReturn(xml); System.out.println(xml); System.out.println(r.getIsSuccess()); System.out.println(r.getError()); }

  

支付寶退款java實現