简简单单得微信支付APP篇

背景

目前大多数APP收款方式都依赖于第三方支付,其中微信得受众是最广泛得,本文讲讲如何简单得调用微信支付;

微信支付官方API

微信APP官方文档

接入准备

成为商家

配置相关信息

配置证书
配置V3key
配置一下证书和V3key,简简单单,证书生成工具跟着微信指引走就行证书申请指引

后端拉起微信支付

可以看到API中得 APP下单 需要得一些参数 然后我们写个demo

先简单得写个微信支付的model
package com.meet.utils.wechat.model;

import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author Awei
 * @Date 2023 02 16 16 10
 * @Desc 微信APP支付model
 **/
@Data
@NoArgsConstructor
public class WechatPayModel {

    protected String appid;

    protected String mchid;

    protected String description;

    protected String out_trade_no;

    protected String notify_url;

    protected WechatAmount amount;

    /**
     * @param appid        由微信生成的应用ID,全局唯一。请求基础下单接口时请注意APPID的应用属性,应为公众号的APPID
     * @param out_trade_no 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
     * @param mchid        直连商户的商户号,由微信支付生成并下发。
     * @param description  商品描述
     * @param notify_url   通知URL必须为直接可访问的URL,不允许携带查询串,要求必须为https地址。
     */
    public WechatPayModel(String appid, String out_trade_no, String mchid, String description, String notify_url,
                          Long total) {
        this.appid = appid;
        this.out_trade_no = out_trade_no;
        this.mchid = mchid;
        this.description = description;
        this.notify_url = notify_url;
        this.amount = new WechatAmount(total, "CNY");
    }
}
然后简单的写个配置类
package com.meet.utils.wechat;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Awei
 * @Date 2023 02 16 15 48
 **/
@Slf4j
@Data
@Configuration
public class WechatConfig {

	/**
	* APP 的 appId 
	*/
    private String appId;
    
 	/**
     * 商户API证书的证书序列号
     */
    String merchantSerialNumber;

    /**
     * 商户API私钥
     *
     */
    String merchantPrivateKey;

    /**
     * 商户v3Key
     */
    String v3Key;

   
    /**
     * 商户号
     */
    String merchantId;

  	/**
     * 回调地址
     */
    String callBackUrl;
  
}
当然不能忘了依赖
 			<!-- 微信授权登录相关 -->
            <dependency>
                <groupId>com.github.binarywang</groupId>
                <artifactId>weixin-java-miniapp</artifactId>
                <version>4.2.4.B</version>
            </dependency>
            <!--  微信支付相关 -->
            <dependency>
                <groupId>com.github.binarywang</groupId>
                <artifactId>weixin-java-pay</artifactId>
                <version>4.2.4.B</version>
            </dependency>
然后开始进行调用
 public String unifyAppPay(UnifyPayParams payParams) throws Exception {
        String appUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        // 请求body参数 当然这里需要构建一些请求参数 订单号 商品描述 金额等
        WechatPayModel wechatPayModel = new WechatPayModel(config.getAppId(), payParams.getOrderNo(), config.getMerchantId(), payParams.getOrderSubject(),
                config.getCallBackUrl(), payParams.getAmount());
    	//然后调用VX方法        
        CloseableHttpResponse response = getCloseableHttpResponse(appUrl, JSON.toJSONString(wechatPayModel));
        JSONObject jsonString = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
        //最后获取到一个prepay_id预支付交易会话标识
        return jsonString.getString("prepay_id");
    }
  private CloseableHttpResponse getCloseableHttpResponse(String h5Url, String s) throws Exception {
        String reqdata = s;
        HttpPost httpPost = new HttpPost(h5Url);
        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        //这里就需要一些 商户号 证书序列号 私钥 通过选择器去选择证书
        CloseableHttpClient closeableHttpClient = getWechatHttpClient(config.getMerchantId(), config.getMerchantSerialNumber(), config.getMerchantPrivateKey());
        return closeableHttpClient.execute(httpPost);
    }
	//通过相关参数进行选择证书实例
   private CloseableHttpClient getWechatHttpClient(String merchantId, String merchantSerialNumber, String merchantPrivateKey) throws Exception {
        PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(merchantPrivateKey.getBytes("utf-8")));
        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
                new PrivateKeySigner(merchantSerialNumber, privateKey)), config.getV3Key().getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号,可继续调用putMerchant添加商户信息

        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(merchantId);
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(merchantId, merchantSerialNumber, privateKey)
                .withValidator(new WechatPay2Validator(verifier));

        return builder.build();
    }
然后构建前端SDK需要的请求参数
**
 * @Author Awei
 * @Date 2023 02 16 16 16
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChargeResponse {

    @ApiModelProperty(value = "订单ID")
    Long orderId;

    @ApiModelProperty(value = "订单唯一标识码")
    String orderNo;

    @ApiModelProperty(value = "微信,开放平台审核通过的移动应用appid")
    String appid;

    @ApiModelProperty(value = "微信,package,java里是关键字不能用作属性所以加了")
    String packageString;

    @ApiModelProperty(value = "微信,随机字符串")
    String noncestr;

    @ApiModelProperty(value = "微信,时间戳,标准北京时间,时区为东八区 需要转换成秒(10位数字)")
    String timestamp;

    @ApiModelProperty(value = "微信,RSA")
    String signType;

    @ApiModelProperty(value = "微信,预支付交易会话标识")
    String sign;

    @ApiModelProperty(value = "微信,原始id")
    String originId;

    @ApiModelProperty(value = "支付宝,支付字符串")
    String aliPayString;

    @ApiModelProperty(value = "APP 支付 partnerid:商户号ID ")
    String partnerid;

    @ApiModelProperty(value = "APP 支付 prepayid:预支付订单号 ")
    String prepayid;

    /**
     * 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
     */
    String attach;

    public void buildPayInfo(JSONObject jsonObject,String orderNo) {
        this.appid = jsonObject.get("appId").toString();
        this.packageString = jsonObject.get("package").toString();
        this.sign = jsonObject.get("paySign").toString();
        this.timestamp = jsonObject.get("timeStamp").toString();
        this.signType = jsonObject.get("signType").toString();
        this.noncestr = jsonObject.get("nonceStr").toString();

    }
}

然后封装一下返回给前端

public Map<String, Object> appPay(UnifyPayParams payParams) {
        Map<String, Object> result = new HashMap<>(4);
        //这里就是上边的方法获取到的预支付交易会话标识
        String prepayId = this.unifyAppPay(payParams);
        // 返回前端支付参数
        ChargeResponse chargeResponse = this.unifyInitAppResponse(prepayId);
        chargeResponse.setOrderNo(payParams.getOrderNo());
        result.put("data", chargeResponse);
        result.put("payId", this.config.getMchInfoId());
        result.put("appId", this.config.getAppId());
        result.put("machId", this.config.getMerchantId());
        result.put("payServerFlag", payParams.getPayServerFlag().code);
        result.put("orderNo", payParams.getOrderNo());
        return result;
    }
	//封装的方法 主要是设置签名sign
   public ChargeResponse unifyInitAppResponse(String prepayId) throws Exception {
        ChargeResponse chargeResponse = new ChargeResponse();
        long timeTmp = System.currentTimeMillis() / 1000;
        String randomString = RandomStringUtils.random(16);
        chargeResponse.setTimestamp(String.valueOf(timeTmp));
        chargeResponse.setSignType("RSA");
        chargeResponse.setAppid(config.getAppId());
        chargeResponse.setPartnerid(config.getMerchantId());
        chargeResponse.setPrepayid(prepayId);
        chargeResponse.setNoncestr(randomString);
        chargeResponse.setPackageString("Sign=WXPay");
        chargeResponse.setSign(getAppSign(randomString, timeTmp, prepayId));
        chargeResponse.setOriginId(config.getWxOriginId());
        return chargeResponse;
    }
//先排序
 public String getAppSign(String nonceStr, long timestamp, String prepayId) throws Exception {
        String message = config.getAppId() + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepayId + "\n";
        return sign(message.getBytes("utf-8"));
    }
//然后加签
 String sign(byte[] message) throws Exception {
        PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getMerchantPrivateKey().getBytes("utf-8")));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

前端就能拉起微信支付啦

前端调用SDK使用后端传入参数拉起微信支付

支付流程
后续就是回调处理逻辑了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值