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 {

    @Resource
    private WxPaymentCfgMapper wxPaymentCfgMapper;
    // 商户号
    private String mchId;
    // 商户API证书序列号
    private String mchSerialNo;
    // 商户私钥文件
    private String privateKeyPath;
    // APIv3密钥
    private String apiV3Key;
    // APPID
    private 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
     */
    @Bean
    public 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();
        //用于构造HttpClient
        WechatPayHttpClientBuilder 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;
    }

    @Override
    public 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对称解密出原始数据)

第四步 处理业务逻辑

第五步 响应请求

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值