PC网站接入微信(Native)支付

一、接入准备

微信支付官网:https://pay.weixin.qq.com
注册微信商家号,在账号中心申请API证书及设置APIv3密钥 ,产品中心申请开通Native支付,AppId账号管理关联AppId(微信体系内应用ID)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
申请通过后,将得到对接过程中所需要的重要参数:

  • 账号信息内的微信支付商户号mchid
  • 微信体系内APPID
  • APIv3密钥
  • API证书序列号
  • API证书压缩包
    在这里插入图片描述

二、创建支付订单

官方Native下单API文档地址
项目内引入 wechatpay-apache-httpclient 依赖(微信支付提供)

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

创建订单测试类


public class CreateOrderTest {

    private String privateKey = "MIIEvQ";  // API证书压缩包内apiclient_key.pem文件内容 -> 私钥字符串

    private String appId = "wx21121323682f";  // 微信体系 AppId

    private String mchId = "1617212105";  // 账号信息 - 微信支付商户号

    private String mchSerialNo = "7DCA2B127B9DDD9A87612172B8EB5E8";  // API证书管理  API证书序列号

    private String apiV3Key = "n21eddqwdqwde2easjdhas213dfas123";  // APIv3密钥

    private CloseableHttpClient httpClient;

    @Before
    public void nativeRequestTest() throws UnsupportedEncodingException {

        // 加载商户私钥(privateKey:私钥字符串)
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

        // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)), apiV3Key.getBytes("utf-8"));

        // 初始化httpClient
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }


    /**
     * 微信native下单接口
     */
    @Test
    public void create() throws Exception{
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");

		// 下单接口金额单位为分
        String money = "0.01";
        BigDecimal multiply = new BigDecimal(money).multiply(new BigDecimal("100"));
        int i = multiply.intValue();

        // 商家系统生成订单号  唯一且不可重复,即使关闭微信订单后相同订单号也无法再次创建订单
        String out_trade_no = "211014247fb24262a2cc3c8548c24312";

        // 请求body参数
        // 支付成功回调通知接口 notify_url,必须为https
        String reqdata = "{" +
                "\"time_expire\": \"2022-10-21T15:38:00+08:00\"," +
                "\"amount\": {" +
                "\"total\": " + i + "," +
                "\"currency\": \"CNY\"" +
                "}," +
                "\"mchid\": \"" + mchId + "\"," +   // 商家号
                "\"out_trade_no\": \"" + out_trade_no + "\", " +  // 系统订单号
                "\"appid\": \"" + appId + "\"," +
                "\"description\": \"" + "测试支付" + "\"," +
                "\"attach\": \"自定义数据说明\"," +
                "\"notify_url\": \"https://143.232.433.42:8285/wxPay/call\" " +
                "}";

        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);

        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) { //处理成功
                System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) { //处理成功,无返回Body
                System.out.println("success");
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }

    }

}

三、关闭订单

/**
     * 关闭订单
     * 204 订单关闭成功返回状态204 无响应报文
     * success
     * @throws IOException
     */
    @Test
    public void close() throws IOException {
        HttpPost post = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/211014247fb24262a2cc32118c24312/close");

        // 请求body参数
        String reqdata = "{" +
                "\"mchid\": \"" + mchId + "\"" +
                "}";

        StringEntity entity = new StringEntity(reqdata, "utf-8");
        entity.setContentType("application/json");
        post.setEntity(entity);
        post.setHeader("Accept", "application/json");

        // 完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(post);

        int statusCode = response.getStatusLine().getStatusCode();

        System.out.println("响应码:" + statusCode);


        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    }

四、查询订单信息

/**
     * 查询订单
     * success,return body = {"amount":{"payer_currency":"CNY","total":1},"appid":"wxe406f9ceabc6682f","mchid":"1617009205","out_trade_no":"211014247fb21231248c24312","promotion_detail":[],"scene_info":{"device_id":""},"trade_state":"NOTPAY","trade_state_desc":"订单未支付"}
     * @throws Exception
     */
    @Test
    public void query()throws Exception{
        HttpGet get = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/211014247fb24262a2cc3c8548c24312?mchid=" + mchId);
        get.setHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(get);

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    }

五、支付成功回调通知报文解析


/**
 * 微信支付回调响应报文解密工具类
 */
public class AesUtil {
    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;
    private final byte[] aesKey;

    public AesUtil(byte[] key) {
        if (key.length != KEY_LENGTH_BYTE) {
            throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
        }
        this.aesKey = key;
    }

    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }
}


public class DecodeResponseBodyTest {

    private String apiV3Key = "ni3221tezho43she43n434123";  // APIv3密钥

    /**
     * 微信支付回调报文解密
     *
     * @throws GeneralSecurityException
     * @throws IOException
     */
    @Test
    public void decode() throws GeneralSecurityException, IOException {
    	// 回调通知报文
        String response = "{\"id\":\"5ae3a07e-0025-5e12-b959-4f7abe76ffbc\",\"create_time\":\"2022-10-21T11:54:50+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"TRANSACTION.SUCCESS\",\"summary\":\"支付成功\",\"resource\":{\"original_type\":\"transaction\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"K/IPHngj23SQvCcmplRuYRt7qjMqHQ9ALG5ou53wG/c331rFf8YjWo+ZDMEgxdRHsmdW4nxrmN7z62h4b98Ka4eCyuxaVaOc1Ddji28cP+u7XFTBWB8Ac9VqVmjQRlv+uM/Z0EIjYYrTx547Bw9soF/sCX9QPtmL9QzvtHlOocHSVDpPgLTrLSR0ruJL+O+PXQ8GQGv/6Jy+bRLmF/5/Lr2CkTybTP2XMfrJevTrKg/OXEHtqtTRdufgW13KdZ7wEHWljZyRM5TqnZOrk04A82+KNXGgaWh5HBtjQ7E+R1wdIiD3+o/aT82M1/FI7eJLRkeiBzIAEkjmFMGkygjZ2+zWpResInCL3VcHIFbl99NKqYDHNAXyUoeARvuI1uwHUBhQyQeF5TQVtNBjiM54K5U5uWTBu2rbsNB5OQU3sFPXzWJTCNKf3UnxMJW5ADpl2AbKzOiBj8bW4fZEy+WR+d2C83PS53R0hXz4g4JEX7Mi5ePP90OIiqI18gmGhfrmaJ9T8tzR8Ik9JSHvaj21coJgf7T4DRKg632Q0rCa5kl8h1saGHthO43jhqymVBDGp/kD6PqU1jvWanuVzIWYKSRCwnrqbgGXPmaupWX8dwphc1sTVA==\",\"associated_data\":\"transaction\",\"nonce\":\"AZ28LA0bMlB5\"}}";
        JSONObject jsonObject = JSONObject.parseObject(response);
        JSONObject resource = jsonObject.getJSONObject("resource");

        // 直接使用 resource.getBytes("nonce") 是错误的
        String associated_data = resource.getString("associated_data");
        String nonce = resource.getString("nonce");

        AesUtil aesUtil = new AesUtil(apiV3Key.getBytes());
        String decrypt = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), resource.getString("ciphertext"));

        System.out.println("解密后得内容:" + decrypt);
    }

}

六、通知签名验证

加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户通过验证签名,以确认请求来自微信,而不是其他的第三方。


/**
 * 获取请求头认证签名信息工具类,用于获取商户微信平台证书列表
 */
public class AuthorizationToken {

    private String mchId = "1617009205";  // 账号信息 - 微信支付商户号
    private String mchSerialNo = "7DCA2B127B9DDD9A876153F3255F3F472B8EB5E8";    // 商户API证书序列号
    private String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDfacUE1AeWa4TT" +
            "ukE/bsjulIBn7VMvsd+8ASZfUqWs5P4MW0Bqp/U9tb1iIO8ECGnK8csC80/peQe7" +
            "SSjdaBFLTWhCOn/4QSjY5wVMNxL9YW17rO2E1YHg+uYpB6i950H27vTh18EOtyeG" +
            "g2tgwGTr3/IuPeY5Cy/ZX4VEWnondYGhKWjJYXYtV1ypeBCkLe/A9zoyiIQUUQiz" +
            "YYibiU/Ow190Iywzc4oKT1K4lXGdai9OZHzkQorOBkCbx2/9vyLvvUjyfa6RtMWv" +
            "qpZuKqjEecQYtqJ6VvJ1N+uKMGDpyChSqBHxG0LT0K5Wu9Gtg5Y+NrYbzMThZUt5" +
            "/aJAF0L7AgMBAAECggEARz2RB6Mc8EhEyMchuzp2dC2CbKFu30yXDXpIZCkUj3dN" +
            "017dwaThPNZRF5Ns5BpSsdY8aCpyFv7zCjOgBkoDCcIbNtM0r1MH1XKFa/I76fRB" +
            "VyijbLIwgi8/aWH52uR9UmKMT9/evfSFdA1AFlADXnvA3CH84b/BeE1PT6aSQTZM" +
            "nZ8G7sgcQe8oBz+7oxhJl+wdDscerPg9YHRid/G3L/sjhKjOaMsBJar7gOhYNsop" +
            "pfbv51gl8v3iT6luwEkf5zmsM5GfXcyKYKZgKjlI3wOWe2QsvcaprsVQhoMETV1/" +
            "I5/KNWIr8sNur7EcEz0TBjLjqNh1pq1M+wTnIi25kQKBgQDzpdt0q5+mdht+ehbm" +
            "2X0TWLm89zPOlUZmq+X0UqD5rYTmZ8JHZuaicVaRqUQoTV18IgiHn7lyPyGFYO20" +
            "0ROl3aVLrpIqTXzmOYUM1AMtEDr6Gmky8RxPaUskMeOe3liPeF/T+AbYw5M9QRPo" +
            "CUTOkldu+w3vKauNPPM6puAmZwKBgQDqvUysPFhAu8YGCqHuJhOcoZkhqh4UrW7o" +
            "MEcv4UVAOwnaY55srkBLR5TN8rpaWcvFCD02Vg1nge9fdWiV1wtH81Oz5bIA+nM1" +
            "qYnOSu2Z1dqEU/iEaR3t+XCSkvuaqydQ6DYW9GVFt/Mj3xjV9r864QnDMuxGspGk" +
            "EY3990jaTQKBgQCjwRJpLLwldfXuoIHp77zXludm8MJaEwv5D4mDF1Hn3U6YSJ5T" +
            "vP4/qWskhR4w9CZjur/+30QVXAbcjRPWVjsdXIWvAwpr8h6C4Z/hylDEJcdttviD" +
            "a3e6i6scDYfNi+T7sEy/u1BmubOpFKcbabdcGxE2nvdziY8qYw+amPPH+wKBgCfU" +
            "Vt4inxbcxYzg4Pj3nPxGryT3KIN5qgfbqTiGkKmFWvajUI5AQsiDLMyFEvmhouGb" +
            "tEcz8rJNacBYu5YxFsjukJVFtB5WYJYKXkeSjx47Gwi49sIA1AM8/8zfA7IKuHER" +
            "9ZuPfF+IBslfYWdspqXm6TElwtF8GxoroFwnSUVBAoGAS+v+LYcrp4zXMuDk9o9h" +
            "3YhzDtedsmTEgR3CHs4hgltdX/jobDfNUk7QVe2ild1O3ULL83r09lf0GoBGxcxt" +
            "l5aGMEsdYLQPROanUZqGihBcWqW3P2Sde4rTgFvi+X14JwFbcmn21ddY9bQbbAzv" +
            "scKClgUPJMk5d0ZeAeJ/cR8=";  // 商户API证书私钥字符串

    public String getToken(String method, String url, String body) throws Exception {
        String nonceStr = UUID.randomUUID().toString().replace("-","");
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));

        return "mchid=\"" + mchId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + mchSerialNo + "\","
                + "signature=\"" + signature + "\"";
    }

    String sign(byte[] message) throws Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");

        // 加载商户私钥(privateKey:私钥字符串)
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

        sign.initSign(merchantPrivateKey);
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }

    String buildMessage(String method, String url, long timestamp, String nonceStr, String body) {
        return method + "\n"
                + url + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

}

/**
 * 验证回调通知签名测试类
 */
public class VerifySignatureTest {

    private String apiV3Key = "nin3232312123123432432anyan123";  // APIv3密钥

    @Test
    public void verify() throws Exception {
        // 支付成功回调参数
        String time = "1664344490";
        String nonce = "fNPfxxlVyJp21232fV93ri1aW";
        String serial = "745AB64ADA0A21221CBEAE7B23DB4C08C4CE";
        String signature = "k/+nNrE6yRLTzMfriBYA6L1MQc12is/qOmdIKogkIy/FrdavmRB2X4F77gBuhlEG8RM156nqxw+THAEEimuu0nuErUe3GeKRkdU2xG6/aiulQ9dXx8YRr14z15c/vEjEhuN/YhhK9RmRoBACrVcv9+5OwULI1872/CEdhj8DC2WwiRC4nldo+O3jPwS3ma1qkkF6hBYQmXYFbRP5zQRSDsk6FLUq5jq++oHk4kYjIlHR7o1FpvMj1y2tHzOQTOy8pFta3RVoS5iJ5oxzA+9wSwXsMsa1rBOn6xD3TzmqFnoiOd/1bvGbqkFXMIav01AUlrYHzdxokEqS484HWgbeIw==";
        String body = "{\"id\":\"5ae3a07e-0025-5e12-b959-4f7abe76ffbc\",\"create_time\":\"2022-10-21T11:54:50+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"TRANSACTION.SUCCESS\",\"summary\":\"支付成功\",\"resource\":{\"original_type\":\"transaction\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"K/IPHngj23SQvCcmplRuYRt7qjMqHQ9ALG5ou53wG/c331rFf8YjWo+ZDMEgxdRHsmdW4nxrmN7z62h4b98Ka4eCyuxaVaOc1Ddji28cP+u7XFTBWB8Ac9VqVmjQRlv+uM/Z0EIjYYrTx547Bw9soF/sCX9QPtmL9QzvtHlOocHSVDpPgLTrLSR0ruJL+O+PXQ8GQGv/6Jy+bRLmF/5/Lr2CkTybTP2XMfrJevTrKg/OXEHtqtTRdufgW13KdZ7wEHWljZyRM5TqnZOrk04A82+KNXGgaWh5HBtjQ7E+R1wdIiD3+o/aT82M1/FI7eJLRkeiBzIAEkjmFMGkygjZ2+zWpResInCL3VcHIFbl99NKqYDHNAXyUoeARvuI1uwHUBhQyQeF5TQVtNBjiM54K5U5uWTBu2rbsNB5OQU3sFPXzWJTCNKf3UnxMJW5ADpl2AbKzOiBj8bW4fZEy+WR+d2C83PS53R0hXz4g4JEX7Mi5ePP90OIiqI18gmGhfrmaJ9T8tzR8Ik9JSHvaj21coJgf7T4DRKg632Q0rCa5kl8h1saGHthO43jhqymVBDGp/kD6PqU1jvWanuVzIWYKSRCwnrqbgGXPmaupWX8dwphc1sTVA==\",\"associated_data\":\"transaction\",\"nonce\":\"AZ28LA0bMlB5\"}}";

        // 1.生成签名认证信息 Authorization
        String token = getAuthorizationToken();

        // 2.根据签名获取平台证书
        String certificates = getCertificatesList(token);

        // 3.选择正确的一个证书字符串
        String certificateJson = chooseCertificate(certificates, serial);

        // 4.从报文中解析出证书字符串
        String certificate = resolveCertificate(certificateJson);

        // 5.将证书字符串转为证书对象
        Certificate certificateObj = convertCertificate(certificate);

        // 6.拼接验签名串,字符串尾部一定也需要添加\n
        String str = Arrays.asList(time, nonce, body).stream().collect(Collectors.joining("\n"))+"\n";
        System.out.println("验签字符串:" + str);

        // 7.将返回的应答签名进行Base64解码
        byte[] signatureByte = Base64.getDecoder().decode(signature);

        // 8.验证签名
        boolean verifyResult= verifySignature(signatureByte, str, certificateObj);

        System.out.println("验签结果:" + verifyResult);
    }


    /**
     * 从报文中选择一个验签的证书
     * @param certificates
     * @param Serial
     * @return
     */
    public String chooseCertificate(String certificates,String Serial){
        JSONObject jsonObject = JSONObject.parseObject(certificates);
        JSONArray data = jsonObject.getJSONArray("data");
        for (Object certificate : data) {
            jsonObject = (JSONObject) certificate;
            if (Serial.equals(jsonObject.getString("serial_no"))){
                return JSONObject.toJSONString(jsonObject);
            }
        }
        return null;
    }


    /**
     * 验证签名
     * @param signature 微信返回的签名
     * @param signStr 验签字符串
     * @param certificate 微信平台证书对象
     * @return
     * @throws Exception
     */
    public boolean verifySignature(byte[] signature, String signStr,Certificate certificate) throws Exception {
        // 加载SHA256withRSA签名器
        Signature sign = Signature.getInstance("SHA256withRSA");

        // 用微信平台证书公钥对签名器进行初始化
        sign.initVerify(certificate);

        // 把我们构造的验签名串更新到签名器中
        sign.update(signStr.getBytes(StandardCharsets.UTF_8));

        boolean verify = sign.verify(signature);

        return verify;
    }


    /**
     * 证书字符串转换为证书对象
     * @param certificates
     * @return
     * @throws CertificateException
     */
    public Certificate convertCertificate(String certificates) throws CertificateException {

        //获取平台证书
        CertificateFactory cf = CertificateFactory.getInstance("X509");

        ByteArrayInputStream inputStream = new ByteArrayInputStream(certificates.getBytes(StandardCharsets.UTF_8));

        X509Certificate x509Certificate = (X509Certificate) cf.generateCertificate(inputStream);

        return x509Certificate;
    }


    /**
     * 解析证书Json字符串得到平台证书字符串
     * @param certificateJson
     * @return
     * @throws Exception
     */
    public String resolveCertificate(String certificateJson) throws Exception {
        JSONObject jsonObject = JSONObject.parseObject(certificateJson);
        JSONObject resource = jsonObject.getJSONObject("encrypt_certificate");
        String associated_data = resource.getString("associated_data");
        String nonce = resource.getString("nonce");

        AesUtil aesUtil = new AesUtil(apiV3Key.getBytes());
        String decrypt = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), resource.getString("ciphertext"));
        return decrypt;
    }


    public String getCertificatesList(String token) throws Exception {
        String schema = "WECHATPAY2-SHA256-RSA2048";
        HttpGet get = new HttpGet("https://api.mch.weixin.qq.com/v3/certificates");
        get.setHeader("Authorization", schema + " " + token);
        get.setHeader("Accept", "application/json");
        get.setHeader("User-Agent", "https://zh.wikipedia.org/wiki/User_agent");

        CloseableHttpClient client = HttpClients.createDefault();
        CloseableHttpResponse response = client.execute(get);

        int statusCode = response.getStatusLine().getStatusCode();
        String res = null;
        if (statusCode == 200) { //处理成功
            res = EntityUtils.toString(response.getEntity());
            System.out.println("success,return body = " + res);
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
        return res;
    }



    /**
     * 获取签名 用于获取平台证书
     *
     * @throws Exception
     */
    public String getAuthorizationToken() throws Exception {
        AuthorizationToken token = new AuthorizationToken();
        String t = token.getToken("GET", "/v3/certificates", "");
        return t;
    }



}

以上代码中关键性身份信息均为错误数据,请大家自行登录微信支付平台申请获取。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值