微信支付---统一下单

微信支付---统一下单

身为一个码农,总是需要要学习一些新的知识来丰富自己的羽翼,让自己能够在程序员的道路上走的更远,更稳。

最近在研究关于微信支付的接口调用:微信支付开发文档

接口连接: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>
原文地址:https://www.cnblogs.com/fxwl/p/6000094.html