微信退款-SDK

微信退款這個功能仍是挺複雜的,建議去看一下官方文檔,理解了以後再寫功能,官方文檔:微信支付官方文檔php

首先去微信支付官網去下載各個版本的demo支付工具,我用的Java版本,地址:微信支付官方-SDK算法

下載完以後大概是這樣api

下面把我本身實現的這兩類貼出來,直接就能用微信

MyWXPayDomainImpl app

/**
 * @ClassName : MyWXPayDomainImpl
 * @Author : Yanqiang
 * @Date : 2019/4/1
 * @Description :本身實現微信的abstract interface WXPayDomain接口,實現請求配置
 */
public class MyWXPayDomainImpl implements WXPayDomain {
    private MyWXPayDomainImpl(){}
    private static class WxpayDomainHolder{
        private static WXPayDomain holder = new MyWXPayDomainImpl();
    }
    public static WXPayDomain instance(){
        return WxpayDomainHolder.holder;
    }

    public synchronized void report(final String domain, long elapsedTimeMillis, final Exception ex) {
        DomainStatics info = domainData.get(domain);
        if(info == null){
            info = new DomainStatics(domain);
            domainData.put(domain, info);
        }

        if(ex == null){ //success
            if(info.succCount >= 2){    //continue succ, clear error count
                info.connectTimeoutCount = info.dnsErrorCount = info.otherErrorCount = 0;
            }else{
                ++info.succCount;
            }
        }else if(ex instanceof ConnectTimeoutException){
            info.succCount = info.dnsErrorCount = 0;
            ++info.connectTimeoutCount;
        }else if(ex instanceof UnknownHostException){
            info.succCount = 0;
            ++info.dnsErrorCount;
        }else{
            info.succCount = 0;
            ++info.otherErrorCount;
        }
    }

    public synchronized DomainInfo getDomain(final WXPayConfig config) {
        DomainStatics primaryDomain = domainData.get(WXPayConstants.DOMAIN_API);
        if(primaryDomain == null ||
                primaryDomain.isGood()) {
            return new DomainInfo(WXPayConstants.DOMAIN_API, true);
        }

        long now = System.currentTimeMillis();
        if(switchToAlternateDomainTime == 0){   //first switch
            switchToAlternateDomainTime = now;
            return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
        }else if(now - switchToAlternateDomainTime < MIN_SWITCH_PRIMARY_MSEC){
            DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
            if(alternateDomain == null ||
                    alternateDomain.isGood() ||
                    alternateDomain.badCount() < primaryDomain.badCount()){
                return new DomainInfo(WXPayConstants.DOMAIN_API2, false);
            }else{
                return new DomainInfo(WXPayConstants.DOMAIN_API, true);
            }
        }else{  //force switch back
            switchToAlternateDomainTime = 0;
            primaryDomain.resetCount();
            DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);
            if(alternateDomain != null)
                alternateDomain.resetCount();
            return new DomainInfo(WXPayConstants.DOMAIN_API, true);
        }
    }

    static class DomainStatics {
        final String domain;
        int succCount = 0;
        int connectTimeoutCount = 0;
        int dnsErrorCount =0;
        int otherErrorCount = 0;

        DomainStatics(String domain) {
            this.domain = domain;
        }
        void resetCount(){
            succCount = connectTimeoutCount = dnsErrorCount = otherErrorCount = 0;
        }
        boolean isGood(){ return connectTimeoutCount <= 2 && dnsErrorCount <= 2; }
        int badCount(){
            return connectTimeoutCount + dnsErrorCount * 5 + otherErrorCount / 4;
        }
    }
    private final int MIN_SWITCH_PRIMARY_MSEC = 3 * 60 * 1000;  //3 minutes
    private long switchToAlternateDomainTime = 0;
    private Map<String, DomainStatics> domainData = new HashMap<String, DomainStatics>();
}

 

/**
 * @ClassName : MyWXPayConfig
 * @Author : Yanqiang
 * @Date : 2019/4/1
 * @Description :微信支付/退款配置類 繼承abstract WXPayConfig ,本身實現微信配置
 */
public class MyWXPayConfig extends WXPayConfig {

    private byte[] certData;

    private static MyWXPayConfig INSTANCE;

    private int profiles;//0是測試;1是正式

    public MyWXPayConfig(int profiles) throws Exception {
        this.profiles = profiles;
        String path;
        //不是沙箱環境要要下載證書,開出來
        //0是測試;1是正式
        if (profiles == 0){
            path = "這個是證書地址,以.p12結尾的那個文件";
        }else {
            path = "這個是證書地址,以.p12結尾的那個文件";
        }
        File file = new ClassPathResource(path).getFile();
        InputStream certStream = new FileInputStream(file);

        this.certData = new byte[(int) file.length()];

        certStream.read(this.certData);

        certStream.close();

    }

    @Override
    String getAppID() {
        return "這裏是Appid";
    }

    @Override
    String getMchID() {
        //0是測試;1是正式
        if (profiles == 0){
            return "這個是Mch的碼";
        }else {
            return "這個是Mch的碼";
        }
    }

    @Override
    String getKey() {
        return "這個是項目私鑰,不要泄露";
    }

    @Override
    InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    WXPayDomain getWXPayDomain() {
        return MyWXPayDomainImpl.instance();
    }
}

支付之類的最大的坑就是沙箱環境,那麼什麼是沙箱環境,其實就是在你去請求正式環境的時候,去(轉換/加密....)一下,讓服務商知道你這個請求是測試環境過來的請求dom

其次,微信退款須要的參數格式爲XML格式,若是用微信支付官網下載的demo的話不須要本身轉xmlide

/**
 * @Author : Yanqiang
 * @Date : 2019/4/9
 * @Description :
 *
 *      其實,真正須要本身去寫的代碼只有這幾行,
 *      可是,是什麼讓咱們寫這一塊的時候這麼費勁的,仍是你要去看懂官方文檔,
 *      說道這兒,不得不說,微信支付的接口文檔寫的真夠爛的,看一遍以爲很好理解,
 *      寫的時候發現處處都是坑,再去看文檔也沒有寫清楚,就讓人二丈和尚摸不着頭髮
 *
 *   PS: 下面是真坑了!
 *
 *      1·參數必須按照文檔上的,如出一轍,不能大小寫,也不能駝峯
 *      2·必須按照文檔上的參數順序一致!!! 除去忽略的參數,必傳參數順序依次往前排列
 *      3·若是你用微信官方SDK的話,sign:簽名 這個參數能夠不傳,這個是工具類幫你作了,本身寫的話要寫!
 *      4·sign 的生成是將 除sign以外的參數,其餘不爲空的參數參與簽名。詳細介紹:簽名生成算法
 */
//構造請求參數 不須要此時設置sign簽名,wxPay.refund()接口 經過配置類自動配置
ConcurrentHashMap<String, String> requestMap = new ConcurrentHashMap();
requestMap.put("appid", shopsApiProperties.mpWeixinAppid);
requestMap.put("mch_id", mch_id);
requestMap.put("nonce_str", WXPayUtil.generateNonceStr());
requestMap.put("out_refund_no", afterSale.getSaleordernum());
requestMap.put("out_trade_no", afterSale.getOuttradeno());
requestMap.put("refund_fee", String.valueOf(refundFee * 100));
requestMap.put("total_fee", String.valueOf(actualPrice));

//MyWXPayConfig: 配置類 0是測試;1是正式; 
// "": 回調通知地址;
//autoReport: 這個沒有用到
//useSandbox: 沙箱環境 (false爲正式/true爲沙箱環境)
WXPay wxPay = new WXPay(new MyWXPayConfig(0), "", true, false);

Map<String, String> refund = wxPay.refund(requestMap, 6*1000,8*1000);
相關文章
相關標籤/搜索