微信支付---统一下单
微信支付---统一下单
身为一个码农,总是需要要学习一些新的知识来丰富自己的羽翼,让自己能够在程序员的道路上走的更远,更稳。
最近在研究关于微信支付的接口调用:微信支付开发文档
接口连接:URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
请求参数、返回字段、错误码、请阅读:统一下单开发文档
请求参数格式和信息例:
<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>
统一下订单发起请求:
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; } }
预付单成功返回信息
测试支付返回信息: <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>