欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

PC网站微信扫码支付

发布时间:2024/3/26 编程问答 168 豆豆
生活随笔 收集整理的这篇文章主要介绍了 PC网站微信扫码支付 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

PC网站微信扫码支付(v3) Native支付对接流程以及注意事项

一.需要的参数

(1)获取商户号(mchID)

微信商户平台: https://pay.weixin.qq.com/
场景:Native支付
步骤:提交资料 =>签署协议 => 获取商户号

(2)获取APPID

微信公众平台: https://mp.weixin.qq.com/
步骤:注册服务号=>服务号认证 =>获取APPID => 绑定商户号(商户产品中心的APPID账号管理中把APPID配置进去)

(3)获取APIv3秘钥(v3key)

APIv3版本的接口需要此秘钥
步骤:登录商户平台=>选择账户中心=>安全中心=>AP安全=>设置APIV3密钥随机感码生成工具: https://suijimimashengcheng.bmcx.com/

(4)申请商户API证书(可通过代码拉取证书,需要拿到证书序列号,和私钥文件)

APIv3版本的所有接口都需要,步骤:登录商户平台=>选择账户中心=>安全中心=>API安全=>申请API证书
=>证书管理=>申请新证书=>下载证书工具

代码获取证书需要:证书序列号(mch_serial_no)

如何查看证书序列号?
登录商户平台:API安全]=>API证书 =>查看证书,可查看商户API证书序列号。

私钥文件是下载证书pem结尾的文件,如下:

可以把此文件放到支付项目的resources文件下,用以下方式读取:

/*** 获取商户的私钥文件* @param filename* @return*/ private PrivateKey getPrivateKey(String filename){try {return PemUtil.loadPrivateKey(new FileInputStream(filename));} catch (FileNotFoundException e) {throw new RuntimeException("私钥文件不存在", e);} }

也可以放在服务器,定义privateKeyPath变量参数,用一下方式读取:

/*** 获取商户的私钥文件*/ public PrivateKey getPrivateKey() {try {URL url=new URL(privateKeyPath);URLConnection connection=url.openConnection();InputStream stream=connection.getInputStream();return PemUtil.loadPrivateKey(stream);} catch (Exception e) {throw new RuntimeException("私钥文件不存在", e);} }
(5)微信服务器IP
"wxIp":"https://api.mch.weixin.qq.com"
(6)回调路径:回调路径不需要在开放平台配置,如果项目有网关,只需在网关开放回调接口

例如: "notify":"http://gateway.jkcgy.com/payment/v1/wxpay/native/notify"

http://gateway.jkcgy.com:就是你网关访问地址

payment/v1/wxpay/native/notify:就是你的回调接口路径

可以在浏览器进行测试,如果出现如下:则回调路径开放成功。

二.可参考资料

JAVA对接Demo:https://github.com/LXT2017/JavaLearnProject ,可以拉到本地参考

对接中遇到问题可以在微信开放社区进行搜索,社区地址:https://developers.weixin.qq.com/community/pay/article

三.配置参数存入数据库

因为支付参数对安全要求高,所以一般在开发中不以配置文件的形式存放支付参数,需要把支付参数存放到数据库。

可以把所有的参数配置成一个json字段,如下:

json字段格式:

{"mchID":"xxxxx","appID":"xxxxxxx","mch-serial-no":"xxxxxx","wxIp":"https://api.mch.weixin.qq.com","privateKeyPath":"https://服务器地址/apiclient_key.pem在服务器的地址","v3key":"xxxxxxx","notify":"xxxxxxx","notify_test":"xxxxx","notify_prod":"xxxxxxx" }

在数据库配置好参数后,可以在代码中配置一个WxPayConfig的配置类,用来读取数据库参数。

读取数据库参数可以通过实现:InitializingBean,重写afterPropertiesSet(),InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,

凡是继承该接口的类,在bean的属性初始化后都会执行该方法。从而配置全局可引用的参数。


完整WxPayConfig配置,包含拉取证书,跳过验签的一些配置:

@Configuration @Data @Slf4j public class WxPayConfig implements InitializingBean {@Resourceprivate WxPaymentCfgMapper wxPaymentCfgMapper;// 商户号private String mchId;// 商户API证书序列号private String mchSerialNo;// 商户私钥文件private String privateKeyPath;// APIv3密钥private String apiV3Key;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;/*** 获取商户的私钥文件* @param* @return*/public PrivateKey getPrivateKey(){try {URL url = new URL(privateKeyPath);URLConnection connection = url.openConnection();InputStream stream = connection.getInputStream();return PemUtil.loadPrivateKey(stream);} catch (Exception e) {throw new RuntimeException("私钥文件不存在", e);}}/*** 获取签名验证器* @return*/@Beanpublic ScheduledUpdateCertificatesVerifier getVerifier(){log.info("获取签名验证器");//获取商户私钥PrivateKey privateKey = getPrivateKey();//私钥签名对象PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);//身份认证对象WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);// 使用定时更新的签名验证器,不需要传入证书ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8));return verifier;}/*** 获取HttpClient,无需进行应答签名验证,跳过验签的流程*/@Bean(name = "wxPayNoSignClient")public CloseableHttpClient getWxPayNoSignClient(ScheduledUpdateCertificatesVerifier verifier){//获取商户私钥PrivateKey privateKey = getPrivateKey();//用于构造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;}@Overridepublic void afterPropertiesSet(){WxPaymentCfg wxPayment = wxPaymentCfgMapper.selectById(1);String json = wxPayment.getJson();WxPaymentCfgDto wxPayments = JSONObject.parseObject(json, WxPaymentCfgDto.class);this.setMchId(wxPayments.getMchId());this.setAppid(wxPayments.getAppId());this.setPrivateKeyPath(wxPayments.getPrivateKeyPath());this.setApiV3Key(wxPayments.getV3key());this.setDomain(wxPayments.getWxIp());this.setNotifyDomain(wxPayments.getNotify());this.setMchSerialNo(wxPayments.getMchSerialNo());} }

四.对接注意事项

一.回调问题

回调通知:

​同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知

确保回调URL是外部可正常访问的,且不能携带后缀参数。

回调通知重复问题:

重复通知的时候,微信的请求id是一样的,用这个做请求幂等性处理响应给微信的内容不规范 或者 超过5秒没响应。

并发下重复通知问题:
可以通过可重入锁 ReentrantLock的tryLock()解决

private final ReentrantLock lock = new ReentrantLock();/**在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱**///尝试获取锁:成功获取则立即返回true,获取失败则立即返回false。不会一直等待锁的释放if (lock.tryLock())

测试的问题:

如果有多个未响应的,则测试的请求id,可能有之前的请求继续回调过来 .

二.金额转换问题

微信支付的金额单位是分,必须转换为Int类型

Integer totalfree = order.getTotalAmount().multiply(new BigDecimal(100)).stripTrailingZeros().intValue();
三.退款原因问题

微信退款原因官方规定不能超过80个字,可以做一个截取。

五.核心流程

第一步 获取报文

第二步 验证签名(确保是微信传输过来的)

第三步 解密(AES对称解密出原始数据)

第四步 处理业务逻辑

第五步 响应请求

总结

以上是生活随笔为你收集整理的PC网站微信扫码支付的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。