概述

  Native支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。详情见开发文档。

前期准备

  1. 注册微信支付商户号,获取商户号 mch_id、key;
  2. 申请微信认证的服务号、政府或媒体类订阅号、小程序、APP、企业微信其中之一,并与商户号绑定。获取 appid。

开发步骤

Native支付可分为两种模式,商户根据支付场景选择相应模式。本文仅介绍模式二。

业务流程时序图

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。

统一下单

SDK

API 详见统一下单API。
下载官方 SDK ,或通过 maven 获取依赖。推荐使用后者。

<!-- wxpay-sdk -->
<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>

SDK 中集成了一个 WXPayConfig.java 的接口,我们需要写一个实现类,存放配置信息。

public class WXPayConfigImpl implements WXPayConfig {// 设置证书,没有的话注释掉// private byte[] certData;// public WXPayConfigImpl() throws Exception {//    String certPath = "/path/to/apiclient_cert.p12";//    File file = new File(certPath);//    InputStream certStream = new FileInputStream(file);//    this.certData = new byte[(int) file.length()];//    certStream.read(this.certData);//    certStream.close();// }// set appidpublic static void setAppId(String appId) {WXPayConfigImpl.appId = "";}// set mch_idpublic static void setMchId(String mchId) {WXPayConfigImpl.mchId = "";}// set keypublic static void setKey(String key) {WXPayConfigImpl.key = "";}public InputStream getCertStream() {ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);return certBis;}// 异步通知地址public String getNotifyUrl() {return "http://www.xxx.com/wxNotify";}public int getHttpConnectTimeoutMs() {return 8000;}public int getHttpReadTimeoutMs() {return 10000;}//    IWXPayDomain getWXPayDomain() {//        return null;
//    }
}

获取 code_url

核心代码如下:

public class WXPayService {/*** 微信扫码下单 native* @param outTradeNo* @param totalFee* @param body* @param productId* @param attach 自定义参数,通知中原样返回。* @return* @throws Exception*/public static String wxUnifiedOrder(String outTradeNo, String totalFee, String body,String productId, String attach) throws Exception {WXPayConfigImpl config = null;WXPay wxpay = null;config = new WXPayConfigImpl();// 异步通知地址String notifyUrl = config.getNotifyUrl();// 使用沙箱环境// wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);// 默认使用MD5,不使用沙箱环境wxpay = new WXPay(config); Map<String, String> data = new HashMap<String, String>();// 商品描述data.put("body", body); // 商户订单号data.put("out_trade_no", outTradeNo); // 标价金额data.put("total_fee", totalFee); // 产品iddata.put("product_id", productId);// 终端IP:调用微信支付API的机器IPdata.put("spbill_create_ip", "221.12.4.52"); // 交易类型:此处指定为扫码支付data.put("trade_type", "NATIVE"); // 异步通知 urldata.put("notify_url", notifyUrl);// 自定义参数data.put("attach", attach);Map<String, String> resp = null;try {resp = wxpay.unifiedOrder(data);} catch (Exception e) {e.printStackTrace();}String codeUrl = resp.get("code_url");System.out.println("============= 微信返回结果 =============");System.out.println(resp);return codeUrl;}
}

将获取得到的 codeUrl 通过第三方库转为二维码,供用户扫码。

异步通知

异步通知的请求路径在统一下单接口中设置。

@RequestMapping("wxNotify")
public class WXController {public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception {// 拿到微信回调信息InputStream inputStream = request.getInputStream();BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));StringBuffer sb = new StringBuffer();// 将微信回调信息转为字符串String line;while ((line = in.readLine()) != null) {sb.append(line);}in.close();inputStream.close();String strXml = sb.toString();WXPayConfigImpl config = new WXPayConfigImpl();Map<String, String> map = WXPayUtil.xmlToMap(strXml);System.out.println(strXml);// 获取业务信息String outTradeNo = map.get("out_trade_no");String totalFee = map.get("total_fee");String appId = map.get("appid");String mchId = map.get("mch_id");String transactionId = map.get("transaction_id");String resultCode = map.get("result_code");String attach = map.get("attach");// 验签boolean signatureValid = WXPayUtil.isSignatureValid(strXml, config.getKey());// todo 这里写代码/* 实际验证过程建议商户务必添加以下校验:1、需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号2、判断 total_fee 是否确实为该订单的实际金额(即商户订单创建时的金额)*/PrintWriter writer = response.getWriter();// 判断签名是否正确if (signatureValid) {// 判断回调信息是否成功if ("SUCCESS".equals(map.get("result_code"))) {// todo 根据不同业务类型处理不同业务// 通知微信订单处理成功String noticeStr = setXML("SUCCESS", "");writer.write(noticeStr);writer.flush();}} else {// 通知微信订单处理失败String noticeStr = setXML("FAIL", "");writer.write(noticeStr);writer.flush();}}private static String setXML(String return_code, String return_msg) {return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";}
}

沙箱测试

  编写完代码,我们就要开始沙箱测试了。
  微信的流程是,写完代码之后,必须使用沙箱测试,对测试结果进行验收,验收通过才可以使用正式的微信商户号,否则会返回“商户无此接口权限”。
  沙箱验收过程可查看支付验收指引。

  1. 使用正式的 mch_id,商户key 来获取沙箱密钥 sandbox_signkey。传送门

  2. 通过调用接口https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey,获取验签密钥。请求方式为 POST,发送 json 字符串。可以使用 Postman 调用此接口,获取验签密钥。

    返回的结果如下

<xml><return_code><![CDATA[SUCCESS]]></return_code><retmsg><![CDATA[ALSDFJASLDFKJASLDFKJASDLFJ]]></retmsg><retcode><![CDATA[0]]></retcode>
</xml>
  1. 使用沙箱环境
// 使用沙箱环境
wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);
  1. 测试结果

    • 微信的沙箱测试 不会 发送异步通知,等待5s左右后,会在控制台打印出模拟异步通知的结果。若无通知,调用 查询订单接口进行查询。
    • 必须按照微信的支付验收用例来设置金额,否则会返回错误信息,“金额不合法”。
    • 各项支付验收用例测试结束后,按照要求调用【查询订单】进行查询,查询结束后验收结束。
    • 在官方微信号查询验收结果。验收通过后,即可使用正式账号。

查询订单

controller 层

public class WXController {public void orderQuery(String key, String appid, String mchId, String outTradeNo, String transactionId) throws Exception {WXPayConfigImpl.setKey(key);WXPayConfigImpl.setAppId(appid);WXPayConfigImpl.setMchId(mchId);WXPayConfigImpl config = new WXPayConfigImpl();Map<String, String> map = WXPayService.orderQuery(outTradeNo, transactionId);String attach = map.get("attach");String appId = map.get("appid");String totalFee = map.get("total_fee");String strXml = WXPayUtil.mapToXml(map);String resultCode = map.get("result_code");transactionId = map.get("transaction_id");System.out.println("strXml: " + strXml);}
}

service 层

    /*** 微信订单查询** @param outTradeNo* @param transactionId* @return* @throws Exception*/public static Map<String, String> orderQuery(String outTradeNo, String transactionId) throws Exception {WXPayConfigImpl config = null;WXPay wxpay = null;config = new WXPayConfigImpl();// wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true); // 使用沙箱wxpay = new WXPay(config);// 默认使用MD5,不使用沙箱环境Map<String, String> data = new HashMap<String, String>();if (!StringUtils.isEmpty(outTradeNo)) {data.put("out_trade_no", outTradeNo);}if (!StringUtils.isEmpty(transactionId)) {data.put("transaction_id", transactionId);}return wxpay.orderQuery(data);}

遇到的问题

  1. appid 与商户号绑定:
      问题描述:调用微信统一下单接口时,返回失败。错误信息为:appid 与 mch_id 不匹配。
      原因分析:appid 与 mch_id 不匹配,在 mch_id 没错的情况下,自然是 appid 出了问题。如果 appid 不合法,或者没有与 mch_id 绑定,就会报这个错。在微信商户账号界面绑定一个 appid 到 mch_id 下。
      解决方法:在微信商户账号界面绑定一个 appid 到 mch_id 下。“申请微信认证的服务号、政府或媒体类订阅号、小程序、APP、企业微信其中之一,并与商户号绑定。”
  2. 商户订单号重复:
      问题描述:在微信支付页面,用户获取了二维码之后并没有付款,或是关闭了页面,或是暂时不想支付等原因,这很常见。此时再次对同一订单进行微信支付,统一下单接口可能会报“INVALID_REQUEST 商户订单号重复”的错误。
      原因分析:同一订单号调用微信的统一下单接口时,若其他参数与首次不同,则微信认为是两个订单。两个订单使用了同一个订单号,这是不被允许的。
      解决方法:订单重入时,要求参数值与原请求一致,请确认参数问题。包括 attach 这种商户自定义参数,都必须一致。

[end]

【微信支付】微信支付之 Native 支付相关推荐

  1. 在线支付系列【14】微信支付实战篇之Native支付下单

    有道无术,术尚可求,有术无道,止于术. 文章目录 Native支付 产品介绍 业务流程图 1. 下单 2. 支付 3. 并行处理 Native下单API 案例演示 1. 环境搭建 2. 创建商户订单 ...

  2. 微信支付之PC网站(Native)支付详解

    了解支付模式 Native 适用场景: Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信"扫一扫"完成支付的模式.该模式适用于PC网站.实体店单品或订单.媒体 ...

  3. 2020微信支付之PC网站(Native)支付详解

    了解支付模式 Native 适用场景: Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信"扫一扫"完成支付的模式.该模式适用于PC网站.实体店单品或订单.媒体 ...

  4. 微信支付之Native支付H5支付JSAPI支付退款

    参考文档: https://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTIwNDU0MA==&hid=2&sn=efa76e36c5b580e41 ...

  5. 微信Native支付接入教程(2022简洁版)

    PC网站接入支付 微信支付支持完成域名ICP备案的网站接入支付功能.PC网站接入支付后,可以通过JSAPI支付或Native支付,自行开发生成二维码,用户使用微信"扫一扫"来完成支 ...

  6. PC网站微信扫码支付之Native支付(模式二)

    简介 Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信"扫一扫"完成支付的模式.该模式适用于PC网站.实体店单品或订单.媒体广告支付等场景. Native支付 ...

  7. 手机网站支付转Native支付--Android

    背景 为了节约开发成本,很多Native-H5混合App采用手机网站支付的方式去实现支付模块.但手机网站支付的网络依赖比较严重,也通常需要经过更多的验证,这种种原因导致手机网站支付的成功率比Nativ ...

  8. (用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正...

    原文:(用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正 native支付模式一demo(用微信扫的静态链接二维码)BUG修复,一共4个BUG 1.nativ ...

  9. PC网站微信扫码支付,Native支付,“当前商户号暂不支持关联该类型的appid“,“签名错误,请检查后再试““springBoot 微信支付“

    springBoot 微信支付 PC网站微信扫码支付-Native支付 一.采坑大合集 1.当前商户号暂不支持关联该类型的appid 2.签名错误,请检查后再试 二.springboot集成微信支付D ...

  10. 微信支付(一)SpringBoot 实现微信扫码支付/Native支付

    SpringBoot 实现微信扫码支付/Native支付 一.背景 在开发一个捐赠项目时须在pc端接入微信扫码支付(Native 扫码支付),在微信端接入微信公众号支付(Jsapi 支付).后端使用的 ...

最新文章

  1. Pycharm 输出中文或打印中文乱码现象的解决办法
  2. 重载(Overload)和重写(Overide)
  3. 在Windows上build Spark
  4. java字符串拆分成数组_Java StringUtils字符串分割转数组的实现
  5. matlab 中的内联函数、匿名函数和函数函数
  6. leetcode最小面积_LeetCode 题解 |力扣杯 LCP 13.寻宝
  7. 2×3卡方检验prism_何时应该使用非参数检验?
  8. java计算时间差 (日时分秒)
  9. CiteSpace学习笔记(七)——网络信息的查看
  10. Java 交互小实例:(ATM机模拟、饮料自助机模拟)
  11. 【NVMe-MI 1.2a - 1】NVM Express Management Interface介绍
  12. Java面试题自我总结
  13. SIMD<SIMT<SMT: NVIDIA GPU的并行机制
  14. 电脑qq怎么设置远程桌面连接到服务器,QQ远程协助在哪个位置 qq远程协助如何使用...
  15. 一个最低限度的国学书目
  16. 盘点百度搜索算法大全(2022最新版)
  17. luoguP5108 仰望半月的夜空 [官方?]题解 后缀数组 / 后缀树 / 后缀自动机 + 线段树 / st表 + 二分...
  18. linux下BLE(低功耗蓝牙协议)C语言开发笔记(2)---ble蓝牙扫描-连接-读写
  19. 计算机组成原理实验报告十,合肥工业大学计算机组成原理实验报告.doc
  20. 一步一步教你跑DCPDN深度学习去雾网络

热门文章

  1. 【无标题】collecting ... collected 0 items pytest解决方法
  2. Git 图标无法正常显示解决方案
  3. switch好玩吗_Switch上有什么好玩的游戏_第三方游戏有什么值得推荐的
  4. 百度云文字识别demo
  5. 浅谈 Spring 中的设计模式
  6. 制造主数据集成开发心得
  7. Win7系统怎么开启远程桌面?Win7远程桌面怎么用
  8. 阿里软件测试工程师推荐|自动化测试——HTTP之URL
  9. Java之HashMap系列--保证线程安全的方法
  10. 软件著作权申报时,使用Linux系统find命令如何统计项目行数