微信支付APIv3

文章目录

  • 微信支付
    • 之前我的密钥啥的都是放到配置文件里面以后可以再写一个文件
    • 基础支付APIv3介绍
    • 获取验签和HttpClient
      • APIv3证书与密钥使用说明
    • 微信支付的SDK工具
    • Native支付流程
    • 我们程序运行时的日志也可以使用log.debug
    • 在方法堆栈里面查看我们程序执行的方法调用顺序
    • 内网穿透
    • 微信支付相关的实体
    • 用户支付成功之后微信回调商户的通知接口,我们的商户自己的回调通知接口必须要进行验签
    • 用户支付成功之后微信回调商户的通知接口,一定要加锁,并且一定要处理微信发来的重复请求
    • 微信支付通知回调商户接口的时候携带的参数有密文需要我们自己解析
    • 如果用户支付成功之后微信一直没有回调商户接口,那么商户会主动调用微信的查询订单API去查询订单情况
    • 微信支付APIv3版本与微信支付APIv2版本的区别
    • 微信支付V3版本引入的SDK是何时被用到的?
    • 代码托管地址

微信支付

之前我的密钥啥的都是放到配置文件里面以后可以再写一个文件

之前,我做微信支付的时候,我把所有的商户号,商户证书序列号,商户证书私钥都放到了配置文件里面,以后像这类信息,可以和配置文件区分开,单独写一个文件,然后把它们放到这个文件里面,如下图:

在这里插入图片描述

在这里插入图片描述

然后我们如果想要取出来商户的相关信息,我们只需要通过WxPayConfig配置类的get方法就可以获取,如下图:

在这里插入图片描述

把我们的wxpay.properties变成SpringBoot的配置文件,如下图:

在这里插入图片描述

在这里插入图片描述

其实这些信息我们还是放到了配置文件里面,只不过取出来的时候,我们用的不再是@Value注解了,但其实我觉得还是使用@Value注解的这种方式比较简便。

基础支付APIv3介绍

内容:

1.引入支付参数

2.加载商户私钥

3.获取平台证书和验签器

4.获取HttpClient对象

5.Api字典和接口规则

6.内网穿透:微信向我们的开发服务器发送请求的时候,我们的开发服务器必须有一个微信可以访问的外网地址,而我们的开发服务器一般都是局域网环境的,是没有独立ip的,因此需要进行内网穿透,让微信那边可以访问到我们开发环境的接口。

7.API v3

获取验签和HttpClient

APIv3证书与密钥使用说明

微信地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_0.shtml,如下图:

img

解释上述流程:商户先使用自己的私钥对签名进行加密,然后微信端再用商户的公钥对签名解密并验证,然后微信端再拿自己的私钥对签名进行加密,接着商户端再拿微信的公钥进行解密,最上面这部分是典型的非对称加密,先拿自己的私钥加密,对方再拿我的公钥解密。

微信支付的SDK工具

在这里插入图片描述

社区源码如下图:

在这里插入图片描述

获取PrivateKey对象如下图:

在这里插入图片描述

如何获取证书对象,如下图:

在这里插入图片描述

对接微信支付SDKV3版本的时候,我们需要根据社区源码中的介绍写一个WxPayConfig配置类,用来做商户对接微信的前期准备(即自动的进行签名验证,加密解密和证书相关的操作),其实也就是需要在生成CloseableHttpClient对象之前,要自动的进行微信的验签,加密解密,敏感数据处理等一些列的操作,这样我们开发的时候就不用管这些细节了,微信的SDK已经自动的帮助我们处理了,如下图:

在这里插入图片描述

Native支付流程

官方网址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_4.shtml,如下图:

img

我们程序运行时的日志也可以使用log.debug

在这里插入图片描述

在这里插入图片描述

在方法堆栈里面查看我们程序执行的方法调用顺序

在这里插入图片描述

在这里插入图片描述

注意我们Frames里面的方法堆栈,只有当我们打断点的时候可以看到,如果不打断点是看不到方法堆栈信息的,如下图:
在这里插入图片描述

内网穿透

当微信回调我们的时候,我们本地必须要有一个公网可以访问的地址,所以我们必须要使用内网穿透,如下图:

在这里插入图片描述

先去ngrok官网下载工具,如下图:

在这里插入图片描述

在这里插入图片描述

然后双击运行我们的额ngrok.exe内网穿透工具,如下图:

在这里插入图片描述

接着去官网找两条命令依次执行,如下图:
在这里插入图片描述

注意,必须要先创建一个用户,这样登录ngrok之后才可以获取到第一条命令的token的值,如下图:

在这里插入图片描述

这两条命令的运行结果如下图:

在这里插入图片描述

正常情况下我们得到的最后的外网地址,是可以在外网访问的,但是我这里却不能,不知道是什么原因,但是原理就是这个原理,知道这个思想原理就可以了。

后来我又发现了一个特别好用的内网穿透工具,叫做快解析

首先去官网注册账号,如下图:

在这里插入图片描述

然后点击免费下载,下载之后的结果如下图:

在这里插入图片描述

双击运行之后,配置内网映射,如下图:
在这里插入图片描述

最后就可以获取到内网穿透地址了,如下图:

在这里插入图片描述

然后在商户那里设置我们的外网地址,如下图:

在这里插入图片描述

微信支付相关的实体

微信支付包括用户方,商户方,和微信方。

所以对于一个用户在某个商户使用微信付款购买了某个商品之后,都会牵涉到那些数据库表呢?

  • 首先肯定是会有一个微信订单表的,每成功进行一次订单交易,微信方都需要记录这次订单的相关信息,包括本次的微信订单号用户的基本信息(包括手机号,姓名等)商户的基本信息(包括商户号等信息)用户购买的商品的基本信息(包括商品的名字,商品的金额,商品的数量等)
  • 对于商户来说,它也是要把这笔订单的信息存放到商户订单表中的,包括本次的商户订单号,用户购买的商品的基本信息(包括商品的名字,商品的金额,商品的数量等)用户的基本信息(包括手机号,姓名等)还有退款表(用户购买商品之后可能会退款,我们也需要用一个数据库记录,这里面要包括微信退款id,微信单号,商户订单号,商品退款理由等)
  • 所以关于微信支付,我现在能想到的数据库表有商户订单表,微信订单表,商品信息表,用户信息表这四个

在这里插入图片描述

商户方有商户方自己的商户订单表和商户退款表,所以商户方有商户的商户订单号和商户退款号;

微信方有微信方自己的微信订单表和微信退款表,所以微信方有微信的微信订单号和微信退款号。

用户支付成功之后微信回调商户的通知接口,我们的商户自己的回调通知接口必须要进行验签

微信支付流程中,当微信回调商户的接口的时候,要求这个商户的这个接口必须要对发来的请求进行验签,以确保这个请求是从微信发送过来的,而不是其他的黑客伪造的,如下图:

在这里插入图片描述

在这里插入图片描述

我们程序里的验签代码,如下图:

在这里插入图片描述

用户支付成功之后微信回调商户的通知接口,一定要加锁,并且一定要处理微信发来的重复请求

官网说明,如下图:

在这里插入图片描述

首先,**先来说一下为什么要在商户的微信回调接口中加锁?**因为你假如,现在有两个微信回调请求,同时到达,这个时候商户就会进行两次处理,而本来商户如果接收到微信发来的回调请求(请求中包含用户的支付成功信息),这个时候商户会给用户进行发货,但如果商户接收了两次这样的请求,它就会发两次货,这样就会造成资金损失。怎么加锁呢?如下图:

在这里插入图片描述

在这里插入图片描述

**再来说一下怎么处理微信重复的回调请求?**本来,在商户接收微信发来的第一个回调请求的时候,会更新订单状态,更新为支付成功,然后会存放一条日志,如下图:

在这里插入图片描述

但是如果微信回调商户,商户给微信返回的结果不对,(比如说由于网络延迟,商户返回给微信的结果超过了5秒钟,那么这个时候微信就会再次回调商户)那么微信重复再发送好多次回调请求,那么商户就会更新订单状态为支付成功(微信回调商户的时候,其实就是把用户支付成功的结果告诉商户,商户再去把它的订单表的订单状态修改为支付成功),更新很多次,这倒无所谓,尽管再更新结果都是一样的;但是对于支付日志就不一样了,会存放很多条重复的信息,这就会对结果产生影响了,所以为了解决这个问题,需要在商户的支付通知接口中验证一下订单状态,如果不是未支付状态就不再更新数据库了,如下图:

在这里插入图片描述

微信支付通知回调商户接口的时候携带的参数有密文需要我们自己解析

在这里插入图片描述

resource解密后的明文信息如下图:

在这里插入图片描述

解密代码如下图:

在这里插入图片描述

如果用户支付成功之后微信一直没有回调商户接口,那么商户会主动调用微信的查询订单API去查询订单情况

微信官方的流程图如下图:

在这里插入图片描述

我们程序中是把商户主动查询微信订单这部分功能写到了定时任务里面,如果商户那边的订单一直超时未支付,到一定的时间之后,商户会去主动的去微信官方查询这笔订单,然后再根据微信方返回结果中的订单状态进行相关的处理,比如如果微信那边返回的交易状态为成功,就更新商户订单状态为成功,如果微信那边返回的交易状态为失败,那么就让商户再向微信发送一个关闭订单的请求,并更新商户订单状态为关闭。

在这里插入图片描述

微信支付APIv3版本与微信支付APIv2版本的区别

在这里插入图片描述

目前微信的大部分功能都已经用V3版的接口实现了,但是仍然有一小部分功能还没有用V3版的接口实现,但是后续会陆续的使用V3版本的接口去实现,如下图:

在这里插入图片描述

对于V3版本来说,无论我们是给微信接口传递参数还是微信给我们的响应结果都是json格式的;但是对于V2版本来说,无论我们是给微信接口传递参数还是微信给我们的响应结果都是xml格式的;所以对于V3版本我们设计到的转换主要是map集合和json的转换,而对于V2版本我们涉及到的转换主要是map集合和xml的转换。

微信支付V3版本引入的SDK是何时被用到的?

首先我们的请求行和我们最后执行请求使用的类一个是HttpPost类,一个是CloseableHttpResponse类,这两个类都是我们SpringBoot项目中自带的类,不需要我们特别的引入,当商户调用微信的统一下单API接口的时候,是如何使用这两个类的呢?如下图:

在这里插入图片描述

而现在我们使用的无论是请求行对象还是执行请求的客户端对象,都不是微信支付V3版本为我们提供的SDK中的,如下图:

在这里插入图片描述

那么现在问题来了,我们既然引入了微信支付V3版本的SDK,那么我们是什么时候使用的这个SDK的呢?如下图:

在这里插入图片描述

而虽然引入了微信的这个SDK即wechatpay,但是我们在控制器方法中发起请求,执行请求并不是运用的这个方法,而是运用的我们SpringBoot项目自带的包,只不过我们执行wxPayClient.execute(httpPost)这个方法的时候会去调用我们微信的SDK,会调用wechatpay包里面的方法,进行签名验证,加解密等系列操作,为什么会这样呢?因为我们的wxPayClient变量其实是CloseableHttpClient类,而这个类我们已经加入到了IOC中,并且从IOC容器中得到这个CloseableHttpClient类的时候,会调用微信支付V3的SDK中的方法,如下图:

在这里插入图片描述

所以如果想使用微信支付V3版本,最关键的就是要写一个WxPayConfig配置类,对CloseableHttpClient对象进行前期准备,并且把微信支付相关的证书序列号,商户号,私钥,APIv3等一系列信息都给存到这个WxPayConfig配置类里面,如下:

package com.atguigu.paymentdemo2.config;import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.*;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;@Configuration
@PropertySource("classpath:wxpay.properties") //读取配置文件
@ConfigurationProperties(prefix="wxpay") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {// 商户号private String mchId;// 商户API证书序列号private String mchSerialNo;// 商户私钥文件private String privateKeyPath;// APIv3密钥private String apiV3Key;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;// APIv2密钥private String partnerKey;/*** 获取商户的私钥文件* @param filename* @return*/private PrivateKey getPrivateKey(String filename){try {return PemUtil.loadPrivateKey(new FileInputStream(filename));} catch (FileNotFoundException e) {throw new RuntimeException("私钥文件不存在", e);}}/*** 获取签名验证器* @return*/@Beanpublic Verifier getVerifier() throws HttpCodeException, GeneralSecurityException, IOException, NotFoundException {log.info("获取签名验证器");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);// 获取证书管理器实例CertificatesManager certificatesManager = CertificatesManager.getInstance();// 向证书管理器增加需要自动更新平台证书的商户信息certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,new PrivateKeySigner(mchSerialNo, privateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));// ... 若有多个商户号,可继续调用putMerchant添加商户信息// 从证书管理器中获取verifierVerifier verifier = certificatesManager.getVerifier(mchId);return verifier;}/*** 获取http请求对象* @param verifier* @return*/@Bean(name = "wxPayClient")public CloseableHttpClient getWxPayClient(Verifier verifier){log.info("获取httpClient");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, privateKey).withValidator(new WechatPay2Validator(verifier));// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();return httpClient;}/*** 获取HttpClient,无需进行应答签名验证,跳过验签的流程*/@Bean(name = "wxPayNoSignClient")public CloseableHttpClient getWxPayNoSignClient(){//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);//用于构造HttpClientWechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()//设置商户信息.withMerchant(mchId, mchSerialNo, privateKey)//无需进行签名验证、通过withValidator((response) -> true)实现.withValidator((response) -> true);// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();log.info("== getWxPayNoSignClient END ==");return httpClient;}}

这样我们使用CloseableHttpClient执行请求的时候,如下图:

在这里插入图片描述

因为wxPayClient变量其实就是我们注入到IOC容器中的CloseableHttpRequest对象,所以在它执行execute方法的过程中就会进行和微信的验签,加解密,证书相关的一系列操作,这个时候它就会调用我们的微信支付V3版本的SDK的API了,如下图:
在这里插入图片描述

代码托管地址

https://gitee.com/xuanyuanzy/payment-demo.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/254421.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

在线支付系列【8】微信支付之注册商户号

有道无术,术尚可求,有术无道,止于术。 文章目录 前言注册商户号1. 微信扫码登录2. 创建申请单2.1 基本信息2.2 主体身份2.3 法人信息及受益人信息2.4 经营与行业信息2.5 结算账户2.6 补充信息2.7 查看申请单 签约方式一:手机签约方…

Scala函数

1.基本语法 解析main方法 def main(args: Array[String]): Unit {函数体}*def 关键字,声明一个函数 * main 方法名 * args 参数名称 * Array[String] 参数的类型 * Unit 返回值类型,相当于Java中的void,没有返回值 * {} 函数体函数省略规则 …

微信公众号注册时提示该主体注册数量已超过上限怎么办?

很多用户在注册或认证微信公众号时,遇到“该主体注册数量已超过上限”的问题,这是怎么回事呢? 原因是2018年11月16日微信官方对公众号注册数量做了调整: 1.个人主体注册公众号数量上限由2个调整为1个; 2.企业类主体注…

开通微信公众号流程所需资料及时间

2019独角兽企业重金招聘Python工程师标准>>> 序号 阶段 所需资料 所需时间 一、(企业)注册公众平台 使用未注册过微信公众号的邮箱注册、验证激活 即时二、 选择帐号类型 详情查看服务号、订阅号、企业号区别后选择类型 即时三、信息登记 选择…

支付宝、微信注册时间,轻松查看!

早几天分享过与微信年度报告查询微信使用多少天,朋友圈传播非常火爆,今天教大家一招如何查询支付宝使用多少天。 看到上图还能回想到当时的激动吗? 马上进入正题,不啰嗦,查看支付宝注册日期的方法,也超级简…

车载ECU休眠唤醒-TJA1145

前言 首先,请教大家几个小小问题,你清楚: 什么是TJA1145吗?你知道休眠唤醒控制基本逻辑是怎么样的吗?TJA1145又是如何控制ECU进行休眠唤醒的呢?使用TJA1145时有哪些注意事项呢? 今天&#xff…

oppor15x支持html吗,oppor15x配置参数详情 r15和17的亲儿子

oppor15x虽然看上去和oppor15这款手机比较相似,但是实际上,作为oppo的最新款手机,oppor15x的发布时间是在oppor17之后的,不仅如此,在外观方面,oppor15x和oppor17会更为相似,在配置方面却更偏向o…

oppo r15 android 8,OPPO R15体验:基于安卓8.1,ColorOS 5.0更好用

当目前智能手机硬件性能普遍过剩,越来越多的人们开始逐渐意识到,参数并不等于体验,反而是依附于硬件之上的操作系统很大程度上直接决定了一款智能手机的使用体验。 在当前智能手机市场,虽然说安卓系统占据了绝大部分市场份额&…

android 汇编 参数,安卓ARM汇编基础知识

ARM 是 Advanced RISC Machine 的缩写,可以理解为一种处理器的架构,还可以将它作为一套完整的处理器指令集。RISC(Reduced Instruction Set Computing) 精简指令集计算机:一种执行较少类型计算机指令的微处理器。 处理器指令集: 计算机处理命…

linux x64 寄存器 传参,Linux X86架构参数传递规则

背景 突然好奇x86架构下函数参数怎么传递的,之前只是听别人说过通过寄存器,但是怎么传,什么顺序都没有仔细研究过,也没有实际测试过,因此就想着用实践来检验一下咯。 传参顺序 在32位和64位机器上,寄存器名称不同,64位机器为rxx,32位机器为exx。传参顺序如下, 64位系统…

linux控制协程参数,Linux高性能网络:协程系列06-协程实现之切换-Go语言中文社区...

目录 6.协程实现之切换 问题:协程的上下文如何切换?切换代码如何实现? 首先来回顾一下x86_64寄存器的相关知识。x86_64 的寄存器有16个64位寄存器,分别是:%rax, %rbx, %rcx, %esi, %edi, %rbp, %rsp, %r8, %r9, %r10, …

陶瓷气体放电管参数含义详解

​很多客户反应,不太明白陶瓷气体放电管产品手册中的参数含义。不可否认,电路保护器件产品规格书手册用的语言大部分都是英文,没有一定的英文基础,还真消化不了。有时候,就算能看得懂,但是面对枯燥无味的参…

ARM寄存器及功能介绍/R0-R15寄存器

1、ARM 寄存器组介绍 ARM 处理器一般共有 37 个寄存器,其中包括: (1) 31 个通用寄存器,包括 PC(程序计数器)在内,都是 32 位的寄存器。 (2) 6 个状态寄存器…

x64 汇编 参数传递

参数传递在不同的系统上是不一样的 称作 calling convention 调用约定 windows rcx,rdx,r8,r9 用来存储整数或指针参数,按照从左到右的顺序 xmm0,1,2,3 用来存储浮点参数 其余参数会压入栈中。 linux 当参数在 6 个以内,参数从左到右依次放入寄存器:…

汇编和c语言函数的参数,C函数与汇编函数之间参数及返回值传递方法

AAPCS对ARM结构的一些标准做了定义,在这里我们只重点介绍函数调用部分,如图8所示,AAPCS为ARM的R0~R15寄存器做了定义,明确了它们在函数中的职责: 图 8 AAPCS关于ARM寄存器的定义 一、函数调用时的规则如下: 1、 父函数与子函数间的入口参数依次通过R0~R3这4个寄存器传递。…

台式计算机配置参数,整机配置参数以及性能测试_台式电脑评测-中关村在线

我们首先来看一看同方E500的硬件配置情况。 根据AIDA64所示,同方E500搭载了i5-7400处理器、8GB内存、128GB建兴固态硬盘以及1TB西部数据机械硬盘。这个配置对于商务办公机来讲是非常合理的,在性能与成本之间得到了最佳的平衡。那么具体性能表现又是如何呢?我们来继续往下看。…

此计算机核心参数,买电脑如何选CPU?这三个参数一定要看!

原标题:买电脑如何选CPU?这三个参数一定要看! CPU是电脑中的核心,也可以说是电脑的大脑,一直以来CPU与GPU那个重要都是争论不休的话题,四月份升级九代酷睿处理器的机械师笔记本拥有怎样的升级体验呢?高性能玩家该通过…

5G NR首版标准R15解读

5G定义了增强型移动宽带(eMBB)、超可靠低延迟通信(URLLC)、大规模机器类型通信(mMTC) 三大场景。针对这三大场景,在2018年6月已完成的3GPP R15标准不仅定义了5G NR(新无线&#xff0…

oppo r15 android 8,抢不到小米8,就用OPPO R15吧

抢不到小米8,就用OPPO R15吧 2018-06-09 17:10:13 17点赞 21收藏 49评论 最近小米8好像很热门,于是,突然就想买个了,反正都是刘海屏千篇一律的手机,还是10年前好,手机款式都是百花齐放,各有各特…

6.S081——补充材料——RISC-V架构中的异常与中断详解

0.briefly speaking 我在阅读Xv6源码过程中对很多概念感到困惑,想到也许会有其他人对此秉持同样的困惑,所以我将我的研究和学习过程总结下来并编篡成如下的博客。本篇博客想对RISC-V标准中有关中断和异常的概念进行一个梳理,考虑RISC-V标准的…