微信公众号 扫码支付 模式二 demo

扫码支付

本文附有代码,在下方,如果不熟悉场景的可以看看下面的场景介绍

场景介绍

官网介绍地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

用户扫描商户展示在各种场景的二维码进行支付。

步骤1:商户根据微信支付的规则,为不同商品生成不同的二维码(如图6.1),展示在各种场景,用于用户扫描购买。

步骤2:用户使用微信“扫一扫”(如图6.2)扫描二维码后,获取商品支付信息,引导用户完成支付(如图6.3)。

图6.1 支付二维码

图6.2 打开微信扫一扫二维码

图6.3 确认支付页面

步骤(3):用户确认支付,输入支付密码(如图6.4)。

步骤(4):支付完成后会提示用户支付成功(如图6.5),商户后台得到支付成功的通知,然后进行发货处理。

图6.4 用户确认支付,输入密码

图6.5 支付成功提示

模式二与模式一相比,流程更为简单,不依赖设置的回调支付URL。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。

业务流程时序图

图6.9 原生支付模式二时序图

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。

(4)商户后台系统根据返回的code_url生成二维码。

(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。

(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。

(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。

(8)微信支付系统根据用户授权完成支付交易。

(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。

(12)商户确认订单已支付后给用户发货。

生成二维码规则

对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。该模式链接较短,生成的二维码打印到结账小票上的识别率较高。

例如,将weixin://wxpay/s/An4baqw生成二维码见图6.10。

图6.10 原生支付“模式二”二维码示例

下面上代码:

这里特要注意的就是key,这个key不是公众号下面的key,而是商户下的key,这个key是自己生成的32位字符串,

调用的是微信统一下单接口:

getWxPayQRCode() 返回的就是要扫的二维码中的值;只要把这个值塞到二维中即可!
/**
     * 微信扫码支付 模式二
     * @return返回的就是二维中的值
     * @throws Exception
     */
    public String getWxPayQRCode() throws Exception{
        //商户key
        String key = "mlqho2dwhxxxxxxxxxxxv81m1r6i28";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        Map<String,String> map = new HashMap<String, String>();
        //公众账号ID
        map.put("appid","wssssssxxxxxxxxxe0e5b");
        //商户号
        map.put("mch_id","1xxxxxxxxx2");
        //随机数
        map.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
        //商品描述
        map.put("body","香辣鸡腿堡");
        //订单号
        map.put("out_trade_no",sdf.format(new Date()));
        //总金额单位分
        map.put("total_fee","1");
        InetAddress ia = InetAddress.getLocalHost();
        //ip
        map.put("spbill_create_ip",ia.getHostAddress());
        //通知地址
        map.put("notify_url","www.niudao.com");
        //交易类型
        map.put("trade_type","NATIVE");
        //商品ID
        map.put("product_id","10000");
        //签名
        map.put("sign", QRSign.getSign(map, key));
        //请求地址及请求数据
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String data = MapToXmlUtil.mapToXml(map);
        //发送请求
        ClientRequest request = new ClientRequest(url);
        request.body("text/xml;charset=utf-8",data);
        ClientResponse response = request.post(String.class);
        //xml字符串转化成json对象
        String result = XMLAndJsonUtil.xmlChangeJson(response.getEntity().toString());
        result = result.replaceAll("\r\n","");
        JSONObject jsonObject = JSONObject.fromObject(result);
        //二维码内容
        String qrCode = "";
        if(jsonObject.get("return_code").toString().equals("SUCCESS")){
            qrCode = jsonObject.get("code_url").toString();
        }
        return qrCode;
    }

工具类

RandomStringGenerator 传入一个n,生成n位随机字符串
import java.util.Random;

/**
 * User: rizenguo
 * Date: 2014/10/29
 * Time: 14:18
 */
public class RandomStringGenerator {

    /**
     * 获取一定长度的随机字符串
     * @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();
    }

}
QRSign 传入的数据生成签名,
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Map;

/**
 * Created by Administrator on 16-12-1.
 */
public class QRSign {

    /**
     * 微信支付签名算法sign
     * @param map 请求微支付body
     * @param key 商户key (不是公众号key)
     * @return
     */
    public static String getSign(Map<String,String> map,String key) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new String[map.keySet().size()]);//获取map中的key转为array
        Arrays.sort(keyArr);//对array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" + key);
        String sign = string2MD5(sb.toString());
        return sign;
    }

    /***
     * MD5加密 生成32位md5码
     */
    public static String string2MD5(String str){
        if (str == null || str.length() == 0) {
            return null;
        }
        char hexDigits[] = { ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
                ‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘ };

        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(str.getBytes("UTF-8"));

            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf).toUpperCase();
        } catch (Exception e) {
            return null;
        }
    }
}
MapToXmlUtil作用:

由于微信支付接口传入的参数是xml格式的,因此此类是将map转化为xml格式

import java.util.Map;

/**
 * Created by Administrator on 16-12-1.
 */
public class MapToXmlUtil {
    /**
     * 将map 转化成 xml
     * @param map
     * @return
     */
    public static String mapToXml(Map<String,String> map)throws Exception{
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append("<" + entry.getKey() + ">" + entry.getValue().toString() + "</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }
}

最终返回的结果也是xml格式的,为了方便取值,本人转成json格式;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by Administrator on 16-12-1.
 */
public class XMLAndJsonUtil {

    //用于判断是否有子节点,若有就将子节点也进行拼接,若无则返回""
    public static String checkChildEle(Element element) throws DocumentException {
        String json="";
        List<Element> list = new ArrayList<Element>();
        list=element.elements();
        if (list.size()>0) {
            for (Element ele : list) {
                json+= "‘" + ele.getName() + "‘" + ":" + "‘" + ele.getText() + "‘" + "," + "\r\n" + checkChildEle(ele);
            }
        }
        return json;
    }
    //这个方法是将xml字符串转成Json
    public static String xmlChangeJson(String XML) throws DocumentException{
        Document document= DocumentHelper.parseText(XML);
        Element root=document.getRootElement();
        Iterator it=root.elementIterator();
        String json="{";
        while (it.hasNext()) {
            Element element =(Element)it.next();
            String j=checkChildEle(element);
            if (j=="") {
                json+= "‘" + element.getName() + "‘" + ":" + "‘" + element.getText() + "‘" + ","+"\r\n";
            }else {
                json+=j;
            }

        }
        json+="}";
        return json;
    }
    //这个方法是将xml文件转成Json
    public static String xmlChangeJson(File XML) throws DocumentException{
        SAXReader reader=new SAXReader();
        Document document=reader.read(XML);
        Element root=document.getRootElement();
        Iterator it=root.elementIterator();
        String json="{";
        while (it.hasNext()) {
            Element element =(Element)it.next();
            String j=checkChildEle(element);
            if (j=="") {
                json+=element.getName()+":"+element.getText()+","+"\r\n";
            }else {
                json+=j;
            }

        }
        json+="}";
        return json;
    }
}

如果报签名错误可以到下面这个网址去验证sign生成的结果是否一致

https://pay.weixin.qq.com/wiki/tools/signverify/

时间: 2024-10-18 00:09:33

微信公众号 扫码支付 模式二 demo的相关文章

JAVA微信扫码支付模式二功能实现以及回调

一.准备工作 首先吐槽一下微信关于支付这块,本身支持的支付模式就好几种,但是官方文档特别零散,连像样的JAVA相关的demo也没几个.本人之前没有搞过微信支付,一开始真是被它搞晕,折腾两天终于调通了,特此写下来,以享后人吧! 关于准备工作,就"微信扫码支付模式二"官方文档地址在这 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 可以先看看,实际上需要准备的东西有以下几个: 其中APP_ID和APP_SECRET

C# 微信扫码支付API (微信扫码支付模式二)

一.SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1,下载.NET C#版本: 二.微信相关设置:(微信扫码支付模式二) 1. 公众账号ID,公众账号secert ,地址:https://mp.weixin.qq.com/ 2. 商户号,商户支付密钥KEY,商户平台地址:https://pay.weixin.qq.com/ 5. 部署的服务器终端ip及回调页面 (1)部署的服务器终端ip:即程序部署所在的

微信支付Native扫码支付模式二之CodeIgniter集成篇

微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 官方API列表:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 二维码生成类库:phpqrcode 走了几天的弯路,直到遇到Lamtin指点(热心网友),他说你既然是集成

微信扫码支付模式二之CodeIgniter集成篇

CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 官方API列表:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 二维码生成类库:phpqrcode 走了几天的弯路,直到遇到Lamtin指点(热心网友)

.NET MVC结构框架下的微信扫码支付模式二 API接口开发测试

直接上干货 ,我们的宗旨就是为人民服务.授人以鱼不如授人以渔.不吹毛求疵.不浮夸.不虚伪.不忽悠.一切都是为了社会共同进步,繁荣昌盛,小程序猿.大程序猿.老程序猿还是嫩程序猿,希望这个社会不要太急功近利 ,希望每个IT行业的BOSS要有良知,程序猿的青春年华都是无私默默奉献,都是拿命拼出来了现在的成就,如果卸磨杀驴,如果逼良为娼,请MM你的良心对得起你爹妈吗,你也有家,你也有小孩,你也有父母的. 在这里致敬程序猿, 致敬我们的攻城狮,致敬我们最可爱的人! 珍惜生命,换种活法也是依然精彩. Vie

Java微信公众平台开发之扫码支付模式二

官方文档点击查看 准备工作:已通过微信认证的公众号,域名可以不通过ICP备案借鉴了很多大神的文章,在此先谢过了大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款模式二支付的流程如下图,可以说是最简单的支付方式了 业务流程说明:(1)商户后台系统根据用户选购的商品生成订单.(2)用户确认支付后调用微信支付[统一下单API]生成预支付交易:(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url.(4)商户后台系统根据返回的code_url生成

php微信支付(仅pc端扫码支付模式二)详细步骤.----仅适合第一次做微信开发的程序员

本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/10,所以微信支付的版本也是对应此时的版本. 一.前期准备: 首先你们公司开通微信支付功能后,会收到一份邮件,里面有账户相关信息,一般有:微信支付商户号,商户平台登录帐号,商户平台登录密码,申请对应的公众号,公众号APPID. 1.下载demo:用上面信息登陆“微信商户平台”,>>>(右上角开发文档)>

thinkphp5.0 微信扫码支付模式二

仅供个人参考,方便大家. 一.1)https://pay.weixin.qq.com/index.php/core/home/login  复制此地址 打开微信商户平台. 2)下载安全操作证书(最好在IE下载): 3)安装后的界面 4)下载证书 5)设置32位秘钥(百度秘钥生成可在线生成): 二.1)https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1  打开此链接下载SDK. 2) 下载后的目录结构 3)在thinkphp

微信扫码支付(模式一)

项目开源地址:http://git.oschina.net/javen205/weixin_guide 微信扫码支付(模式一)你有测试成功吗?如果你看到了这篇文章,我想你是在测试中遇到问题了.OK 那现在我们来看看微信扫码支付中的坑. 原生支付URL参数错误 回调接口URL有回调,但是接收不到参数 商户后台返回的数据字段结构不合法 获取商户订单信息超时或者商户返回的httpcode非200 官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.