1. 程式人生 > >微信公眾號支付(一)統一下單

微信公眾號支付(一)統一下單

最近在研究微信公眾號的支付開發,一開始對著開發文件各種懵,也自然而然地跳入了各種坑,現在把整個開發過程簡略地做個記錄。

1.開發環境準備

首先要有一個微信服務號,訂閱號是不能開通微信支付的。微信公眾號申請微信支付後,接著申請微信支付商戶平臺,公眾號上面已經標明“公眾平臺微信支付公眾號支付授權目錄、掃碼支付回撥URL配置入口已於8月1日遷移至商戶平臺(pay.weixin.qq.com)。遷移後,原有配置資料不會受影響,你可在商戶平臺檢視和配置。帶來的不便敬請諒解”。所以後續開發所需要的配置項基本都在商戶平臺中進行。


2.開發開始

首先還是得先看下微信官方提供的公眾號支付開發文件,大概對整個開發的流程有個理解。主要是看API列表

開發文件地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1


首先看到的就是統一下單,沒錯,支付開發的第一步就是實現統一下單。 2.1 構造統一下單物件 首先,構造一個統一下單物件,物件的欄位包括裡面的必填欄位,有額外需要的可以自己新增。特別注意裡面對請求引數的描述。
/**
 * 統一下單
 */
@XmlRootElement(name = "xml")
public class UnifiedOrder {

    /**
     * 公眾賬號ID
     */
    private 
String appid; /** * 商戶號 */ private String mch_id; /** * 附加資料(說明) */ private String attach; /** * 商品描述 */ private String body; /** * 隨機串 */ private String nonce_str; /** * 通知地址 */ private String notify_url; /** * 使用者標識
*/ private String openid; /** * 商戶訂單號 */ private String out_trade_no; /** * 終端IP(使用者) */ private String spbill_create_ip; /** * 總金額 */ private Integer total_fee; /** * 交易型別 */ private String trade_type; /** * 簽名 */ private String sign; /** * 簽名方式 */ private String signType; /** * WEB */ private String device_info; /** * 統一下單介面 */ private String prepay_id; /** * 時間戳 * @return */ private String timeStamp;
後臺建立一個介面,後面H5支付的時候要呼叫,填充這個統一下單物件,appid,mchid等可以封裝成引數。微信需要接收的是xml的資料。所以我們還得把封裝好的物件轉化成xml。官網的提供的demo也有utils方法。demo在這下載。
2.2 獲取openid,對於微信公眾號支付,統一下單時openid是必須的。因此在統一下單之前還得獲取openid。首先要到公眾號後臺進行授權配置。官網說明:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 通過 公眾號可以通過微信網頁授權機制,來獲取使用者基本資訊,一般只要scope為snsapi_userinfo,也是靜默授權即可。
如果使用的是預設授權,那麼就不會出現使用者確認的提示。如圖所示
獲取openid,一般是通過js調起微信授權。所以可在調起支付的頁面進行js授權,url配置公眾號的appid,後臺回撥地址,授權成功後,微信會呼叫這個介面,並給我們返回使用者的資訊。
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=公眾號的appida&redirect_uri=回撥介面(瀏覽器能訪問的介面)&response_type=code&scope=snsapi_base&state=ssssqqqq#wechat_redirect";
介面呼叫成功後,微信呼叫後臺介面,在這我們要根據微信返回的code來獲取使用者資訊,並將其進行轉換,然後放到session中,確保獲取的是當前登入使用者的資訊。以下為上面所寫的回撥介面。url配置appid,secret為公眾號祕鑰即AppSecret,可在公眾號後臺的基本配置中進行檢視。code為微信授權返回的code。
/**
 * 獲取openid
 *
 * @return
 */
@RequestMapping("auth")
public String auth(String code, String state, HttpServletRequest request) {
    HttpSession session = request.getSession();
    String format = MessageFormat.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", Constant.APPID, Constant.SECRET, code);
    String s = HttpUtils.get(format);
    Map map = JSON.parseObject(s, Map.class);
    //String userInfo = MessageFormat.format(url_user, Constant.APPID, Constant.SECRET, code);
    SecurityUser currentUser = SecurityUserUtils.getCurrentUser(request);
    if (currentUser != null) {
        session.setAttribute("openid", map.get("openid"));
    }
    return "redirect:http://www.XXX.com/index.html";
}
到這裡,openid就已經獲取到了。然後統一下單物件setOpenid(session.getAttribute("openid")。構造一個完整的統一下單物件。
//構建統一下單物件
UnifiedOrder unifiedOrder = new UnifiedOrder();
unifiedOrder.setAppid(Constant.APPID);
unifiedOrder.setDevice_info(Constant.DEVICE_INFO);
unifiedOrder.setMch_id(Constant.MCHID);
unifiedOrder.setNonce_str(Constant.NONCE_STR);
unifiedOrder.setBody("充值" + uiorder.getTotalFee() + "元");
unifiedOrder.setAttach("自動充值");
unifiedOrder.setSpbill_create_ip(request.getRemoteAddr());
unifiedOrder.setNotify_url(Constant.NOTIFY_URL);
unifiedOrder.setTrade_type(Constant.TRADE_TYPE);
unifiedOrder.setOpenid((String) request.getSession().getAttribute("openid"));
BigDecimal totalFee = uiorder.getTotalFee();
unifiedOrder.setTotal_fee(totalFee.multiply(new BigDecimal(100)).intValue());
unifiedOrder.setOut_trade_no(SequenceUtils.generateOrderNo(date));
2.3 第一次簽名 統一下單之前還得對統一下單物件設定簽名,根據官方文件的說明進行簽名生成。key在商戶平臺的api祕鑰中進行設定
以下提供簽名生成的方法。MD5加密等方法都可以在官網的sdk例子中找得到。
簽名生成完成,這時候我們把統一下單物件打包成xml。傳送給微信的介面
https://api.mch.weixin.qq.com/pay/unifiedorder
SignUtils.sign(unifiedOrder);
String s = XmlParserUtil.object2Xml(unifiedOrder);
//統一下單
String s1 = HttpUtils.postXML("https://api.mch.weixin.qq.com/pay/unifiedorder", s);
UnifiedOrder order = XmlParserUtil.xml2Object(s1, UnifiedOrder.class);
HttpUtils的postXML方法如下
public static String postXML(String url, String xml) {
    RequestBody body = RequestBody.create(XML, xml);
    Request request = new Request.Builder()
            .post(body)
            .url(url)
            .addHeader("Accept", "application/xml")
            .build();
    Call call = httpClient.newCall(request);
    try {
        Response response1 = call.execute();
        return response1.body().string();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
到了這裡,統一下單就完成了。此時微信給我們返回的order物件就包括一個很重要的欄位
prepay_id
這個物件用來做後面的H5支付調起是非常重要的。下一章節我們將介紹如何進行H5調起微信支付。