微信小程序集成V3支付接口

news2024/11/24 1:08:34

官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml

  1. 小程序开通微信支付

 在这里插入图片描述

 

微信小程序集成参考最新先程序集成文档

yml配置:

x-pay:
  v3:
    #微信关联的小程序的appid
    appId: wx281xxxxxxxxxxx
    #微信支付商户号
    mchId: 16480333333333
    #微信支付证书序列号 在配置api证书的界面可以找到
    serialnumber: 43442BF
    #微信支付apiv3的密钥
    apiKey3: D321123456789
    #微信支付证书
    certKeyPath: /home/key/apiclient_key.pem
    #微信支付回调商户线上地址api
    notifyUrl: https://cc/api/wxPay/notify
    #微信支付关闭订单api
    closeOrderUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close
    #微信支付小程序预下单api
    jsApiUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
    #微信支付订单查询api
    queryOrder: https://api.mch.weixin.qq.com/v3/pay/transactions/id/

配置类xie

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix="wx-pay.v3")
public class WxPayConfig {

    //appId
    private String appId;

    //商户id
    private String mchId;

    //证书序列号
    private String serialnumber;

    //商户秘钥
    private String apiKey3;

    //商户的key【API密匙】存放路径
    private String certKeyPath;

    //回调通知地址
    private String notifyUrl;

    //jsapi预支付url
    private String jsApiUrl;

    //关闭订单接口
    private String closeOrderUrl;

    //查询订单地址
    private String queryOrder;
}

servieImp实现

 public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
@Autowired
    private WxPayConfig wxPayConfig;

    //生成签名用
    private static Sign sign;
    //证书管理器
    private static CertificatesManager certificatesManager;
    private static CloseableHttpClient httpClient;
    //商户证书私钥
    private PrivateKey merchantPrivateKey;
    //证书
    private Verifier verifier;


    //初始化微信支付的参数
    @PostConstruct
    public void init() throws Exception {
        logger.info("微信支付获取支付二维码path:{} input:{}", wxPayConfig.getCertKeyPath(), new FileInputStream(wxPayConfig.getCertKeyPath()));
        //获取商户私钥
        merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(wxPayConfig.getCertKeyPath()));
        // 获取证书管理器实例
        certificatesManager = CertificatesManager.getInstance();
        sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, merchantPrivateKey.getEncoded(), null);
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(wxPayConfig.getMchId(), new WechatPay2Credentials(wxPayConfig.getMchId(),
                new PrivateKeySigner(wxPayConfig.getSerialnumber(), merchantPrivateKey)), wxPayConfig.getApiKey3().getBytes(StandardCharsets.UTF_8));
        // 从证书管理器中获取verifier
        verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
        //用于构造HttpClient
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(wxPayConfig.getMchId(), wxPayConfig.getSerialnumber(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));
        httpClient = builder.build();

}
  @Override
    public AjaxResult prePay(PayOrder payOrder) {

        logger.info("微信小程序支付JSAPI预下单开始------");
        AjaxResult ajaxResult = AjaxResult.success();
        JSONObject obj = new JSONObject();
        //应用ID
        obj.put("appid", wxPayConfig.getAppId());
        //直连商户号
        obj.put("mchid", wxPayConfig.getMchId());
        //商品描述
        obj.put("description", payOrder.getOrderRemark());
        //商户订单号
        obj.put("out_trade_no", payOrder.getTradeNo());
        //通知地址
        obj.put("notify_url", wxPayConfig.getNotifyUrl());

        //附加数据 查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
        Map<String, String> attach = new HashMap<>();
        attach.put("orderCode", payOrder.getOrderName());
        obj.put("attach", JSON.toJSONString(attach));

        //订单金额
        JSONObject amount = new JSONObject();
        amount.put("total", payOrder.getOrderAmount().intValue());
        obj.put("amount", amount);

        //支付者
        JSONObject payer = new JSONObject();
        payer.put("openid", payOrder.getOpenId());
        obj.put("payer", payer);

        logger.info("微信小程序支付JSAPI预下单请求参数:{}" + obj.toJSONString());

        HttpPost httpPost = new HttpPost(wxPayConfig.getJsApiUrl());
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(obj.toJSONString(), "UTF-8"));

        String bodyAsString;
        try {
            if (httpClient == null) {
                logger.info("微信小程序支付JSAPI预下单请求失败");
                return AjaxResult.error("预下单失败,请重试,无法连接微信支付服务器!");
            }
            //执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            bodyAsString = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            logger.info("微信小程序支付JSAPI预下单请求失败{}", e.getMessage());
            return AjaxResult.error("预下单失败,请重试!" + e.getMessage());
        }
        String prePayId = JSONObject.parseObject(bodyAsString).getString("prepay_id");
        if (prePayId == null) {
            String message = JSONObject.parseObject(bodyAsString).getString("message");
            logger.info("微信小程序支付JSAPI预下单请求失败{}", message);
            return AjaxResult.error("预下单失败,请重试!" + message);
        }
        //准备小程序端的请求参数
        ajaxResult.put("appId", wxPayConfig.getAppId());
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        ajaxResult.put("timeStamp", timeStamp);
        String nonceStr = IdUtil.fastSimpleUUID();
        ajaxResult.put("nonceStr", nonceStr);
        String packageStr = "prepay_id=" + prePayId;
        ajaxResult.put("package", packageStr);
        ajaxResult.put("signType", "MD5");
        String signString = wxPayConfig.getAppId() + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n";
        //ajaxResult.put("paySign", (sign.sign(signString.getBytes())));
        // 公共参数
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("nonceStr", nonceStr);
        resMap.put("timeStamp", timeStamp);
        resMap.put("appId", wxPayConfig.getAppId());
        resMap.put("package", packageStr);
        // 使用字段appId、timeStamp、nonceStr、package进行签名
        String paySign = signRSA(signString);
        ajaxResult.put("paySign", paySign);

        return ajaxResult;
    }

    /**
     * 微信支付v3签名 RSA签名
     *
     * @param message 要签名的字符串
     * @return
     */
    public String signRSA(String message) {
        try {
            Signer signer = new PrivateKeySigner(wxPayConfig.getSerialnumber(), merchantPrivateKey);
            Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8));
            return signature.getSign();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("签名出错:{}", e);
            return "";
        }
    }
}

controler代码:

  /**
     * 微信支付统一下单接口
     */
    @Log(title = "统一下单", businessType = BusinessType.INSERT)
    @PostMapping("/unifiedOrder")
    public AjaxResult unifiedOrder(@RequestBody PayOrder payOrder,
                                   HttpServletRequest request) {
        logger.info("payOrder:{} request:{}", payOrder, request);
        String openId = payOrder.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            return AjaxResult.error("openId不能为空");
        }
        String redisKey = "h5_order_add" + openId;
        String redisValue = openId + "_" + System.currentTimeMillis();
        try {
            redisCache.lock(redisKey, redisValue, 60);
            // 1、验证订单是否存在
            //根据订单号查询出订单信息
            QueryWrapper<PayOrder> wrapper = new QueryWrapper<>();
            wrapper.eq("trade_no", payOrder.getTradeNo());
            wrapper.eq("order_status", OrderStatusEnum.PENDING_PAYMENT.getStatus());
            PayOrder payOrder1 = iPayOrderService.getOne(wrapper);
            if (payOrder1 == null) {
                String orderNo = TenpayUtil.getTradeNoByPhone();
                payOrder.setTradeNo(orderNo);

                //更新创建人和时间
                //payOrder.setCreateBy(LoginHelper.getUserId());
                payOrder.setCreateTime(new Date());
                payOrder.setOrderAmount(payOrder.getOrderAmount());
                //payOrder.setOrderUid(LoginHelper.getUserId());
            }
            payOrder.setOrderUserName(payOrder.getOpenId());
            payOrder.setPayWay(1L);
            //支付品牌为余额
            payOrder.setPayBrand(1L);
            //消费类型为通话
            payOrder.setConsumeType(2L);
            //套餐操作类型 1为购买
            payOrder.setOperateType(1L);
            //状态为未付款
            payOrder.setOrderStatus(OrderStatusEnum.PENDING_PAYMENT.getStatus());
            iPayOrderService.saveOrUpdate(payOrder);
            // 2、开始微信支付统一下单
            //ResultMap resultMap = wxPayService.unifiedOrder(orderNo, orderNo, body);
            return iPayOrderService.prePay(payOrder);
            //return iPayOrderService.unifiedOrder(payOrder.getOpenId(),payOrder.getTradeNo(), payOrder.getOrderAmount(), payOrder.getOrderName(), request);
        } catch (Exception e) {
            logger.error("unifiedOrder error:{}", e);
            return AjaxResult.error("运行异常,请联系管理员");
        } finally {
            try {
                redisCache.unLock(redisKey, redisValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

 

 

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

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

相关文章

深度学习,计算机视觉任务

目录 计算机视觉任务 1.K近邻算法 2.得分函数 3.损失函数的作用 4.向前传播整体流程 5.反向传播计算方法 计算机视觉任务 机器学习的流程&#xff1a; 数据获取 特征工程 建立模型 评估与应用 计算机视觉&#xff1a; 图像表示&#xff1a;计算机眼中的图像&#…

实际工作中通过python+go-cqhttp+selenium实现自动检测维护升级并发送QQ通知消息(程序内测)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 首先&#xff0c;今年比较忙没有多余时间去实操创作分享文章给大家&#xff0c;那就给大家分享下博主在实际工作中的一点点内容吧&#xff0c;就当交…

2024考研408-计算机网络 第四章-网络层学习笔记

文章目录 前言一、网络层的功能1.1、网络层功能概述&#xff08;三种功能介绍&#xff09;1.2、SDN基本概念1.2.1、理解转发与路由选择1.2.1.1、转发1.2.1.2、路由选择 1.2.2、数据平面&#xff08;转发&#xff09;1.2.3、控制平面&#xff08;路由计算与选择&#xff09;实现…

九分学长大作文笔记

前言 最近看了《顾家北手把手教你雅思写作》&#xff0c;我觉得收获很少&#xff0c;逻辑感觉很乱&#xff0c;不知道为什么网上全是吹的。在Bilibili上看了九分学长&#xff0c;非常清晰&#xff0c;发现自己很多没有注意到的问题&#xff0c;下面将总结一些对我有用的部分。…

C#,OpenCV开发指南(01)

C#&#xff0c;OpenCV开发指南&#xff08;01&#xff09; 一、OpenCV的安装1、需要安装两个拓展包&#xff1a;OpenCvSharp4和OpenCvSharp4.runtime.win 二、C#使用OpenCV的一些代码1、需要加头文件2、读取图片3、在图片上画矩形框4、 在图片上画直线 一、OpenCV的安装 1、需…

使用 React Native CLI 创建项目

React Native 安装的先决条件和设置 需要掌握的知识点 掌握 JavaScript 基础知识掌握 React 相关基础知识掌握 TypeScript 相关基础知识 安装软件前需要首先安装Chocolatey。Chocolatey 是一种流行的 Windows 包管理器。 安装 nodejs 和 JDK choco install -y nodejs-lts …

接口测试——postman接口测试(三)

目录 1. postman介绍与安装 2. postman发送get请求 3. postman发送post请求 1. postman介绍与安装 安装网址&#xff1a;Postman安装教程&#xff1a;留言找我要即可 2. postman发送get请求 import pymysql from flask import Flask,request# 这里是mysql的基本连接信息 c…

cloudstack management高可用

一、环境说明 CPU&#xff1a; kunpeng 920 操作系统&#xff1a;OpenEuler 22.03 IP角色192.168.157.20mysql192.168.157.21management-server 1192.168.157.22management-server 2192.168.157.30nginx 二、部署 基础环境准备参考【cloudstack测试环境搭建】 1、部署mysql&…

音视频 FFmpeg命令行搭建

文章目录 一、配置二、测试 一、配置 以FFmpeg4.2.1 win32为例 解压ffmpeg-4.2.1-win32-shared.zip 拷⻉可执⾏⽂件到C:\Windows拷⻉动态链接库到C:\Windows\SysWOW64 注&#xff1a;WoW64 (Windows On Windows64)是⼀个Windows操作系统的⼦系统&#xff0c;被设计⽤来处理许…

替换开源LDAP,某科技企业用宁盾目录统一身份,为业务敏捷提供支撑

客户介绍 某高科技企业成立于2015年&#xff0c;是一家深耕于大物流领域的人工智能公司&#xff0c;迄今为止已为全球16个国家和地区&#xff0c;120余家客户打造智能化升级体验&#xff0c;场景覆盖海陆空铁、工厂等货运物流领域。 该公司使用开源LDAP面临的挑战 挑战1 开源…

【论文阅读】基于深度学习的时序异常检测——Anomaly Transformer

系列文章链接 论文一&#xff1a;2022 Anomaly Transformer 文章目录 理论概述代码实战 论文链接&#xff1a; Anomaly Transformer.pdf 代码链接&#xff1a; https://github.com/thuml/Anomaly-Transformer 视频讲解&#xff08;原作者禁止转载&#xff0c;联系的话侵删&am…

DC电源模块对于定制的要求主要有这几点

BOSHIDA DC电源模块对于定制的要求主要有这几点 DC电源模块是一种将交流电转换成为稳定的直流电的装置。在现代工业生产中&#xff0c;DC电源模块被广泛应用于各种电子设备中&#xff0c;例如计算机、手机、电视等。为了满足不同用户需求&#xff0c;DC电源模块的定制需求也是…

K8s中的Ingress

1.把端口号对外暴露&#xff0c;通过ip端口号进行访问 使用Service里面的NodePort实现 2.NodePort缺陷 在每个节点上都会起到端口&#xff0c;在访问时候通过任何节点&#xff0c;通过节点ip暴露端口号实现访问 意味着每个端口只能使用一次&#xff0c;一个端口对应一个应用…

pycharm中opencv库导入 cv2. 无函数提示跳出解决方法

pycharm中opencv库导入 cv2. 无函数提示跳出解决方法 1、找到当前解释器安装目录 例如&#xff1a; 2、进入D:\Python37\Lib\site-packages\cv2文件&#xff0c;进入cv2文件夹&#xff1a; 找到cv2.pyd, 把cv2.pyd复制一份&#xff0c;放到上层文件夹下&#xff0c;即site-p…

算法基础简介

目录 1、递归 2、二分查找 3、排序算法 分类 3.1、冒泡排序 3.2、选择排序 3.3、插入排序 3.4、希尔排序(高级插入排序) 3.5、归并排序 3.6、快速排序 核心思想 具体步骤 代码实现 3.7、堆排序 3.8、计数排序 3.9、桶排序 3.10、基数排序 4、字符串匹…

Pytest测试框架1

目录&#xff1a; 1.pytest简介、安装与准备2.pytest命名规则3.pycharm配置与界面化运行4.pytest测试用例结构5.pytest测试用例断言6.pytest测试框架结构7.计算器实战 1.pytest简介、安装与准备 前言 自动化测试前&#xff0c;需要提前准备好数据&#xff0c;测试完成后&am…

Linux下安装VMware虚拟机

目录 1. 简介 2. 工具/原料 2.1. 下载VMware 2.2. 安装 1. 简介 ​ VMware Workstation&#xff08;中文名“威睿工作站”&#xff09;是一款功能强大的桌面虚拟计算机软件&#xff0c;提供用户可在单一的桌面上同时运行不同的操作系统&#xff0c;和进行开发、测试 …

【Python数据容器】--- 列表的基本使用

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Python小白从入门到精通】&#x1f388; 本专栏旨在分享学习Python的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 在学…

重磅发布|《人效九宫格:劳动力效能提升指引白皮书》,人效提升完全指南

5月&#xff0c;盖雅工场发布 「人效九宫格」 后引起了各位管理者和人力资源从业者的关注讨论。为方便大家更广泛地交流学习&#xff0c;在理论基础上&#xff0c;我们筹备了 《人效九宫格&#xff1a;劳动力效能提升指引白皮书》于今日正式发布&#xff0c;以更详细地阐述企…

Spring Boot如何整合mybatisplus

文章目录 1. 相关配置和代码2. 整合原理2.1 spring boot自动配置2.2 MybatisPlusAutoConfiguration2.3 debug流程2.3.1 MapperScannerRegistrar2.3.2MapperScannerConfigurer2.3.3 创建MybatisPlusAutoConfiguration2.3.4 创建sqlSessionFactory2.3.5 创建SqlSessionTemplate2.…