扫码支付

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

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

步骤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/

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

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

    CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/ ...

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

    一.SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1,下载.NET C#版本: 二.微信相关设置:(微信扫码 ...

  3. JAVA微信扫码支付模式二功能实现完整例子

    概述 本例子实现微信扫码支付模式二的支付功能,应用场景是,web网站微信扫码支付.实现从点击付费按钮.到弹出二维码.到用户用手机微信扫码支付.到手机上用户付费成功.web网页再自动调整到支付成功后的页 ...

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

    直接上干货 ,我们的宗旨就是为人民服务.授人以鱼不如授人以渔.不吹毛求疵.不浮夸.不虚伪.不忽悠.一切都是为了社会共同进步,繁荣昌盛,小程序猿.大程序猿.老程序猿还是嫩程序猿,希望这个社会不要太急功近 ...

  5. .NET微信扫码支付模式二API接口开发测试

    主要实现微信扫码支付,官网的SDKdemo 就不要使用 一直不能调试通过的,还是自己按照API接口文档一步一步来实现,吐槽下微信一点责任感都木有,能不能demo搞个正常的吗,不要坑惨了一大群码农们有点 ...

  6. Java之微信支付(扫码支付模式二)案例实战

    摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...

  7. ThinkPHP 整合微信支付 扫码支付 模式二 图文教程

    这篇文章主要介绍扫码支付场景二. 目前有两种模式,模式一比模式二稍微复杂点,至于模式一与模式二的具体内容,流程,微信开发文档都有详细介绍,这里就不多说废话,接下来赶紧上教程! [title]下载SDK ...

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

    官方文档点击查看 准备工作:已通过微信认证的公众号,域名可以不通过ICP备案借鉴了很多大神的文章,在此先谢过了大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款模式二支付的流程 ...

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

    本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/10,所以微信支付 ...

随机推荐

  1. XUtils——GET请求

    //HttpUtils实例化对象     HttpUtils http = new HttpUtils();       /*                *发送请求send(HttpMethod ...

  2. NTDLL未文档化函数RtlGetNtVersionNumbers获取操作系统版本

    作为新手,对获取操作系统版本号好奇过,因为曾经假象过一个场景:自己的程序在windows xp环境下编译,在windows 2003, windows 7,windows 8是否需要提权或者兼容处理, ...

  3. Calculating Stereo Pairs

    Calculating Stereo Pairs Written by Paul BourkeJuly 1999 Introduction The following discusses comput ...

  4. vim段替换

    文件中有很多字段: dd ssdf df aaa="100" dd ssdf df aaa="200" asdf sdf sdf aaa="700&q ...

  5. LXD 2.0 系列(四):资源控制

    LXD 提供了各种资源限制.其中一些与容器本身相关,如内存配额.CPU 限制和 I/O 优先级.而另外一些则与特定设备相关,如 I/O 带宽或磁盘用量限制.-- Stéphane Graber 本文导 ...

  6. 188. Best Time to Buy and Sell Stock IV leetcode解题笔记

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  7. survey on Time Series Analysis Lib

    (1)I spent my 4th year Computing project on implementing time series forecasting for Java heap usage ...

  8. vios 虚拟光驱 安装vioc

    一.VIO server 创建虚拟光驱 1 检查是否创建Library $lsrep 2 创建 VMLibrary :vg 和size都可以自己定义 $mkrep -sp rootvg -size 1 ...

  9. virtual 修饰符 C# .NET

    virtual 关键字用于修饰方法.属性.索引器或事件声明,并且允许在派生类中重写这些对象. 例如,此方法可被任何继承它的类重写. (C#参考) public virtual double Area( ...

  10. 读取全球ip获取用户地区

    这个 首先说明下.ip库是qq纯真ip库 dat文件类型 public static string QQipPath = AppDomain.CurrentDomain.BaseDirectory + ...