微信支付之前的统一下单

前言:想调用微信支付的小伙伴们,在看我给予的案例之前,我们先看懂微信的支付流程。

我总结了一下,就比较简单了(要看明细流转,就到微信官网)【微信签名这一块我们拿出来单独简介】【报酬求助联系:1124904642】

1.客户下单,该单据保存在自己的库存中

2.在点击确认支付的时候,调用微信的统一下单接口

3.统一下单接口会根据你提供的回调接口反馈统一下单信息,自己去解析返回的XML术语对比是否成功,成功与否,把信息返回给微信(微信会反复回调你的接口至少两次,确保统一下单成功)

4.告诉微信,统一下单成功后,微信会返回成功之后的信息,自己解析XML术语,根据术语中的字段,生成微信调用SDK的必要参数.

一.微信统一下单

1.统一下单接口讲解

统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder

请求参数

字段名 变量名 必填 类型 示例值 描述
公众账号ID appid String(32) wxd678efh567hg6787 微信支付分配的公众账号ID(企业号corpid即为此appId)
商户号 mch_id String(32) 1230000109 微信支付分配的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,长度要求在32位以内。推荐随机数生成算法
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 通过签名算法计算得出的签名值,详见签名生成算法
签名类型 sign_type String(32) MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
商品描述 body String(128) 腾讯充值中心-QQ会员充值
商品简单描述,该字段请按照规范传递,具体请见参数规定

商品详情 detail String(6000)   商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见“单品优惠参数说明”
附加数据 attach String(127) 深圳分店 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
商户订单号 out_trade_no String(32) 20150806125346 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。详见商户订单号
标价币种 fee_type String(16) CNY 符合ISO 4217标准的三位字母代码,默认人民币:CNY,详细列表请参见货币类型
标价金额 total_fee Int 88 订单总金额,单位为分,详见支付金额
终端IP spbill_create_ip String(16) 123.12.12.123 APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
交易起始时间 time_start String(14) 20091225091010 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
交易结束时间 time_expire String(14) 20091227091010
订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。订单失效时间是针对订单号而言的,由于在请求支付的时候有一个必传参数prepay_id只有两小时的有效期,所以在重入时间超过2小时的时候需要重新请求下单接口获取新的prepay_id。其他详见时间规则

建议:最短失效时间间隔大于1分钟

订单优惠标记 goods_tag String(32) WXG 订单优惠标记,使用代金券或立减优惠功能时需要的参数,说明详见代金券或立减优惠
通知地址 notify_url String(256) http://www.weixin.qq.com/wxpay/pay.php 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
交易类型 trade_type String(16) JSAPI 取值如下:JSAPI,NATIVE,APP等,说明详见参数规定
商品ID product_id String(32) 12235413214070356458058 trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
指定支付方式 limit_pay String(32) no_credit 上传此参数no_credit--可限制用户不能使用信用卡支付
用户标识 openid String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识。openid如何获取,可参考【获取openid】。企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid,再调用【企业号userid转openid接口】进行转换
+场景信息 scene_info String(256)
{"store_info" : {
"id": "SZTX001",
"name": "腾大餐厅",
"area_code": "440305",
"address": "科技园中一路腾讯大厦" }}


该字段用于上报场景信息,目前支持上报实际门店信息。该字段为JSON对象数据,对象格式为{"store_info":{"id":
"门店ID","name": "名称","area_code": "编码","address": "地址" }}
,字段详细说明请点击行前的+展开

将参数构造成XML字符串写入到请求微信接口的请求正文中(xml字符串示例)

<xml>

<appid>wx2421b1c4370ec43b</appid>

<attach>支付测试</attach>

<body>JSAPI支付测试</body>

<mch_id>10000100</mch_id>

<detail><![CDATA[{
"goods_detail":[
{
"goods_id":"iphone6s_16G",
"wxpay_goods_id":"1001",
"goods_name":"iPhone6s 16G",
"quantity":1,
"price":528800,
"goods_category":"123456",
"body":"苹果手机"
},
{
"goods_id":"iphone6s_32G",
"wxpay_goods_id":"1002",
"goods_name":"iPhone6s 32G",
"quantity":1,
"price":608800,
"goods_category":"123789",
"body":"苹果手机"
}
]
}]]></detail>

<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>

<notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>

<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>

<out_trade_no>1415659990</out_trade_no>

<spbill_create_ip>14.23.150.211</spbill_create_ip>

<total_fee>1</total_fee>

<trade_type>JSAPI</trade_type>

<sign>0CB01533B8C1EF103065174F50BCA001</sign>

</xml>

2.notify_url:回调(通知地址接口)

微信解析XML字符串信息之后会调用notify_url,回调接口,告诉客户同意下下单是否成功。

3.统一下单成功之后,根据微信返回的信息中构造调用微信SDK需要用到的参数,返回给前端,前端利用SDK调用支付的接口。

代码案例:

//微信支付需要的参数返回
    public static  boolean  weChat(Map<String,Object> map,Map<String,Object> errorMap){
        //微信统一下单
        if(!PublicUtil.unifiedOrder(map,errorMap)){
            errorMap.put("error",ResMessage.Server_Abnormal.code);
            return true;
        }
        //下单成构造四个参数调用SDK
        JSONObject jsonObject= weChatMaps(map);
        map.clear();
        jsonObjectConversionMap(jsonObject, map);
        return false;
    }

unifiedOrder:

/**
     *
     * @Title: unifiedOrder
     * @Description: TODO
     * @param @return
     * @return boolean
     * @throws
     * 微信统一下单接口
     */
    public static  boolean  unifiedOrder(Map<String,Object> map,Map<String,Object> errorMap){
        Map<String,Object> mapstem  = new HashMap<String,Object>();
        map.put("body","******");
        map.put("time_start",DateForamtUtil.to_YYYYMMddHHmmss_str(new Date())); //交易起始时间
        map.put("time_expire",DateForamtUtil.to_YYYYMMddHHmmss_str(DateForamtUtil.addMinute(new Date(), 10))); //交易結束起始时间
        //封装微信端要求的参数
        Map<String,Object> mapParameter =encapsulatedData(map);//封装微信端要求的参数
        //封装成XML,转成字符串
        String  spliceXml=spliceXml(mapParameter);
        try{
            //访问微信接口
            String  strResult =getHttpRequest(Configure.UNIFIEDORDER_API, null, spliceXml);
            //解析微信返回的XML
            mapstem=XMLParser.getMapFromXML(spliceXml);
            if(mapstem==null || mapstem.size()==0){
                errorMap.put("error",ResMessage.comment_autograph_notnull.code);
                return true;
            }
            map.put("prepay_id",String.valueOf(mapstem.get("mapstem")));
            Map<String,Object> maps=weChatMaps(map);
            return false;
        } catch (MalformedURLException e){
            e.printStackTrace();
            return true;
        } catch (IOException e){
            e.printStackTrace();
            return true;
        } catch (ParserConfigurationException e){
            // TODO Auto-generated catch block
            e.printStackTrace();
            return true;
        } catch (SAXException e){
            // TODO Auto-generated catch block
            e.printStackTrace();
            return true;
        }
        
    }

encapsulatedData:

/**
     *
     * @Title: encapsulatedData
     * @Description: TODO
     * @param
     * @return void
     * @throws
     * 构造微信统一下单的数据参数
     */
    public static Map<String,Object>  encapsulatedData(Map<String,Object> map){
        Map<String,Object> mapParameter = new HashMap<String,Object>();
        mapParameter.put("appid", Configure.getAppid());//微信分配的公众号ID
        mapParameter.put("mch_id", Configure.getMchid());//微信支付分配的商户号ID
        mapParameter.put("nonce_str",UUID.randomUUID().toString().replace("-",""));//随机字符串32位
        mapParameter.put("body", String.valueOf(map.get("body")));//商品描述
        mapParameter.put("out_trade_no", String.valueOf(map.get("strorder")));//微信支付分配的商户号ID
        String dbmoney=String.valueOf(Float.parseFloat(String.valueOf(map.get("dbmoney")))*100);
        mapParameter.put("total_fee",dbmoney.substring(0,dbmoney.length()-2));//标价金额
        mapParameter.put("time_start", String.valueOf(map.get("time_start")));
        mapParameter.put("time_expire", String.valueOf(map.get("time_expire")));
        mapParameter.put("openid", String.valueOf(map.get("struserid")));//用户的openid
        mapParameter.put("spbill_create_ip", String.valueOf(map.get("spbill_create_ip")));//终端IP  request.getRemoteAddr()
        mapParameter.put("notify_url", "http://autotest.xiaobaoche.net/weixin/paynt");//通知地址
        mapParameter.put("trade_type", "JSAPI");//支付类型
        String sign=sign(mapParameter);
        mapParameter.put("sign",sign);//签名(通过签名算法计算得出的签名值,详见签名生成算法)
        return mapParameter;
    }

构造XNL字符串 spliceXml:

/**
     *
     * @Title: spliceXml
     * @Description: TODO
     * @param @return
     * @return String
     * @throws
     * 拼接微信要求的XML格式,凭借XML时,最好用转义符号 <![CDATA[]]>
     */
    public static String  spliceXml(Map<String,Object> map){
        StringBuffer spliceXml=new StringBuffer();
        spliceXml.append("<xml>");
        spliceXml.append("<appid><![CDATA[").append(String.valueOf(map.get("appid"))).append("]]</appid>");
        spliceXml.append("<mch_id><![CDATA[").append(String.valueOf(map.get("mch_id"))).append("]]</mch_id>");
        spliceXml.append("<nonce_str><![CDATA[").append(String.valueOf(map.get("nonce_str"))).append("]]</nonce_str>");
        spliceXml.append("<body><![CDATA[").append(String.valueOf(map.get("body"))).append("]]</body>");
        spliceXml.append("<out_trade_no><![CDATA[").append(String.valueOf(map.get("out_trade_no"))).append("]]</out_trade_no>");
        spliceXml.append("<total_fee><![CDATA[").append(String.valueOf(map.get("total_fee"))).append("]]</total_fee>");
        spliceXml.append("<time_start><![CDATA[").append(String.valueOf(map.get("time_start"))).append("]]</time_start>");
        spliceXml.append("<time_expire><![CDATA[").append(String.valueOf(map.get("time_expire"))).append("]]</time_expire>");
        spliceXml.append("<appid><![CDATA[").append(String.valueOf(map.get("spbill_create_ip"))).append("]]</appid>");
        spliceXml.append("<spbill_create_ip><![CDATA[").append(String.valueOf(map.get("notify_url"))).append("]]</spbill_create_ip>");
        spliceXml.append("<trade_type><![CDATA[").append(String.valueOf(map.get("trade_type"))).append("]]</trade_type>");
        spliceXml.append("<sign><![CDATA[").append(String.valueOf(map.get("sign"))).append("]]</sign>");
        spliceXml.append("</xml>");
        return spliceXml.toString();
    }

访问微信接口的方法

/**
     * 获取http请求的数据
     * @return
     * @throws IOException
     * @throws MalformedURLException
     * 发起请求的方法
     */
    public static String getHttpRequest(String url, String param, String contentType) throws MalformedURLException, IOException{
        String result = "";
        HttpURLConnection connection = null;
        connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setDoOutput(true);// 设置连接输出流为true,默认false (post
        // 请求是以流的方式隐式的传递参数)
        connection.setDoInput(true); // 设置连接输入流为true
        connection.setRequestProperty("Accept-Charset", "utf-8");
        connection.setRequestProperty("contentType", "utf-8");
        connection.setRequestProperty("contentType", "utf-8");
        connection.setUseCaches(false); // post请求缓存设为false
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // application/x-www-form-urlencoded->表单数据
        connection.connect(); // 建立连接
        // application/json;charset=UTF-8    application/x-www-form-urlencoded
        if(contentType != null){
            connection.setRequestProperty("contentType", contentType);
        }
        //参数字符串
        if(param != null){
            OutputStream out = connection.getOutputStream(); // 创建输入输出流
            out.write(param.getBytes("UTF-8")); // 将参数输出到连接
            out.flush(); // 输出完成后刷新并关闭流
            out.close(); // 重要且易忽略步骤 (关闭流,切记!)
        }
        InputStream fin = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(fin, "utf-8"));
        String str = reader.readLine();
        while (str != null){
            result += str;
            str = reader.readLine();
        }
        return result;
    }

getMapFromXML:解析微信端返回的XML

/**
     *
     * @Title: getMapFromXML
     * @Description: TODO
     * @param @param xmlString
     * @param @return
     * @param @throws ParserConfigurationException
     * @param @throws IOException
     * @param @throws SAXException
     * @return Map<String,Object>
     * @throws
     * 解析XML,返回MAP
     */
    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  = null;
        try{
         document = builder.parse(is);
        }catch(Exception e){
            
        }
        //获取到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;

}

构造微信调用SDK支付需要用到的参数

//------------------构造微信支付需要的参数开始--------------------------------------------------------------
    public static JSONObject  weChatMaps(Map<String,Object> maps){
        //构造做微信支付时需要用到的参数
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("appId",Configure.getAppid());//公众号APPID
        jsonObject.put("timeStamp",String.valueOf(System.currentTimeMillis() / 1000));
        jsonObject.put("nonceStr",PublicTool.getRandomUUID(32));
        jsonObject.put("package","prepay_id="+ String.valueOf(maps.get("prepay_id")));
        jsonObject.put("signType","md5");
        Map<String,Object> map = jsonObject;
        String signs =  sign(map);//签名            
        jsonObject.put("paySign",signs);    
        return jsonObject;
    }
    //------------------构造微信支付需要的参数结束--------------------------------------------------------------

原文地址:https://www.cnblogs.com/yvanBk/p/8412717.html

时间: 2024-10-11 07:57:59

微信支付之前的统一下单的相关文章

微信支付开发,统一下单

1.签名失败 是因为统一下单接口中的API_KEY没有设置的原因,设置以后就OK了. <xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名错误]]></return_msg></xml>, 1.参数名ASCII码未按升序排列,或者是生成MD5字符串没有toUpperCase转换为大写.这种问题解决方法很简单,到微信官网上用

微信支付模式二 统一下单一直提示签名错误

来源:https://www.jianshu.com/p/2195599195e3 我这个项目是用的公司之前的商户信息,但是也把新的公众号进行了支付配置,应该没什么问题了,但是在选择支付方式NATIVE生成二维码支付时一直提示签名错误.所以截取xml进行字段的检查.检查sgin的生成过程,数据都没什么问题.另外使用微信官方的支付sign校验工具进行匹配,将转成的xml填写进去,输入商户的密钥key,居然说签名是正确的. 重点:微信支付接口返回签名错误,使用微信sign校验工具提示签名正确,可以试

微信:微信扫码支付、调用统一下单接口、网站支付 + springmvc

一.场景:公司需要在网站上进行微信支付. 二.API:使用微信开放平台的接入微信支付 -扫码支付.微信支付开发者平台链接 三.分析: 接入扫码支付(包含PC网站支付)包含三个阶段,问这里只讲使用,也就是第2阶段的<启动设计和开发>. 点击查看开发者文档(扫码支付)后,这里感觉微信的文档没有支付宝好理解(稍微吐槽下~~~),不过我们忽略一切,直接进入模式二:模式二最简单直接,不需要在商户后台进行配置,推荐大家使用,微信也说流程更为简单,我这里也讲的是模式二,模式一大家有兴趣可以自行研究下. 如上

微信扫码支付(4):统一下单

1.下载微信JAVA SDK 地址:https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA.zip 2.配置文件及代码 #####################支付宝-开始##################### #应用ID com.test.zconfig[APP_ID]=****** #支付宝网关,含dev是测试网关,正式地址:https://openapi.alipay.com/gateway.do com.test.

基于H5的微信支付开发详解

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

****基于H5的微信支付开发详解[转]

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

微信支付接口开发之---微信支付之JSSDK(公众号支付)步骤

1.准备 1.1.公众号为服务号,开通微信支付功能 1.2.为了方便调试微信后台的回调URL(必须为外网),我用了nat123软件来做一个映射 1.3.官方微信开发的示例WxPayApi(.net版本) 2.业务流程图 3.步骤 3.1.用户访问商户的链接,商户链接地址调用[网页授权获取用户信息]接口获取用户的openid和access_token 参考:网页授权获取用户基本信息 3.1.1.第一步,用户同意授权,获取code,调用接口如下 https://open.weixin.qq.com/

iOS-关于微信支付

突然发现的一篇文章,这位博主介绍的还是挺详细的,给大家分享一下 不懂的也可以咨询我qq:564702640 1.申请接入 详见 微信支付申请接入 . 创建应用+审核通过,你将得到:APP_ID.APP_SECRET.APP_KEY.PARTNER_ID .那就可以开始实现支付功能的接入. 2.业务流程 不管是客户端还是后台开发者,微信支付开发者文档里面这张交互时序图,都有必要看看.其实很多开发者,当然也包括我,在接入第三方sdk时,一般都是从其官方demo入手,快速了解其api.结果在这里就掉坑

springboot+微信小程序实现微信支付【统一下单】

说明: 1)微信支付必须有营业执照才可以申请 2)微信支付官方api是全套的,我这是抽取其中的统一下单api,做了一个简单的封装 首先看看微信支付 商户系统和微信支付系统主要交互: 1.小程序内调用登录接口,获取到用户的openid,api参见公共api[小程序登录API] 2.商户server调用支付统一下单,api参见公共api[统一下单API] 3.商户server调用再次签名,api参见公共api[再次签名] 4.商户server接收支付通知,api参见公共api[支付结果通知API]