<正則吃餃子> :關於微信支付的簡單總結說明(一)

關於支付,一直想參與開發,如今根據項目中已有及參見的微信開發文檔,將本身對於微信開發的流程進行簡單的總結,以備後用和幫助後來者。php

1、相關官方文檔

微信支付官方文檔:https://pay.weixin.qq.com/wiki/doc/api/index.htmlhtml

2、參考博文

(待添加,等我找找..)前端

3、本身參看文檔時候的簡單文檔整理,

ps:只爲了方便本身記憶和聯想java

4、根據官方文檔中,標記後臺主要作的工做流程

5、參看項目代碼時候,整理的demo,來源於網絡

(1)MD5Util  ----  生成簽名時候使用git

 

package com.weixin.test;

import java.security.MessageDigest;

/**
 * 微信測試MD5
 * @author Administrator
 *
 */
public class MD5Util {

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

}
View Code

 

 

 

(2)PayTest算法

 

package com.weixin.test;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

public class PayTest {

    // http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3
    private static String Key = "192006250b4c09247ec02edce69f6a2d";

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(">>>模擬微信支付<<<");
        System.out.println("==========華麗的分隔符==========");
        // 微信api提供的參數
        String appid = "wxd930ea5d5a258f4f";
        String mch_id = "10000100";
        String device_info = "1000";
        String body = "test";
        String nonce_str = "ibuaiVcKdpRxkhJA";

        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("appid", appid);
        parameters.put("mch_id", mch_id);
        parameters.put("device_info", device_info);
        parameters.put("body", body);
        parameters.put("nonce_str", nonce_str);

        String characterEncoding = "UTF-8";
        String weixinApiSign = "9A0A8659F005D6984697E2CA0A9CF3B7";
        System.out.println("微信的簽名是:" + weixinApiSign);
        String mySign = createSign(characterEncoding, parameters);
        System.out.println("我     的簽名是:" + mySign);

        if (weixinApiSign.equals(mySign)) {
            System.out.println("恭喜你成功了~");
        } else {
            System.out.println("不行啊,再接再礪~");
        }

        String userAgent = "Mozilla/5.0(iphone;CPU iphone OS 5_1_1 like Mac OS X) AppleWebKit/534.46(KHTML,like Geocko) Mobile/9B206 MicroMessenger/5.0";

        char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger") + 15);

        System.out.println("微信的版本號:" + new String(new char[] { agent }));
    }

    /**
     * 微信支付簽名算法sign
     * @param characterEncoding
     * @param parameters
     * @return
     */
    @SuppressWarnings("unchecked")
    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();// 全部參與傳參的參數按照accsii排序(升序)
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + Key);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

}
View Code

 

 

 

6、結合項目,微信支付流程解析api

主要爲微信支付官方文檔提供的流程中,對應於 四、五、六、十、11微信

(1)網頁內請求生成支付訂單。主要工做就是前端(app)在將商品添加到購物車後下單購買或者當即購買時,在後臺系統中所生成的一個未支付訂單。網絡

下面只是項目中一個業務處理,能夠忽略,僅作參考和方便記憶。微信開發

/**
     * 生成訂單
     *
     * @param order
     * @param baseUser
     * @return
     */
    @Override
    public Response<String> createRechargeOrder(RechargeOrder order, BaseUser baseUser) {
        Response<String> response = new Response<>();

        try {
            if (baseUser == null) {
                throw new BusinessException(ResultCode.ERROR_USER_UNLOGIN.getName());
            }
            if (order == null) {
                throw new ArgumentException(ResultCode.ERROR_ORDER_SAVE_NULL.getName());
            }
            if (!checkAmount(order.getActuralAmount(), order.getRechargeAmount())) {
                throw new ArgumentException("支付金額異常");
            }

            order.setCustomerName(baseUser.getName());
            order.setCustomerId(baseUser.getId());
            if("customer".equals(baseUser.getType())){
                Response<MemberCustomerUser> res = customerService.getCustomerById(baseUser.getId());
                if (null != res && res.isSuccess()) {
                    order.setCustomerPhone(res.getResult().getMobilePhone());
                }
            }else if("shop".equals(baseUser.getType())){
                MemberShopUser user = new MemberShopUser();
                user.setId(baseUser.getId());
                Response<MemberShopUser> res = terminalShopService.getShopUserById(user);
                if (null != res && res.isSuccess()) {
                    order.setCustomerPhone(res.getResult().getMobilePhone());
                }
            }
            if (StringUtils.isBlank(order.getSource())) {
                order.setSource("");
            }
            //訂單狀態:01未支付
            order.setOrderCode("10");
            order.setOrderName("未支付");
            //付款狀態:待付款
            order.setPayStatus("0");
            rechargeOrderManager.createRechargeOrder(order);
            //記錄訂單狀態日誌
            if (order.getOrderId() != null && !"".equals(order.getOrderId())) {
                ConvenienceOrderLog orderLog = new ConvenienceOrderLog();
                orderLog.setOrderId(String.valueOf(order.getOrderId()));
                orderLog.setStatusCode(10);
                orderLog.setStatusName("未支付");
                orderLog.setStatusUserId(baseUser.id);
                orderLog.setStatusUser(baseUser.name);
                rechargeOrderManager.saveConvenienceOrderLog(orderLog);
            }
            response.setResult(String.valueOf(order.getOrderId()));
        } catch (ArgumentException a) {
            //參數異常不寫log日誌
            response.setError(a.getMessage());
        } catch (BusinessException b) {
            response.setError(b.getMessage());
            log.error("保存訂單異常!緣由:{}", Throwables.getStackTraceAsString(b));
        } catch (Exception e) {
            response.setError(e.getMessage());
            log.error("保存訂單異常!緣由:{}", Throwables.getStackTraceAsString(e));
        }
        return response;
    }
View Code

 

(2)調用統一下單api,交易請求,獲取微信後臺返回的交易支付預付單,對返回信息處理後,返回給前端(app)

/**
     * 微信支付 交易請求,生成預付單 -====== 公衆號
     *
     * @param orderId
     * @param baseUser
     * @return
     */
    @Override
    public Response<Map<String, String>> weChatPayRequest(String orderId, String openId, BaseUser baseUser) {
        Response<Map<String, String>> response = new Response<>();
        Map<String, String> map = new HashMap<>();
        try {
            if (Strings.isNullOrEmpty(orderId)) {
                throw new ArgumentException("交易編號爲空");
            }
            if (Strings.isNullOrEmpty(openId)) {
                throw new ArgumentException("openId爲空");
            }
            if (baseUser == null) {
                throw new BusinessException(ResultCode.ERROR_USER_UNLOGIN.getName());
            }
            Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
            int amount = 0;
            if (res.isSuccess() && res.getResult() != null) {
                amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
            } else {
                throw new BusinessException(res.getError());
            }
            //生成請求參數XML--公衆號
            String xml = this.createWeChatPayXml(orderId, openId, amount);
            //微信支付統一下單接口
            String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
            //發起請求
            String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
            result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
            log.error(result);
            //解析返回結果,從新處理以發給前端(app)
            Document doc = DocumentHelper.parseText(result);
            Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
            if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
                map.put("appid", (String) resultMap.get("appid"));
                map.put("mch_id", (String) resultMap.get("mch_id"));
                map.put("prepay_id", (String) resultMap.get("prepay_id"));
                map.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                Long l = new Date().getTime() / 1000;
                Integer timestamp = Integer.parseInt(l.toString());
                map.put("timestamp", timestamp.toString());
                map.put("nonceStr", "aaronlovem" + timestamp.toString());
                // createPaySignStr()  ---- 生成支付簽名-公衆號,注意 :須要跟發起支付時候的,生成簽名的參數規則一致。總之,須要跟前端提交時候,微信生成的簽名一致。
                String paySign = createPaySignStr(map.get("nonceStr").toString(), map.get("package"), map.get("timestamp"));
                map.put("paySign", paySign);
                map.put("openId", openId);
                response.setResult(map);
            } else {
                response.setSuccess(false);
                response.setError((String) resultMap.get("return_msg"));
            }
        } catch (ArgumentException a) {
            response.setError(a.getMessage());
        } catch (BusinessException b) {
            response.setError(b.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(b));
        } catch (RuntimeException c) {
            response.setError(c.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(c));
        } catch (Exception e) {
            response.setError("微信支付異常!" + Throwables.getStackTraceAsString(e));
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(e));
        }
        //返回給前端,微信支付訂單信息
        return response;
    }
View Code

 

一個生成簽名的方式,還有其餘方式,僅作記錄,以下:

 

/**
     * 生成支付簽名-公衆號
     *
     * @return
     */
    public String createPaySignStr(String nonceStr, String packageStr, String timestamp) throws Exception {
        String[] arr = new String[5];
        arr[0] = "appId=suwxb1d7b09dsaf81c92eb";
        arr[1] = "nonceStr=" + nonceStr;
        arr[2] = "package=" + packageStr;
        arr[3] = "signType=MD5";
        arr[4] = "timeStamp=" + timestamp;
        Arrays.sort(arr);
        String param = "";
        for (int i = 0; i < arr.length; i++) {
            param += arr[i] + "&";
        }
        param += "key=我是key呵呵呵呵呵";
        log.error("微信支付請求參數:" + param);
        return MD5Util.MD5Encode(param, null).toUpperCase();
    }

    /**
     * 生成支付簽名-B端、C端
     *
     * @param noncestr
     * @param packagestr
     * @param prepayid
     * @param timestamp
     * @return
     */
    public String createWeChatGoPayXmlForAPP(String noncestr, String packagestr, String prepayid, String timestamp, String type) {
        String appId = "";
        String partnerId = "";
        String key = "";
        if ("B2C".equals(type)) {
            appId = "suwxb1d7bf09af81c92eb";
            partnerId = "1322218523201";
            key = "我是key";
        } else if ("B2B".equals(type)) {
            appId = "suwxb1d7b09af81c92eb";
            partnerId = "1352713d383902";
            key = "我是key啊";
        }
        String[] arr = new String[6];
        arr[0] = "appid=" + appId;
        arr[1] = "noncestr=" + noncestr;
        arr[2] = "package=" + packagestr;
        arr[3] = "partnerid=" + partnerId;
        arr[4] = "prepayid=" + prepayid;
        arr[5] = "timestamp=" + timestamp;
        Arrays.sort(arr);
        String param = "";
        for (int i = 0; i < arr.length; i++) {
            param += arr[i] + "&";
        }
        param += "key=" + key;
        log.error("微信支付請求參數:" + param);
        return MD5Util.MD5Encode(param, null).toUpperCase();
    }
View Code

 

 

 

b、c的交易請求,app支付:大致與公衆號支付相似,參數不一致

/**
     * 微信支付 交易請求,生成預付單,C端
     *
     * @param orderId
     * @param baseUser
     * @return
     */
    @Override
    public Response<Map<String, String>> weChatPayRequestForC(String orderId, BaseUser baseUser) {
        Response<Map<String, String>> response = new Response<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        try {
            if (Strings.isNullOrEmpty(orderId)) {
                throw new ArgumentException("交易編號爲空");
            }
            Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
            int amount = 0;
            if (res.isSuccess() && res.getResult() != null) {
                amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
            } else {
                throw new BusinessException(res.getError());
            }
            String xml = this.createWeChatPayXmlForAPP(orderId, amount, "B2C");
            String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
            String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
            result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
            log.error(result);
            Document doc = DocumentHelper.parseText(result);
            Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
            if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
                Map<String, String> param = new HashMap<String, String>();
                param.put("appid", (String) resultMap.get("appid"));
                param.put("partnerid", (String) resultMap.get("mch_id"));
                param.put("prepayid", (String) resultMap.get("prepay_id"));
                param.put("package", "Sign=WXPay");
                Long l = new Date().getTime() / 1000;
                Integer timestamp = Integer.parseInt(l.toString());
                param.put("noncestr", "xxxxxB2Capp" + timestamp.toString());
                param.put("timestamp", timestamp.toString());
                param.put("sign", this.createWeChatGoPayXmlForAPP(param.get("noncestr").toString(), param.get("package").toString(), param.get("prepayid").toString(), param.get("timestamp").toString(), "B2C"));
                response.setResult(param);
            } else {
                response.setSuccess(false);
                response.setError((String) resultMap.get("return_msg"));
            }
        } catch (ArgumentException a) {
            response.setError(a.getMessage());
        } catch (BusinessException b) {
            response.setError(b.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(b));
        } catch (RuntimeException c) {
            response.setError(c.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(c));
        } catch (Exception e) {
            response.setError("微信支付異常!" + Throwables.getStackTraceAsString(e));
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(e));
        }
        return response;
    }

    @Override
    public Response<Map<String, String>> weChatPayRequestForB(String orderId, BaseUser baseUser) {
        Response<Map<String, String>> response = new Response<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        try {
            if (Strings.isNullOrEmpty(orderId)) {
                throw new ArgumentException("交易編號爲空");
            }
            Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
            int amount = 0;
            if (res.isSuccess() && res.getResult() != null) {
                amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
            } else {
                throw new BusinessException(res.getError());
            }
            String xml = this.createWeChatPayXmlForAPP(orderId, amount, "B2B");
            String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
            String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
            result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
            log.error(result);
            Document doc = DocumentHelper.parseText(result);
            Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
            if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
                Map<String, String> param = new HashMap<String, String>();
                param.put("appid", (String) resultMap.get("appid"));
                param.put("partnerid", (String) resultMap.get("mch_id"));
                param.put("prepayid", (String) resultMap.get("prepay_id"));
                param.put("package", "Sign=WXPay");
                Long l = new Date().getTime() / 1000;
                Integer timestamp = Integer.parseInt(l.toString());
                param.put("noncestr", "xxxxB2Bapp" + timestamp.toString());
                param.put("timestamp", timestamp.toString());
                param.put("sign", this.createWeChatGoPayXmlForAPP(param.get("noncestr").toString(), param.get("package").toString(), param.get("prepayid").toString(), param.get("timestamp").toString(), "B2B"));
                response.setResult(param);
            } else {
                response.setSuccess(false);
                response.setError((String) resultMap.get("return_msg"));
            }
        } catch (ArgumentException a) {
            response.setError(a.getMessage());
        } catch (BusinessException b) {
            response.setError(b.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(b));
        } catch (RuntimeException c) {
            response.setError(c.getMessage());
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(c));
        } catch (Exception e) {
            response.setError("微信支付異常!" + Throwables.getStackTraceAsString(e));
            log.error("weChatPayRequest 異常!緣由:{}", Throwables.getStackTraceAsString(e));
        }
        return response;
    }
View Code

 

(3)告知微信處理通知支付結果。此爲,咱們在後臺發起微信支付請求生成預訂單時候,傳入的回調函數的方法。微信後臺在處理完微信支付結果後,會發起請求,調用咱們已經準備好的回調函數地址。

回調函數中,能夠具體處理下咱們商戶系統中的一些業務,好比更新訂單狀態,提醒消息等等.....處理完成,返回微信後臺處理結果。

對應於微信支付下單api接口參數中的,以下:

 

 

 /**
     * 微信支付回調函數
     *
     * @param weChatPayReturn
     * @return
     */
    @Override
    public String getWeChatPayReturnForOrder(WeChatPayReturn weChatPayReturn) {
        log.error("微信普通訂單回調,參數爲:" + weChatPayReturn.toString());
        System.out.println("微信普通訂單回調,參數爲:" + weChatPayReturn.toString());
        boolean flag = false;
        try {
            if (null != weChatPayReturn) {
                //保存微信回調信息
                rechargeOrderManager.saveRechargeOrderWeChatPayInfo(weChatPayReturn);
                if (true) {
                    //判斷該筆訂單是否在商戶網站中已經作過處理
                    //若是沒有作過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
                    //若是有作過處理,不執行商戶的業務程序
                    flag = rechargeOrderManager.getWeChatPayReturnForOrder(weChatPayReturn);
                    if (flag) {
                        String successStr = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                        return successStr;
                    } else {
                        return "fail";
                    }
                }
            } else {
                throw new ArgumentException("微信回調對象爲空!");
            }
        } catch (ArgumentException a) {
            //參數異常不寫log日誌
            log.error("微信回調對象異常!緣由:{}", Throwables.getStackTraceAsString(a));
        } catch (BusinessException b) {
            log.error("微信回調對象異常!緣由:{}", Throwables.getStackTraceAsString(b));
        } catch (Exception e) {
            log.error("微信回調對象異常!緣由:{}", Throwables.getStackTraceAsString(e));
        }
        return "fail";
    }
View Code

 

注意:文章中所列出的代碼不必定是最好的,只提供流程思路,方便理解和記憶。具體的實現方式,本身把握。好比,在生成支付簽名時候,有多種方式來實現。

相關文章
相關標籤/搜索