微信公眾號支付(一)統一下單
阿新 • • 發佈:2018-11-12
最近在研究微信公眾號的支付開發,一開始對著開發文件各種懵,也自然而然地跳入了各種坑,現在把整個開發過程簡略地做個記錄。
1.開發環境準備
首先要有一個微信服務號,訂閱號是不能開通微信支付的。微信公眾號申請微信支付後,接著申請微信支付商戶平臺,公眾號上面已經標明“公眾平臺微信支付公眾號支付授權目錄、掃碼支付回撥URL配置入口已於8月1日遷移至商戶平臺(pay.weixin.qq.com)。遷移後,原有配置資料不會受影響,你可在商戶平臺檢視和配置。帶來的不便敬請諒解”。所以後續開發所需要的配置項基本都在商戶平臺中進行。
2.開發開始
首先還是得先看下微信官方提供的公眾號支付開發文件,大概對整個開發的流程有個理解。主要是看API列表
開發文件地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
/** * 統一下單 */ @XmlRootElement(name = "xml") public class UnifiedOrder { /** * 公眾賬號ID */ private後臺建立一個介面,後面H5支付的時候要呼叫,填充這個統一下單物件,appid,mchid等可以封裝成引數。微信需要接收的是xml的資料。所以我們還得把封裝好的物件轉化成xml。官網的提供的demo也有utils方法。demo在這下載。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;
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調起微信支付。