微信小程序支付V2版之JSAPI支付

发布时间 2023-08-09 09:55:01作者: 大西瓜3721

文章目录

  • 一、微信支付环境搭建
    • 1 企业微信小程序的开通
    • 2. 企业商户号的开通
    • 3 小程序号与商户号关联
  • 二、微信小程序的支付流程
    • 1 `JSAPI`支付流程
    • 2 微信小程序获取`openid`
    • 3 微信小程序下单
    • 4 后台服务程序对订单的处理
    • 5 微信小程序发起支付
    • 6 支付结果的通知
  • 三、微信支付API的使用
    • 1 导入微信官方提供的SDK
    • 2 控制器
  • 四、总结

 


一、微信支付环境搭建

  • 微信支付必须开通两个账号:微信小程序账号 与微信商户平台账号
  • 涉及到支付功能只能是公司,个人是不能玩支付功能,即个人的微信小程序号是不能开通微信支付功能的
  • 支付在线文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

1 企业微信小程序的开通

  • 要认证:认证需要缴费
  • 获取appid:小程序的身份标识
  • 生成secret:生成后需要保存后
    在这里插入图片描述
  • 开通支付功能
    在这里插入图片描述
  • 关联商户号
    在这里插入图片描述

2. 企业商户号的开通

  • 要认证
  • 获取商户号:mch_id
  • 设置商户API秘钥:mch_key
  • APPID授权
  • 配置支付接口

3 小程序号与商户号关联

在这里插入图片描述


二、微信小程序的支付流程

JSAPI支付流程

  • 微信小程序JSAPI支付的在线文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4
    在这里插入图片描述

  • 一个简单的流程如下
    在这里插入图片描述

  • 在实际项目开发中分为小程序开发与后台服务器的开发

2 微信小程序获取openid

  • 微信小程序的支付需要使用到openid,获取openid有两种方式
    • 微信小程序携带code登录开发者服务器开发者服务器请求微信服务器获取到openid,再将openid响应给微信小程序
    • 直接使用微信小程序的云开发功能获取到openid
  • 使用上述的第一种方式拿到openid,流程如下:
    在这里插入图片描述
  • 微信小程序的登录代码
    wx.login({ // 1. 微信小程序 → 微信服务器: 拿到临时凭证 codesuccess: res => { // 2. 微信服务器 → 微信小程序: 返回结果if(res.code) {wx.request({ // 3. 微信小程序 → 开发者服务器: 目的: 使用code换取openidurl: 'http://ycom.free.idcfengye.com/wechat/requestOpenId',data: { // 请求参数code:res.code},success: res=>{ // 4. 开发者服务器 → 微信小程序: 返回结果if(res.data.openid) {wx.setStorage({ // 5. 将开发者服务器返回的opneid存储起来, 之后的支付需要用到openidkey: 'openid',data: res.data.openid})}}})} }});
  • 开发者服务器后代代码
    /*** 小程序请求openid* 获取 openid 微信小程序的身份标识* 1. 小程序发送请求给开发者服务器* 2. 开发者服务器发送请求给微信服务器* 3. 微信服务器响应开发者服务器的请求* 4. 开发者服务器响应微信小程序的请求* 5. 微信小程序拿到了openid** @param code 临时code, 小程序传过来的* @return 给小程序返回openid*/@GetMapping("/requestOpenId")@ResponseBodyprivate Object requestOpenId(String code) {CloseableHttpClient httpclient = null;CloseableHttpResponse response = null;try {httpclient = HttpClients.createDefault();URI uri = new URIBuilder("https://api.weixin.qq.com/sns/jscode2session").addParameter("appid", Constants.appid).addParameter("secret", Constants.appSecret).addParameter("js_code", code).addParameter("grant_type", "authorization_code").build();HttpGet httpGet = new HttpGet(uri);// 执行请求: 开发者服务器给微信服务器发送GET请求response = httpclient.execute(httpGet);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == 200) {// 解析响应数据String content = EntityUtils.toString(response.getEntity(), "UTF-8");JSONObject obj = (JSONObject) JSONObject.parse(content);obj.put("session_key", null); // session_key不需要暴露给微信小程序, 所以置nullreturn obj;}} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpclient != null) {try {httpclient.close();} catch (IOException e) {e.printStackTrace();}}}return null;}

3 微信小程序下单

  • 微信小程序下单的意思就是微信小程序请求开发者服务器:我有一笔款需要付给微信
    在这里插入图片描述

4 后台服务程序对订单的处理

    /*** 微信小程序下单请求* 1. 微信小程序发送请求给开发者服务器: 下单*      |- openid是必须的参数*      |- 金额: 微信小程序可以传进来也可以不传, 在这里金额是由服务端计算得到的* 2. 开发者服务器经过一顿操作后, 按照要求响应对应的数据给微信小程序* 3. 然后微信小程序拿着这一堆数据去请求微信服务器进行真正的付款操作** @param request* @param openid* @return* @throws Exception*/@GetMapping("/placeOrder")@ResponseBodypublic Object placeOrder(HttpServletRequest request, String openid) throws Exception {// 获取请求的IP地址String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}if (ip.indexOf(",") != -1) {String[] ips = ip.split(",");ip = ips[0].trim();}// 核心在这里return wxPayService.wxPay(openid, ip);}
  • 开发者服务器对微信小程序订单的处理代码
    public Map<String, String> wxPay(String openid, String ip) throws Exception {// 1. 拼接统一下单地址参数Map<String, String> paraMap = new HashMap<>();paraMap.put("body", "车库试验塔收费测试"); // 商家名称-销售商品类目 String(128)paraMap.put("openid", openid); // 用户登录的openidparaMap.put("out_trade_no", UUID.randomUUID().toString().replaceAll("-", ""));// 订单号, 每次都不同paraMap.put("spbill_create_ip", ip); // ip地址paraMap.put("total_fee", "1"); // 支付金额paraMap.put("trade_type", "JSAPI"); // 支付类型// 2. 通过MyWXPayConfig创建WxPay对象, 用于支付请求final String SUCCESS_NOTIFY = "http://ycom.free.idcfengye.com/wechat/notify"; // 微信小程序支付成功后的回调接口WXPayConfig wxPayConfig = new MyWXPayConfig();WXPay wxPay = new WXPay(wxPayConfig, SUCCESS_NOTIFY, false, false);// 3. 开发者服务器请求微信服务器: 统一下单// wxPay.fillRequestData(paraMap)是将上述的参数用key=value的形式和MCH_KEY一起加密为sign: 第一次加密Map<String, String> map = wxPay.unifiedOrder(wxPay.fillRequestData(paraMap), 15000, 15000);// 4. 向微信服务器发送统一下单请求后,得到响应, 从响应的结果中获取 预支付id, 即prepay_id// 将微信服务器返回的结果进行第二次加密String prepayId = map.get("prepay_id");Map<String, String> payMap = new HashMap<>();payMap.put("appId", WechatConstants.APPID);payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");payMap.put("nonceStr", WXPayUtil.generateNonceStr());payMap.put("signType", WXPayConstants.HMACSHA256);payMap.put("package", "prepay_id=" + prepayId);String paySign = WXPayUtil.generateSignature(payMap, WechatConstants.MCH_KEY, WXPayConstants.SignType.HMACSHA256);payMap.put("paySign", paySign);// 5. 返回最终的结果: 这个结果最终返回给微信小程序return payMap;}

5 微信小程序发起支付

在这里插入图片描述

6 支付结果的通知

在这里插入图片描述

  • 开发者服务器支付通知回调的接口:

三、微信支付API的使用

1 导入微信官方提供的SDK

  • 微信支付V2版的API其实很简单,因为微信官方提供了相关的API:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
    在这里插入图片描述
    在这里插入图片描述
  • 使用微信官方提供的SDK有两种方式:
    • 使用Maven引入SDK的依赖
    • 下载SDK与DEMO,将里面的源码拷贝到自己的工程中:com.github.wxpay.sdk,同时还需要在pom.xml文件中配置<license>
在这里插入图片描述在这里插入图片描述
  • 我们需要实现WXPayConfig类,因为在统一下单中需要使用到该类的实现类对象,那我们就必须提供一个该接口的实现类:实现如下
public class WechatPayConfig extends WXPayConfig {/*** 获取微信小程序的appid** @return*/@Overridepublic String getAppID() {return WechatConstants.APPID;}/*** 获取商户id** @return*/@Overridepublic String getMchID() {return WechatConstants.MCH_ID;}/*** 获取商户的秘钥** @return*/@Overridepublic String getKey() {return WechatConstants.MCH_KEY;}/*** 不需要证书** @return*/@Overridepublic InputStream getCertStream() {return null;}/*** 域名配置** @return*/@Overridepublic IWXPayDomain getWXPayDomain() {return new IWXPayDomain() {@Overridepublic void report(String domain, long elapsedTimeMillis, Exception ex) {}@Overridepublic DomainInfo getDomain(WXPayConfig config) {return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);}};}
}

2 控制器


四、总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。