点此查看 微信公众号/微信网页/微信支付/企业微信/小程序开发合集及源代码下载

本文目录

  • 1. 场景
  • 2. 普通商户支付
    • 2.1 构建项目
    • 2.2 编写配置类
    • 2.3 网页授权获取openid
    • 2.4 编写网页发起支付
    • 2.5 后端生成订单方法
    • 2.6 支付结果通知
    • 2.7 测试
  • 3. 服务商模式支付
  • 4. 小结

1. 场景

JSAPI是微信网页发起支付,应用场景包括:

  • 用户进入商家公众号,打开某个主页面,完成支付
  • 用户点击朋友圈、聊天窗口等商家页面链接打开商家页面,完成支付
  • 用户扫描二维码后在微信浏览器中打开页面后完成支付

2. 普通商户支付

2.1 构建项目

构建springboot项目wx-server,pom.xml配置如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.5.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><groupId>cn.pandabrother</groupId><artifactId>wx-server</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><maven-jar-plugin.version>3.0.0</maven-jar-plugin.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><!-- 添加swagger2相关功能 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- 添加swagger-ui相关功能 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><!-- 微信公众号 --><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>4.1.0</version></dependency><!-- 微信支付 --><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>4.1.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

2.2 编写配置类

支付配置类编写,注意支持两种模式:普通商户模式、服务商模式,通过isServiceMode切换。

/*** 微信支付配置*/
@Configuration
public class PayConfig {public static boolean isServiceMode = false;@Beanpublic WxPayService wxService() {WxPayConfig payConfig = new WxPayConfig();// ----------------------------------------------------------------------------------普通商户if (isServiceMode == false) {payConfig.setAppId("");// 微信公众号或者小程序等的appidpayConfig.setMchId("");// 微信支付商户号payConfig.setMchKey("");// 微信支付商户密钥payConfig.setKeyPath("classpath:xxx.p12");// p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)}// ----------------------------------------------------------------------------------服务商+特约商户else if (isServiceMode == true) {payConfig.setAppId("");// 微信公众号或者小程序等的appidpayConfig.setMchId("");// 服务商商户号payConfig.setMchKey("");// 服务商商户密钥payConfig.setSubAppId("");// 服务商模式下的子商户公众账号ID,注意此处如果子商户使用了服务商的appid,则无需填写payConfig.setSubMchId("");// 服务商模式下的子商户号payConfig.setKeyPath("classpath:xxx.p12");// p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)}// 可以指定是否使用沙箱环境payConfig.setUseSandboxEnv(false);WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}
}

由于JSAPI支付还需要网页授权,所以编写公众号配置类:

/*** 微信公众平台配置*/
@Configuration
public class WxMpConfig {@Beanpublic WxMpDefaultConfigImpl wxMpDefaultConfigImpl() {WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();config.setAppId(""); // 设置微信公众号的appidconfig.setSecret(""); // 设置微信公众号的app corpSecretconfig.setToken(""); // 设置微信公众号的tokenconfig.setAesKey(""); // 设置微信公众号的EncodingAESKeyreturn config;}@Beanpublic WxMpService wxMpService() {WxMpService wxMpService = new WxMpServiceImpl();// 实际项目中请注意要保持单例,不要在每次请求时构造实例,具体可以参考demo项目wxMpService.setWxMpConfigStorage(wxMpDefaultConfigImpl());return wxMpService;}
}

2.3 网页授权获取openid

由于JSAPI支付需要用于的openid,所以我们编写控制器,实现引导用户授权并获取openid。

/*** 支付控制器*/
@Controller
@Api(tags = "支付API")
public class PayController {@Autowiredprivate WxMpService wxMpService;@Autowiredprivate WxPayService wxPayService;/*** 第一步,引导用户授权*/@GetMapping("/wxPayAuth")public String wxPayAuth(HttpServletRequest request) throws Exception {String url = "http://easypanda.oicp.io/wx-server/wxPayUserInfo";String redirectUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_BASE, null);return "redirect:" + redirectUrl;}/*** 第二步,用户授权后,回调该方法,拿到code换取access_token*/@GetMapping("/wxPayUserInfo")public String wxPayUserInfo(@RequestParam("code") String code, @RequestParam("state") String state) throws Exception {WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);String openId = wxOAuth2AccessToken.getOpenId();// 返回我们开发的网页return "redirect:" + "http://easypanda.oicp.io/wx-server/wxpay.html?openid=" + openId;}
}

2.4 编写网页发起支付

网页授权后,会进入页面wxpay.html,此时我们编写wxpay.html发起支付。

<html>
<head>
<meta charset="utf-8">
<style>
* {font-size: 1.5em;
}
</style>
</head>
<body><input type="button" value="发起支付" onclick="btnPay()"> |<script src="https://cdn.staticfile.org/jquery/1.9.1/jquery.min.js"></script><script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script><script>function getQueryVariable(variable) {var query = window.location.search.substring(1);var vars = query.split("&");for (var i = 0; i < vars.length; i++) {var pair = vars[i].split("=");if (pair[0] == variable) {return pair[1];}}return '';}function btnPay() {var param = {body : '电费',outTradeNo : '10000001',openid : getQueryVariable('openid'),spbillCreateIp : '123.135.154.64',feeType : 'CNY',totalFee : 1,//单位分tradeType : 'JSAPI',notifyUrl : 'http://easypanda.oicp.io/wx-server/wxNotify',};$.ajax({type : "POST",url : "/wx-server/wxPay",data : JSON.stringify(param),contentType : "application/json",dataType : "json",success : function(re) {console.log(re);WeixinJSBridge.invoke("getBrandWCPayRequest",{appId: re.appId, //公众号名称,由商户传入timeStamp: re.timeStamp, //时间戳,自1970年以来的秒数nonceStr: re.nonceStr, //随机串package: re.packageValue, //signType: re.signType, //微信签名方式:paySign: re.paySign //微信签名},function (res) {if (res.err_msg == "get_brand_wcpay_request:ok") {alert('支付成功!')} else if (res.err_msg == "get_brand_wcpay_request:cancel") {alert('支付取消!')} else if (res.err_msg == "get_brand_wcpay_request:fail") {alert('支付失败,请重试!')} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。}); //invoke}});}</script>
</body>
</html>

2.5 后端生成订单方法

后端接收前端请求后,生成订单,注意outTradeNo是唯一订单号,用于区分订单。

 /*** 发起支付*/@PostMapping("/wxPay")@ResponseBodypublic Object wxPay(@RequestBody WxPayUnifiedOrderRequest request) throws Exception {return wxPayService.createOrder(request);}

2.6 支付结果通知

支付成功后,微信官方会向notifyUrl 指定的地址推送支付结果,应根据该结果处理订单状态。

 /*** 支付结果通知*/@ResponseBody@PostMapping("/wxNotify")public String wxNotify(HttpServletRequest request, HttpServletResponse response) {try {String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);// 加入自己处理订单的业务逻辑,需要判断订单是否已经支付过,否则可能会重复调用String orderId = result.getOutTradeNo();String tradeNo = result.getTransactionId();String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());return WxPayNotifyResponse.success("处理成功!");} catch (Exception e) {return WxPayNotifyResponse.fail(e.getMessage());}}

2.7 测试

使用手机微信打开网页,点击【发起支付】,效果如下:

确认支付后,后台wxNotify收到通知数据如下,可以发现result_code、return_code为SUCCESS,表示支付成功。

<xml><appid><![CDATA[wxa0168d6e3b5547]]></appid>
<bank_type><![CDATA[ICBC_CREDIT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<mch_id><![CDATA[16147815]]></mch_id>
<nonce_str><![CDATA[1644396002773]]></nonce_str>
<openid><![CDATA[oINiq6UqTiKqfXN3H6RmeKvvRn]]></openid>
<out_trade_no><![CDATA[10000001]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[100B0932A6D10D31126F7F18EBE021]]></sign>
<time_end><![CDATA[20220209164017]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[42000014062022020952146956]]></transaction_id>
</xml>

3. 服务商模式支付

修改配置类,启用服务商模式,并配置服务商模式需要的参数。

/*** 微信支付配置*/
@Configuration
public class PayConfig {public static boolean isServiceMode = true;@Beanpublic WxPayService wxService() {WxPayConfig payConfig = new WxPayConfig();// ----------------------------------------------------------------------------------普通商户if (isServiceMode == false) {payConfig.setAppId("");// 微信公众号或者小程序等的appidpayConfig.setMchId("");// 微信支付商户号payConfig.setMchKey("");// 微信支付商户密钥payConfig.setKeyPath("classpath:xxx.p12");// p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)}// ----------------------------------------------------------------------------------服务商+特约商户else if (isServiceMode == true) {payConfig.setAppId("");// 微信公众号或者小程序等的appidpayConfig.setMchId("");// 服务商商户号payConfig.setMchKey("");// 服务商商户密钥payConfig.setSubAppId("");// 服务商模式下的子商户公众账号ID,注意此处如果子商户使用了服务商的appid,则无需填写payConfig.setSubMchId("");// 服务商模式下的子商户号payConfig.setKeyPath("classpath:xxx.p12");// p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)}// 可以指定是否使用沙箱环境payConfig.setUseSandboxEnv(false);WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}}

再次通过微信客户端发起支付,此时会发现商户名称发生了变化,此时是服务商模式下的特约商户的名字。

4. 小结

JSAPI支付通过微信网页发起,支付成功后支付结果发送给指定的地址,我们通过后端接收支付结果来修改订单状态。

服务商模式下,只需要修改配置即可。

微信支付开发(5)--JSAPI支付开发详解相关推荐

  1. 微信小程序开发【六】-- wxss详解

    系列文章目录 微信小程序开发[一]-- 初识小程序 传送门 微信小程序开发[二]-- 小程序入门 传送门 微信小程序开发[三]-- 项目结构概述 传送门 微信小程序开发[四]-- 配置详解 传送门 微 ...

  2. PHP开发中常见的安全问题详解和解决方法

    PHP开发中常见的安全问题详解和解决方法 参考文章: (1)PHP开发中常见的安全问题详解和解决方法 (2)https://www.cnblogs.com/walblog/articles/83313 ...

  3. iOS 开发:『Runtime』详解(二)Method Swizzling

    本文用来介绍 iOS 开发中『Runtime』中的黑魔法Method Swizzling. 通过本文,您将了解到: Method Swizzling(动态方法交换)简介 Method Swizzlin ...

  4. 必过SafetyNet!以MIUI开发版系统为例详解Android设备通过SafetyNet校验方法

    必过SafetyNet!以MIUI开发版系统为例详解Android设备通过SafetyNet校验方法 作者 梓沐啊_(KylinDemons) 版权声明 Copyright © 2021 KylinD ...

  5. 【区块链开发入门】(四) Truffle详解篇2

    由于本篇篇幅较长,因此转为两篇文章.Truffle详解篇篇1请见:link 目录导航页 [区块链开发入门](一) 以太坊的搭建与运行 [区块链开发入门](二) 以太坊的编程接口 [区块链开发入门](三 ...

  6. android什么控件能够输入多行文字,Android开发:文本控件详解——EditText(一)基本属性...

    一.简单实例: EditText输入的文字样式部分的属性,基本都是和TextView中的属性一样. 除此之外,EditText还有自己独有的属性. 二.基本属性: hint 输入框显示的提示文本 te ...

  7. 降低游戏陪玩平台系统前端开发复杂度的方式详解

    优秀的程序员总是能优雅的组织自己的代码,编写思路清晰,组织结构划分合理,从小的功能组件,到大的模块结构,都能通过合理巧妙的搭配,化复杂为简单,并且提升游戏陪玩平台系统运行效率,提高游戏陪玩平台系统代码 ...

  8. Android NDK开发之旅(3): 详解JNI数据类型与C/C++、Java之间的互调

    Android NDK开发之旅(3):详解JNI数据类型与C/C++.Java之间的互调 (码字不易,转载请声明出处:http://blog.csdn.net/andrexpert/article/d ...

  9. 微信小程token_微信小程序url与token设置详解

    微信小程序url与token设置详解 新浪云应用sae的代码里创建一个weixin.php文件,写入以下代码 isValid(); class wechatAPI { public function ...

  10. 小程序setdata优化_微信小程序 setData的使用方法详解

    微信小程序 setData的使用方法详解 微信小程序 setData的使用方法详解 最近在使用微信小程序的setData时,遇到了以下问题.如下: 官网文档在使用setData()设置数组对象的某个元 ...

最新文章

  1. BZOJ 2135 刷题计划(贪心,求导,二分)【BZOJ 修复工程】
  2. JavaMail学习之一-邮件传输协议
  3. “智慧北京”让生活更美好
  4. md5后得到的32位字符串存储到mysql中太占空间了_好看!快收藏:非常完整的 MySQL 规范...
  5. 遗传算法求函数最大值实验_小知识:什么是遗传算法
  6. Linux(centOS)手动安装删除Apache+MySQL+PHP+Memcached原创无错版
  7. 小小的 API 如何创造出 3.5 亿美元的价值?
  8. BZOJ 1606: [Usaco2008 Dec]Hay For Sale 购买干草(动态规划)
  9. R语言自然语言处理:关键词提取与文本摘要(TextRank)
  10. 关于constexpr
  11. 遍历Map集合的四种方式
  12. 学术界布局区块链,日本东京大学开始提供区块链课程
  13. 教师测评系统php,校无忧教师评价系统 v2.6
  14. Ionic3 Demo
  15. Usability Testing Demystified
  16. html class生效顺序,HTML5 CSS3小猪日历(动物挂历)
  17. 一:部署harbor镜像仓库
  18. usb无线网卡和U盘同时使用
  19. IEEE access投稿详细步骤
  20. 干货:Spark RDD写入HBase 优化

热门文章

  1. html5制作购物车页面,利用html来制作一个简单美观的购物车界面
  2. 机器学习:算法中的泛化误差、偏差、方差、噪声的理解(超详细)
  3. python实现阶乘的几种方法
  4. Java8 Stream 流API总结
  5. latex 参考文献 natbib, biblatex 引用网页,超链接
  6. useradd与adduser命令的区别
  7. 4面阿里拿到P7Offer,面试真题解析
  8. 【飞桨领航团AI达人养成营】课节1: Python计算基础学习笔记
  9. 第4课 弹性之城--故事卡--弹城精灵口中的故事
  10. 【2019.06.16】Django + 微信小程序 实现微信小程序1——小程序基本信息,开发规范