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

由于微信接口经常会调整,首次对接尽量参考官方文档,并以最新的文章为主,因为我试了好几种方法,最终发现都是老版有问题,用了最新版本就通了,最新版APIV3版本开发指引 - JSAPI支付 | 微信支付商户文档中心

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

  1. 小程序开通微信支付

 

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

pom.xml

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

yml配置:

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/

配置类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;
}

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();
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/zy08403/article/details/132146164