微信扫码支付记录


前言

本文记录了微信扫码支付(API V3版本native支付 Java版)实操过程。客户需求:业务系统内根据商品价格自动生成支付二维码,用户扫码后调启微信支付。查阅了微信支付官方文档,Navite支付产品符合需求预期。这里直接使用的微信支付提供的SDK,免去了自己加签验签的烦恼。


一、native支付是什么?

Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。详见微信官网介绍

https://pay.weixin.qq.com/docs/merchant/products/native-payment/introduction.html

二、使用步骤

1.接入前准备

  1. merchantId 商户id
  2. apiV3Key V3版API密钥key
  3. appId 微信应用标识,公众号/小程序/APP
  4. 支付证书
    支付证书
  5. merchantSerialNumber 商户证书序列号

2.引入依赖

```
<dependency>
        <groupId>com.github.wechatpay-apiv3</groupId>
        <artifactId>wechatpay-java</artifactId>
        <version>0.2.14</version>
</dependency>
```

3.证书配置

本文将微信证书放入到项目的resources文件夹下
在这里插入图片描述

4.代码设置

新建一个名为PayController.java的Controller类,代码如下


    //微信商户号和密钥
    private String merchantId = "16xxxxxxxx";
    private String apiV3Key = "D5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    private String appId = "wxxxxxxxxxxxxx";
	//支付回调地址
    private final static String notifyUrl = "https://xxxxx/api/pay/v1/payCallBack";
    private String privateKeyName = "wechat/apiclient_key.pem";
    private String privateKeyString = "";
    private PrivateKey privateKey;
    /**
     * 商户证书序列号
     */
    private String merchantSerialNumber = "407xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    Config config;
    public PayController() {
        try {
            ClassPathResource classPathResource = new ClassPathResource(privateKeyName);
            privateKeyString = IOUtils.toString(classPathResource.getInputStream(), "utf8");
            config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(merchantId)
                    .privateKey(privateKeyString)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
            privateKey = getPrivateKey(privateKeyName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ResultData createUserOrder(@RequestBody PayOrderDTO payOrderDTO) {
        try {
            // 构建service
            NativePayService service = new NativePayService.Builder().config(config).build();

            //构建支付请求参数
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
			//微信支付单位为分,将元转为分
            amount.setTotal(金额 * 100));
            request.setAmount(amount);
            request.setAppid(appId);
            request.setMchid(merchantId);
            request.setDescription(productDO.getName());
            request.setNotifyUrl(notifyUrl);
            Date date = new Date();
            request.setOutTradeNo("hxt" + DateUtil.formatDate(date, "yyyyMMddHHmmssSSS") + RandomUtil.randomNumbers(6));
            // 调用下单方法,得到应答
            PrepayResponse response = service.prepay(request);
            // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("order_id", request.getOutTradeNo());
            hashMap.put("qrcode_url", response.getCodeUrl());
            return new ResultData(true, hashMap);

        } catch (Exception e) {
            LOGGER.error("createUserOrder error: {}", e.getMessage());
            return new ResultData(false, e.getMessage(), "");
        }

    }

调用微信接口成功后,正常返回

{
“code_url” : “weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00”
}

将此code_url的内容在前端转换成二维码,通过微信扫码即可调启微信支付,如下图
在这里插入图片描述
在这里插入图片描述

5.前端调用

前端调用接口生成二维码展示即可,这不是本文的重点。

6.支付回调

上文中提到的支付回调地址payCallBack代码如下

@PostMapping(value = "/v1/payCallBack")
    public ResultData payCallBack(@RequestBody String body) {
        try {
            LOGGER.error("payCallBack body: ", body);
            JSONObject jsonObject = JSONObject.parseObject(body);
            if (jsonObject.size() > 0) {
                NotifationDO notifationDO = jsonObject.toJavaObject(NotifationDO.class);

                String ciphertext = jsonObject.getJSONObject("resource").getString("ciphertext");
                String associated_data = jsonObject.getJSONObject("resource").getString("associated_data");
                String nonce = jsonObject.getJSONObject("resource").getString("nonce");
                String decryText = decryptText(ciphertext, associated_data, nonce);
                JSONObject decryJsonObject = JSONObject.parseObject(decryText);
				//业务代码处理
				......

            }

        } catch (Exception e) {
            LOGGER.error("payCallBack error: {}", e.getMessage());
        }
        return new ResultData(ResultStatusEnum.SUCCESS.getCode(), "");
    }

为了保证安全性,微信支付在回调通知,对关键信息进行了AES-256-GCM加密。需要对返回的数据进行解密后,做相应的业务处理

    private String decryptText(String ciphertext, String associated_data, String nonce) {

        try {
            String decryptData = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
            return decryptData;
        } catch (Exception e) {
            return e.getMessage();
        }
    }

总结

以上就是对微信扫码支付介绍,实际项目中不能完全依赖支付回调,应结合查询订单接口主动查询订单状态,完成下一步的业务逻辑。
查询订单可通过微信支付订单号和商户订单号两种方式查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xs_2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值