WeChat mini program integrates V3 payment interface

Since the WeChat interface is often adjusted, try to refer to the official documents for the first time, and focus on the latest articles. Because I tried several methods, and finally found that there were problems with the old version. I used the latest version and it worked. The latest version APIV3 Version Development Guide - JSAPI Payment | WeChat Payment Merchant Document Center .

Official document address: https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml

  1. Open WeChat payment in mini program

 

WeChat Mini Program Integration Reference Latest Program Integration Document

pom.xml

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

yml configuration:

weixin-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/

Configuration class xie

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

@Data
@Component
@ConfigurationProperties(prefix="weixin-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;
}

serveImpimplementation

 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 "";
        }
    }
}

controller code:

  /**
     * 微信支付统一下单接口
     */
    @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();
            }
        }
    }

Guess you like

Origin blog.csdn.net/zy08403/article/details/132146164