微信公众号 扫码支付 模式二 demo
扫码支付
本文附有代码,在下方,如果不熟悉场景的可以看看下面的场景介绍
用户扫描商户展示在各种场景的二维码进行支付。
步骤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生成的结果是否一致
微信公众号 扫码支付 模式二 demo的更多相关文章
- 微信支付Native扫码支付模式二之CodeIgniter集成篇
CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/ ...
- C# 微信扫码支付API (微信扫码支付模式二)
一.SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1,下载.NET C#版本: 二.微信相关设置:(微信扫码 ...
- JAVA微信扫码支付模式二功能实现完整例子
概述 本例子实现微信扫码支付模式二的支付功能,应用场景是,web网站微信扫码支付.实现从点击付费按钮.到弹出二维码.到用户用手机微信扫码支付.到手机上用户付费成功.web网页再自动调整到支付成功后的页 ...
- .NET MVC结构框架下的微信扫码支付模式二 API接口开发测试
直接上干货 ,我们的宗旨就是为人民服务.授人以鱼不如授人以渔.不吹毛求疵.不浮夸.不虚伪.不忽悠.一切都是为了社会共同进步,繁荣昌盛,小程序猿.大程序猿.老程序猿还是嫩程序猿,希望这个社会不要太急功近 ...
- .NET微信扫码支付模式二API接口开发测试
主要实现微信扫码支付,官网的SDKdemo 就不要使用 一直不能调试通过的,还是自己按照API接口文档一步一步来实现,吐槽下微信一点责任感都木有,能不能demo搞个正常的吗,不要坑惨了一大群码农们有点 ...
- Java之微信支付(扫码支付模式二)案例实战
摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...
- ThinkPHP 整合微信支付 扫码支付 模式二 图文教程
这篇文章主要介绍扫码支付场景二. 目前有两种模式,模式一比模式二稍微复杂点,至于模式一与模式二的具体内容,流程,微信开发文档都有详细介绍,这里就不多说废话,接下来赶紧上教程! [title]下载SDK ...
- Java微信公众平台开发之扫码支付模式二
官方文档点击查看 准备工作:已通过微信认证的公众号,域名可以不通过ICP备案借鉴了很多大神的文章,在此先谢过了大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款模式二支付的流程 ...
- php微信支付(仅pc端扫码支付模式二)详细步骤.----仅适合第一次做微信开发的程序员
本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/10,所以微信支付 ...
随机推荐
- 利用node构建本地服务
利用node构建本地服务 首先安装下node.js,地址为https://nodejs.org/en/,然后安装npm. node.js的中文api地址http://nodeapi.ucdok.com ...
- 怎样获取本机的ip地址
首先介绍一下用到的结构体 struct hostent { const char *h_name; // official name of host char **h_aliases; // alia ...
- 修复IE9.0下PlaceHolder 属性问题js脚本
在开发前端系统时候碰到这种兼容问题,以下是个人解决方案,希望能给其他人带来帮助: var JPlaceHolder = { //检测 _check: function () { return 'pla ...
- [[UIScreen mainScreen] bounds] 返回的屏幕尺寸不对
在使用cocos2d-iphone 2.0生成项目的时候,用5s测试时全屏中上下一直有黑条,发现[[UIScreen mainScreen] bounds]返回的屏幕尺寸不是320*568的,而是32 ...
- SQL SERVER增加、删除、更改表中的字段名 (详询请加qq:2085920154)
1. 向表中添加新的字段 alter table table_name add column_name varchar2(20) not null 2. 删除表中的一个字段 delete t ...
- Dreamweaver 升级问题汇总
Adobe的产品开始从CC (Creative Cloud) 开始转向云平台,CS将逐渐成为过去时.不过CC并不限制用户在同一台机器上同时使用CS和CC,这种策略估计要持续较长一段时间. If you ...
- android应用中增加权限判断
android6.0系统允许用户管理应用权限,可以关闭/打开权限. 所以需要在APP中增加权限判断,以免用户关闭相应权限后,APP运行异常. 以MMS为例,在系统设置——应用——MMS——权限——&g ...
- Android Service完全解析,关于服务你所需知道的一切(上)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的A ...
- 基于ArcGIS Viewer for Flex开发的一款跨平台的应用程序
特点: 1.基于ArcGIS Viewer for Flex开发的一款跨平台的应用程序: -(IBAction) showTOC:(id)sender { if (_tocViewController ...
- Java实现视频网站的视频上传、视频转码、视频关键帧抽图, 及视频播放功能
视频网站中提供的在线视频播放功能,播放的都是FLV格式的文件,它是Flash动画文件,可通过Flash制作的播放器来播放该文件.项目中用制作的player.swf播放器. 多媒体视频处理工具FFmpe ...