微信支付---統一下單php
身爲一個碼農,老是須要要學習一些新的知識來豐富本身的羽翼,讓本身可以在程序員的道路上走的更遠,更穩。html
最近在研究關於微信支付的接口調用:微信支付開發文檔java
接口鏈接:URL地址:https://api.mch.weixin.qq.com/pay/unifiedordernode
請求參數、返回字段、錯誤碼、請閱讀:統一下單開發文檔程序員
請求參數格式和信息例:web
<xml> <return_code><![CDATA[SUCCESS]]></return_code>//返回狀態碼 <return_msg><![CDATA[OK]]></return_msg>//返回信息 <appid><![CDATA[wx2421b1c4370ec43b]]></appid>//公衆帳號ID <mch_id><![CDATA[10000100]]></mch_id>//商戶號 <device_info><![CDATA[1000]]></device_info>//設備號 <nonce_str><![CDATA[TN55wO9Pba5yENl8]]></nonce_str>//隨機字符串 <sign><![CDATA[BDF0099C15FF7BC6B1585FBB110AB635]]></sign>//簽名 <result_code><![CDATA[SUCCESS]]></result_code>//業務結果 <openid><![CDATA[oUpF8uN95-Ptaags6E_roPHg7AG0]]></openid>//用戶標識 <is_subscribe><![CDATA[Y]]></is_subscribe>//是否關注公衆帳號 <trade_type><![CDATA[MICROPAY]]></trade_type>//交易類型 <bank_type><![CDATA[CCB_DEBIT]]></bank_type>//付款銀行 <total_fee>1</total_fee>//訂單金額——單位分 <fee_type><![CDATA[CNY]]></fee_type>//貨幣種類 <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>//微信支付訂單號 <out_trade_no><![CDATA[1415757673]]></out_trade_no>//商戶訂單號 <attach><![CDATA[訂單額外描述]]></attach>//附加數據 <time_end><![CDATA[20141111170043]]></time_end>//支付完成時間 <trade_state><![CDATA[SUCCESS]]></trade_state>//交易狀態 </xml>
統一下訂單發起請求:json
package com.daat.front.pay.web.actions; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.daat.front.base.web.actions.BaseAction; import com.daat.front.base.web.tools.WebUtils; import com.daat.front.pay.sdk.common.RandomStringGenerator; import com.daat.front.pay.sdk.common.Util; import com.daat.front.pay.web.util.WechatURLs; import com.daat.front.weixin.sdk.base.domain.constant.WXAppConstant; import com.daat.front.weixin.sdk.base.exception.WXException; import com.daat.front.weixin.sdk.util.MD5Util; import com.daat.front.weixin.sdk.util.TenpayUtil; import com.daat.front.weixin.sdk.util.WXHttpUtil; public class pay extends BaseAction { public static void main(String[] args) { } /** * 商戶發起生成預付單請求 * @return */ public String unifiedOrder(){ Map map = WebUtils.getParameterMap();//獲取前臺數據 String appid = WXAppConstant.APP_ID;//appid String mch_id = WXAppConstant.MCH_ID;//微信支付商戶號 String nonce_str =getRandomStringByLength(8);//隨機碼 String body = map.get("bodyName").toString();//商品描述 String out_trade_no = map.get("outTradeNo").toString();//商品訂單號 String product_id = map.get("productId").toString();//商品編號 String total_fee = (int)(Float.valueOf(map.get("totalFee").toString()).floatValue()*100)+"";//總金額 分 String time_start =getCurrTime();//交易起始時間(訂單生成時間非必須) String trade_type = "NATIVE";//公衆號支付 String notify_url = "http://"+"域名"+"/"+"項目名"+"回調地址.do";//回調函數 SortedMap<String, String> params = new TreeMap<String, String>(); params.put("appid", appid); params.put("mch_id", mch_id); params.put("device_info", "WEB"); //設備號 params.put("nonce_str", nonce_str); params.put("body", body);//商品描述 params.put("out_trade_no", out_trade_no); params.put("product_id", product_id); params.put("total_fee", total_fee); params.put("time_start", time_start); params.put("trade_type", trade_type); params.put("notify_url", notify_url); String sign = "";//簽名(該簽名本應使用微信商戶平臺的API證書中的密匙key,但此處使用的是微信公衆號的密匙APP_SECRET) sign = getSign(params); //參數xml化 String xmlParams = parseString2Xml(params,sign); //判斷返回碼 String jsonStr = ""; try { jsonStr = WXHttpUtil.doPost(WechatURLs.prepayOrderUrl, xmlParams);// 調用支付接口 } catch (WXException e) { e.printStackTrace(); } if (jsonStr.indexOf("FAIL") == -1 && jsonStr.trim().length() > 0) {//成功 model.put("result_code", "SUCCESS"); } else {//失敗 try { Map resultMap = new HashMap(); resultMap = getMapFromXML(jsonStr);// 解析返回值 if(resultMap!=null&&"SUCCESS".equals(resultMap.get("return_code").toString())){ //通訊接口二級錯誤 model.put("result_code", resultMap.get("result_code")); model.put("error_code", resultMap.get("err_code")); model.put("result_msg", resultMap.get("err_code_des")); }else{ //通訊接口一級錯誤 model.put("result_code", "FAIL"); } } catch (Exception e) { e.printStackTrace(); } } return "success"; } /** * 參數進行XML化 * @param map,sign * @return */ public static String parseString2Xml(Map<String, String> map,String sign){ StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = map.entrySet(); Iterator iterator = es.iterator(); while(iterator.hasNext()){ Map.Entry entry = (Map.Entry)iterator.next(); String k = (String)entry.getKey(); String v = (String)entry.getValue(); sb.append("<"+k+">"+v+"</"+k+">"); } sb.append("<sign>"+sign+"</sign>"); sb.append("</xml>"); return sb.toString(); } /** * 獲取簽名 md5加密(微信支付必須用MD5加密) * 獲取支付簽名 * @param params * @return */ public static String getSign(SortedMap<String, String> params){ String sign = null; StringBuffer sb = new StringBuffer(); Set es = params.entrySet(); Iterator iterator = es.iterator(); while(iterator.hasNext()){ Map.Entry entry = (Map.Entry)iterator.next(); String k = (String)entry.getKey(); String v = (String)entry.getValue(); if (null != v && !"".equals(v) && !"sign".equals(k)&& !"key".equals(k)) { sb.append(k+"="+v+"&"); } } sb.append("key="+WXAppConstant.APP_SECRET); sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); return sign; } public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException { //這裏用Dom的方式解析回包的最主要目的是防止API新增回包字段 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputStream is = Util.getStringStream(xmlString); Document document = builder.parse(is); //獲取到document裏面的所有結點 NodeList allNodes = document.getFirstChild().getChildNodes(); Node node; Map<String, Object> map = new HashMap<String, Object>(); int i=0; while (i < allNodes.getLength()) { node = allNodes.item(i); if(node instanceof Element){ map.put(node.getNodeName(),node.getTextContent()); } i++; } return map; } /** * 獲取必定長度的隨機字符串 * @param length 指定字符串長度 * @return 必定長度的字符串 */ public static String getRandomStringByLength(int length) { String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } /** * 獲取當前時間 yyyyMMddHHmmss * @return String */ public static String getCurrTime() { Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String s = outFormat.format(now); return s; } }
預付單成功返回信息api
測試支付返回信息: <xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx13842d984810c06b]]></appid> <mch_id><![CDATA[1355962702]]></mch_id> <device_info><![CDATA[WEB]]></device_info> <nonce_str><![CDATA[uUaaXpCCnERVXE6R]]></nonce_str> <sign><![CDATA[E9A1087F5A0C5F8EBCF26F3C7A842022]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <openid><![CDATA[oD7UhwESE3wh22Uz6PqdCXRyR-pA]]></openid> <is_subscribe><![CDATA[Y]]></is_subscribe> <trade_type><![CDATA[NATIVE]]></trade_type> <bank_type><![CDATA[CFT]]></bank_type> <total_fee>2</total_fee> <fee_type><![CDATA[CNY]]></fee_type> <transaction_id><![CDATA[4002722001201610247590660332]]></transaction_id> <out_trade_no><![CDATA[1477296302523]]></out_trade_no> <attach><![CDATA[]]></attach> <time_end><![CDATA[20161024155820]]></time_end> <trade_state><![CDATA[SUCCESS]]></trade_state> <cash_fee>2</cash_fee> </xml>