springboot实现微信小程序V3微信支付功能

这篇具有很好参考价值的文章主要介绍了springboot实现微信小程序V3微信支付功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 程序开发前的准备工作,获取微信支付相关的参数

  • appId:小程序appid
  • appSecret:小程序的secret
  • mchId:商户号
  • keyPath:商户私钥路径(apiclient_key.pem)
  • certPath:证书路径(apiclient_cert.pem)
  • platFormPath:平台证书(cert.pem)
    注 : 需要通过写程序生成平台证书(见v3Get()方法)
  • apiKey3:apiv3密钥
  • serialnumber:商户证书序列号
  • notifyUrl:回调地址
    注 : 回调地址需要是线上能访问到的地址,本地的地址是无效的

1.1 在application.yml文件中填写配置信息

# 微信支付
pay:
  wechat:
    appId: xxx
    appSecret: xxx
    mchId: xxx
    # 商户私钥路径
    keyPath: D:\xx\xx\WxPay\apiclient_key.pem
    # 证书路径
    certPath: D:\xx\xx\\WxPay\apiclient_cert.pem
    platFormPath: D:\xx\xx\\WxPay\cert.pem  # 后续生成的平台证书路径
    # apiv3秘钥
    apiKey3: xxx
    # 商户证书序列号
    serialnumber: xxx
    # 回调地址
    notifyUrl: http://xxx:xx/wx/pay/payNotify # 线上地址

1.2 获取配置文件中的参数

	/**微信小程序appid**/
    @Value("${pay.wechat.appId}")
    String appid;

    /**微信小程序secretId**/
    @Value("${pay.wechat.appSecret}")
    String secret;

    /**商户号**/
    @Value("${pay.wechat.mchId}")
    String mchid;

    /**商户密钥**/
    @Value("${pay.wechat.apiKey3}")
    String mchKey;

    /**回调地址**/
    @Value("${pay.wechat.notifyUrl}")
    String notifyUrl;

    /**证书地址**/
    @Value("${pay.wechat.certPath}")
    String certPath;

    /**证书密钥地址**/
    @Value("${pay.wechat.keyPath}")
    String certKeyPath;

    /**微信平台证书**/
    @Value("${pay.wechat.platFormPath}")
    String platFormPath;

    /**证书序列号**/
    @Value("${pay.wechat.serialnumber}")
    String serialNumber;

2. 在pom.xml中引入相关依赖

		<!-- https://mvnrepository.com/artifact/com.github.javen205/IJPay-WxPay -->
        <dependency>
            <groupId>com.github.javen205</groupId>
            <artifactId>IJPay-WxPay</artifactId>
            <version>2.7.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-core -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.8.16</version>
        </dependency>

        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.7</version>
        </dependency>

3. 实现微信支付相关方法

3.1 获取平台证书

	public String v3Get() {
        // 获取平台证书列表
        try {
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethod.GET,
                    WxDomain.CHINA.toString(),
                    WxApiType.GET_CERTIFICATES.toString(),
                    mchid,
                    serialNumber,
                    null,
                    certKeyPath,
                    ""
            );
            String serialNumber = response.getHeader("Wechatpay-Serial");
            String body = response.getBody();
            int status = response.getStatus();
            log.info("serialNumber: {}", serialNumber);
            log.info("status: {}", status);
            log.info("body: {}", body);
            int isOk = 200;
            if (status == isOk) {
                JSONObject jsonObject = JSONUtil.parseObj(body);
                JSONArray dataArray = jsonObject.getJSONArray("data");
                // 默认认为只有一个平台证书
                JSONObject encryptObject = dataArray.getJSONObject(0);
                JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
                String associatedData = encryptCertificate.getStr("associated_data");
                String cipherText = encryptCertificate.getStr("ciphertext");
                String nonce = encryptCertificate.getStr("nonce");
                String serialNo = encryptObject.getStr("serial_no");
                final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, platFormPath);
                log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
            }
            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, platFormPath);
            System.out.println("verifySignature:" + verifySignature);
            return body;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    // 保存平台证书
    private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) {
        try {
            AesUtil aesUtil = new AesUtil(mchKey.getBytes(StandardCharsets.UTF_8));
            // 平台证书密文解密
            // encrypt_certificate 中的  associated_data nonce  ciphertext
            String publicKey = aesUtil.decryptToString(
                    associatedData.getBytes(StandardCharsets.UTF_8),
                    nonce.getBytes(StandardCharsets.UTF_8),
                    cipherText
            );
            // 保存证书
            cn.hutool.core.io.file.FileWriter writer = new FileWriter(certPath);
            writer.write(publicKey);
            // 获取平台证书序列号
            X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
            return certificate.getSerialNumber().toString(16).toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

3.2 微信支付

	public String wxPay(String openId, String payId, int amount) {
        //商户订单号(随机字符串)
//        String orderSn = PayKit.generateStr();
        try {
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    // APPID
                    .setAppid(appid)
                    // 商户号
                    .setMchid(mchid)
                    .setDescription("门票账单支付")
                    .setOut_trade_no(payId)
                    .setTime_expire(timeExpire)
                    .setNotify_url(notifyUrl)
                    .setAmount(new Amount().setTotal(amount))
                    .setPayer(new Payer().setOpenid(openId));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethod.POST,
                    WxDomain.CHINA.toString(),
                    WxApiType.JS_API_PAY.toString(),
                    mchid,
                    serialNumber,
                    null,
                    certKeyPath,
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            log.info("统一下单响应 {}", response);
            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, platFormPath);
            log.info("verifySignature: {}", verifySignature);
            if (response.getStatus() == HttpStatus.HTTP_OK && verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, certKeyPath);
                log.info("唤起支付参数:{}", map);
                String jsonStr = JSONUtil.toJsonStr(map);
                return jsonStr;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

3.3 微信支付回调

    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    mchKey, platFormPath);

            log.info("支付通知明文 {}", plainText);

            if (StrUtil.isNotEmpty(plainText)) {
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.4 微信退款

    public String payRefund(int amount, int qty, String outTradeNo, String outRefundNo) {
        log.info("进入退款接口------>" );
        log.info("执行操作的 原支付交易对应的商户订单号:{}", outTradeNo );

        try {
//            String outRefundNo = PayKit.generateStr();
            log.info("商户退款单号: {}", outRefundNo);
            List<RefundGoodsDetail> list = new ArrayList<>();
            RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
                    .setMerchant_goods_id(outRefundNo)
                    .setGoods_name("取消订单")
                    .setUnit_price(amount)     //金额,单位为分
                    .setRefund_amount(amount)
                    .setRefund_quantity(qty);
            list.add(refundGoodsDetail);

            RefundModel refundModel = new RefundModel()
                    .setOut_refund_no(outRefundNo)
                    .setReason("取消订单")
                    //.setNotify_url(wechatPayV3Bean.getDomain().concat("/wechat/operation/pay/refundNotify")) //退款异步回调通知
                    .setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
                    .setGoods_detail(list);
            if (outTradeNo != null && !outTradeNo.equals("")) {
                refundModel.setOut_trade_no( outTradeNo );
            }
            log.info("退款参数: {}", JSONUtil.toJsonStr(refundModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethod.POST,
                    WxDomain.CHINA.toString(),
                    WxApiType.DOMESTIC_REFUNDS.toString(),
                    mchid,
                    serialNumber,
                    null,
                    certKeyPath,
                    JSONUtil.toJsonStr(refundModel)
            );
            log.info("退款响应 {}", response);

            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, platFormPath);
            log.info("verifySignature: {}", verifySignature);

            String body = response.getBody();
            JSONObject jsonObject = JSONUtil.parseObj(body); //转换为JSON
            log.info("响应数据:" + body);

            if(response.getStatus()==200){ //退款成功,处理业务逻辑
                System.out.println("==================================");
                System.out.println("退款成功!");
            }
            if (verifySignature) {
                return response.getBody();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
        return null;
    }

3.5 订单查询

    public String queryPayResult(String payId) throws Exception{
        WechatPayHttpClientBuilder builder = getWechatPayHttpClientBuilder();
        CloseableHttpClient httpClient = builder.build();

        String result = "";
        try {
            URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"+ payId +"?mchid=" + mchid);
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            httpGet.addHeader("Accept", "application/json");
            CloseableHttpResponse response = httpClient.execute(httpGet);

            result = EntityUtils.toString(response.getEntity());
            log.info("支付信息:" + result);

            JSONObject jsonObject = JSONUtil.parseObj(result);
            String code = jsonObject.getStr("trade_state");
            log.info("支付结果:" + code);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    private WechatPayHttpClientBuilder getWechatPayHttpClientBuilder() throws Exception{
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                new FileInputStream(certKeyPath));

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();

        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(mchid, new WechatPay2Credentials(mchid,
                new PrivateKeySigner(serialNumber, merchantPrivateKey)), mchKey.getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号,可继续调用putMerchant添加商户信息

        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(mchid);

        X509Certificate certificate = verifier.getValidCertificate();
        List<X509Certificate> certificates = new ArrayList<>();
        certificates.add(certificate);

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(mchid, serialNumber, merchantPrivateKey)
                .withWechatPay(certificates);

        // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
        return builder;
    }

文章来源地址https://www.toymoban.com/news/detail-662821.html

到了这里,关于springboot实现微信小程序V3微信支付功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java实现微信小程序V3支付

    Java实现微信小程序V3支付

    2024年02月12日
    浏览(20)
  • Java实现微信小程序V3支付 (完整demo)
  • 【微信支付】java-微信小程序支付-V3接口

    【微信支付】java-微信小程序支付-V3接口

    最开始需要在微信支付的官网注册一个商户; 在管理页面中申请关联小程序,通过小程序的 appid 进行关联;商户号和appid之间是多对多的关系 进入微信公众平台,功能-微信支付中确认关联 具体流程请浏览官方文档:接入前准备-小程序支付 | 微信支付商户平台文档中心 流程走

    2024年02月06日
    浏览(21)
  • 【Java】微信小程序V3支付(后台)

    【Java】微信小程序V3支付(后台)

    目录         相关官网文档         1.需要的参数         2.引入库         3.用到的工具类         4.支付下单实现         5.支付回调 接入前准备-小程序支付 | 微信支付商户平台文档中心 微信支付-JSAPI下单 获取平台证书列表-文档中心-微信支付商户平

    2024年02月12日
    浏览(33)
  • PHP实现小程序微信支付(v3版本)

    PS:本篇文章是PHP对小程序进行微信支付v3版本的实现,仅用于对支付流程的了解,具体使用方面需要大家自行调整 小程序端JS代码: PHP类的相关代码:

    2024年02月12日
    浏览(13)
  • Python对接微信小程序V3接口进行支付,并使用uwsgi+nginx+django进行https部署

    网上找了很多教程,但是很乱很杂,并且教程资源很少且说的详细。这里就记录一下分享给大家 共分为以下几个步骤: 目录 一、开始前准备信息 二、使用前端code获取用户的openid 三、对接小程序v3接口下单 四、小程序支付的回调 五、安装并启动uwsgi 六、安装并启动nginx 七、

    2024年02月12日
    浏览(17)
  • 微信小程序完整实现微信支付功能(SpringBoot和小程序)

    微信小程序完整实现微信支付功能(SpringBoot和小程序)

    1.前言 不久前给公司实现支付功能,折腾了一阵子,终于实现了,微信支付对于小白来说真的很困难,特别是没有接触过企业级别开发的大学生更不用说,因此尝试写一篇我如何从小白实现微信小程序支付功能的吧,使用的后端是 SpringBoot 。 2.准备工作 首先,要实现支付功能

    2024年02月04日
    浏览(20)
  • Java实现微信支付v3的支付回调

    Java实现微信支付v3的支付回调

    以前都是自己手搓api的, 现在有轮子了, 尝试记录一下如何使用 我的做法是首先打开v3的代码仓库, 直接进去看看他们的文档, 可以看到这么一坨东西 开发前准备 2. 先引入maven 初始化商户配置 先从请求头中获取构建RequestParam需要的参数 初始化解析器 进行验签, 解密并转换成

    2024年02月12日
    浏览(13)
  • 小程序微信支付V3版本Java集成

    相较于之前的微信支付API,主要区别是: 遵循统一的REST的设计风格 使用JSON作为数据交互的格式,不再使用XML 使用基于非对称密钥的SHA256-RSA的数字签名算法,不再使用MD5或HMAC-SHA256 不再要求携带HTTPS客户端证书(仅需携带证书序列号) 使用AES-256-GCM,对回调中的关键信息进

    2024年02月11日
    浏览(11)
  • 微信公众号使用uniappH5、python对接微信支付V3-JSAPI的支付功能

    微信公众号使用uniappH5、python对接微信支付V3-JSAPI的支付功能

    微信公众号网页用uniapp,后台用的python,近期对接微信支付-apiv3版-jsapi支付,特此整理记录方便日后查找使用 apiv3升级后,请求体使用不用xml使用json,每次请求需要在header中添加签名,而签名需要用微信支付的商户证书私钥进行RSA加密 使用公众号进行对接流程如下 先保存公

    2024年02月02日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包