【学习笔记】微信支付相关接口实现--个人笔记线上直接用的那种笔记

前提

是为了获取:标识商户身份的信息、商户的证书和私钥、微信支付的证书、微信支付API的URL

  • 获取商户号
    微信商户平台:https://pay.weixin.qq.com/步骤:申请成为商户 => 提交资料 => 签署协议 =>
    获取商户号
  • 获取AppID
    微信公众平台:https://mp.weixin.qq.com/步骤:注册服务号 => 服务号认证 => 获取APPID => 绑定商户号
  • 申请商户证书
    步骤:登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 申请API证书包括商户证书和商户私钥
  • 获取微信的证书
    可以预先下载,也可以通过编程的方式获取。
  • 获取APIv3秘钥(在微信支付回调通知和商户获取平台证书使用APIv3密钥)
    步骤:登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 设置APIv3密钥

引依赖

<!--wechatpay-sdk-->
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-apache-httpclient</artifactId>
    <version>0.4.5</version>
</dependency>

配置类

@Configuration
public class WechatpayConfig{
    @Value("${wechat-pay.merchant-id}")
    private String merchantId;
    @Value("${wechat-pay.merchant-serial-number}")
    private String merchantSerialNumber;
    @Value("${wechat-pay.private-key}")
    private String privateKey;
    @Value("${wechat-pay.api-v3-key}")
    private String apiV3Key;
    /**
     * 给容器中加入WechatPay的HttpClient,虽然它是WechatPay的,
     * 但可以用它给任何外部发请求,因为它只对发给WechatPay的请求做处理而不对发给别的的请求做处理.
     */
    @Bean
    public HttpClient httpClient(){
        //私钥
        PrivateKey merchantPrivateKey=PemUtil.loadPrivateKey(privateKey);
        //微信证书校验器
        Verifier verifier=null;
        try{
            //获取证书管理器实例
            CertificatesManager certificatesManager=CertificatesManager.getInstance();
            //向证书管理器增加需要自动更新平台证书的商户信息(默认时间间隔:24小时)
            certificatesManager.putMerchant(merchantId,new WechatPay2Credentials(merchantId,new PrivateKeySigner(merchantSerialNumber,merchantPrivateKey)),apiV3Key.getBytes(StandardCharsets.UTF_8));
            //从证书管理器中获取verifier
            verifier=certificatesManager.getVerifier(merchantId);
        }
        catch(Exception e){
            new RuntimeException("微信证书校验器配置失败");
        }
        WechatPayHttpClientBuilder builder=WechatPayHttpClientBuilder.create().withMerchant(merchantId,merchantSerialNumber,merchantPrivateKey).withValidator(new WechatPay2Validator(verifier));
        CloseableHttpClient httpClient=builder.build();
        return httpClient;
    }
    /**
     * 和上面相比只是不需要验证签名了
     * @return
     */
    @Bean
    public HttpClient httpClientWithNoSign(){
        //私钥
        PrivateKey merchantPrivateKey=PemUtil.loadPrivateKey(privateKey);
        //微信证书校验器
        Verifier verifier=null;
        try{
            //获取证书管理器实例
            CertificatesManager certificatesManager=CertificatesManager.getInstance();
            //向证书管理器增加需要自动更新平台证书的商户信息(默认时间间隔:24小时)
            certificatesManager.putMerchant(merchantId,new WechatPay2Credentials(merchantId,new PrivateKeySigner(merchantSerialNumber,merchantPrivateKey)),apiV3Key.getBytes(StandardCharsets.UTF_8));
            //从证书管理器中获取verifier
            verifier=certificatesManager.getVerifier(merchantId);
        }
        catch(Exception e){
            new RuntimeException("微信证书校验器配置失败");
        }
        WechatPayHttpClientBuilder builder=WechatPayHttpClientBuilder.create()
                                                                     .withMerchant(merchantId,merchantSerialNumber,merchantPrivateKey)
                                                                     .withValidator(response->true);
        CloseableHttpClient httpClient=builder.build();
        return httpClient;
    }
}

写配置

wechat-pay:
  #接下来两个用来标识用户
  #商户id
  merchant-id: xxxxxxxxxxx
  #公众号appid(和商户id绑定过)
  appid: xxxxxxxxxxx
  #接下来两个用来确保SSL(内容未作任何加密,只做了签名.)
  #商户证书序列号
  merchant-serial-number: xxxxxxxxxxx
  #商户私钥
  private-key: xxxxxxxxxxx
  #APIv3密钥(在微信支付回调通知和商户获取平台证书使用APIv3密钥)
  api-v3-key: xxxxxxxxxxx
  #接下来两个是相关地址
  #微信服务器地址
  domain: https://api.mch.weixin.qq.com
  #接收结果通知地址
  notify-domain: xxxxxxxxxxx

使用

以下涉及的共有的内容

public class WechatPayConstant{
    public static final String CANCEL_PAY_URL="/v3/pay/transactions/out-trade-no/%s/close";
    public static final String CREATE_PAY_URL="/v3/pay/transactions/native";
    public static final String QUERY_PAY_URL="/v3/pay/transactions/out-trade-no/%s?mchid=%s";
    public static final String CREATE_REFUND_URL="/v3/refund/domestic/refunds";
    public static final String QUERY_REFUND_URL="/v3/refund/domestic/refunds/%s";
    public static final String TRADE_BILL_URL="/v3/bill/tradebill?bill_date=%s&bill_type=%s";
    public static final String FLOW_BILL_URL="/v3/bill/fundflowbill?bill_date=%s";
    public static final String TRADE_STATE_SUCCESS="SUCCESS";
    public static final String REFUND_STATE_SUCCESS="SUCCESS";
}
@Value("${wechat-pay.merchant-id}")
private String merchantId;
@Value("${wechat-pay.merchant-serial-number}")
private String merchantSerialNumber;
@Value("${wechat-pay.api-v3-key}")
private String apiV3Key;
@Value("${wechat-pay.domain}")
private String domain;
@Value("${wechat-pay.appid}")
private String appId;
@Value("${wechat-pay.notify-url}")
private String notifyUrl;
@Autowired
private HttpClient httpClient;
@Autowired
private HttpClient httpClientWithNoSign;

支付

流程图
在这里插入图片描述

创建支付

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml

private String createPay(OrderInfo orderInfo) throws Exception{
    //请求构造
    HttpPost httpPost=new HttpPost(domain+WechatPayConstant.CREATE_PAY_URL);
    //请求体
    //构造数据
    HashMap<String,Object> reqData=new HashMap<>();
    reqData.put("appid",appId);
    reqData.put("mchid",merchantId);
    reqData.put("description",orderInfo.getTitle());
    reqData.put("out_trade_no",orderInfo.getOrderNo());
    reqData.put("notify_url",notifyUrl+"/pay/order/order-signal");
    HashMap<String,Integer> amount=new HashMap<>();
    //单位是分
    amount.put("total",orderInfo.getTotalFee());
    reqData.put("amount",amount);
    String jsonReqData=new Gson().toJson(reqData);
    StringEntity entity=new StringEntity(jsonReqData,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    //请求头
    httpPost.setHeader("Accept","application/json");
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpPost);
    Map<String,String> dataMap=null;
    try{
        int statusCode=response.getStatusLine()
                               .getStatusCode();
        //成功
        if(statusCode==200){
            String body=EntityUtils.toString(response.getEntity());
            dataMap=new Gson().fromJson(body,HashMap.class);
        }
        //失败
        else{
            if(statusCode!=204){
                String body=EntityUtils.toString(response.getEntity());
                log.error(body);
                return null;
            }
        }
    }
    finally{
        response.close();
    }
    //返回二维码的地址
    return dataMap.get("code_url");
}

支付通知

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_5.shtml

@PostMapping("/pay-signal")
public HashMap<String,String> paySignal(@RequestBody Map<String,Object> signalRes,HttpServletResponse response){
    log.debug("收到微信回调");
    try{
        //TODO:验签
        //用密文解密出明文
        Map<String,String> resource=(Map<String,String>)signalRes.get("resource");
        String ciphertext=resource.get("ciphertext");
        String associatedData=resource.get("associated_data");
        String nonce=resource.get("nonce");
        String plainText=new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
        //转换
        HashMap<String,Object> data=new Gson().fromJson(plainText,HashMap.class);
        //从数据库中查出对应的订单
        QueryWrapper<OrderInfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("order_no",data.get("out_trade_no"));
        OrderInfo orderInfo=orderInfoService.getOne(queryWrapper);
        synchronized(this){
            if(orderInfo.getOrderStatus()
               .equals(OrderInfo.NOT_PAIED)){
                //将订单设置为已支付状态
                orderInfo.setOrderStatus(OrderInfo.PAIED);
                //更新订单状态
                orderInfoService.updateById(orderInfo);
                //添加支付记录
                PaymentInfo paymentInfo=new PaymentInfo();
                paymentInfo.setOrderNo(orderInfo.getOrderNo());
                paymentInfo.setCreateTime(new Date());
                paymentInfo.setUpdateTime(new Date());
                paymentInfo.setPayerTotal(orderInfo.getTotalFee());
                paymentInfo.setPaymentType(PaymentInfo.WECHAT_PAY);
                //微信支付中的支付编号
                paymentInfo.setTransactionId((String)data.get("transaction_id"));
                //交易类型(扫码 刷脸等等)
                paymentInfo.setTradeType((String)data.get("trade_type"));
                paymentInfo.setTradeState((String)data.get("trade_state"));
                //存放全部数据(json)以备不时之需
                paymentInfo.setContent(plainText);
                paymentInfoService.save(paymentInfo);
                log.info("订单{}的支付记录添加成功,支付记录id为{}.",orderInfo.getOrderNo(),paymentInfo.getId());
            }
            else{
                log.debug("订单{}状态为{},回调处理退出.",orderInfo.getOrderNo(),OrderInfo.PAIED);
            }
        }
        return null;
    }
    catch(Exception e){
        log.error(e.getMessage());
        response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
        HashMap<String,String> map=new HashMap<>();
        map.put("code","FAIL");
        map.put("message","支付失败");
        return map;
    }
}

查询支付

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml

private Map<String,Object> queryPay(String orderNo) throws Exception{
    //请求构造
    HttpGet httpGet=new HttpGet(String.format(domain+WechatPayConstant.QUERY_PAY_URL,orderNo,merchantId));
    //请求头
    httpGet.setHeader("Accept","application/json");
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpGet);
    Map<String,Object> dataMap=null;
    try{
        int statusCode=response.getStatusLine()
            .getStatusCode();
        String body=EntityUtils.toString(response.getEntity());
        //成功
        if(statusCode<400){
            dataMap=new Gson().fromJson(body,HashMap.class);
            log.info("查询订单支付{}成功",orderNo);
        }
        //失败
        else{
            log.error("查询订单支付{}失败,返回数据为{}.",orderNo,body);
            throw new IOException("订单查询失败");
        }
    }
    finally{
        response.close();
    }
    return dataMap;
}

取消支付

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_3.shtml

private boolean cancelPay(String orderNo){
    //请求构造
    HttpPost httpPost=new HttpPost(String.format(domain+WechatPayConstant.CANCEL_PAY_URL,orderNo));
    //请求体
    //构造数据
    HashMap<String,Object> reqData=new HashMap<>();
    reqData.put("mchid",merchantId);
    String jsonReqData=new Gson().toJson(reqData);
    StringEntity entity=new StringEntity(jsonReqData,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    //请求头
    httpPost.setHeader("Accept","application/json");
    CloseableHttpResponse response=null;
    try{
        //完成签名并执行请求
        response=(CloseableHttpResponse)httpClient.execute(httpPost);
        Map<String,String> dataMap=null;
        int statusCode=response.getStatusLine()
            .getStatusCode();
        //成功
        if(statusCode==204){
            log.info("取消订单{}成功",orderNo);
            return true;
        }
        //失败
        else{
            log.error("取消订单{}失败",orderNo);
            return false;
        }
    }
    catch(Exception e){
        log.error("取消订单{}失败",orderNo);
        return false;
    }
    finally{
        try{
            response.close();
        }
        catch(IOException e){
            log.error("关闭response失败");
        }
    }
}

退款

创建退款

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_10.shtml

private String createRefund(RefundInfo refundInfo) throws Exception{
    //请求构造
    HttpPost httpPost=new HttpPost(domain+WechatPayConstant.CREATE_REFUND_URL);
    //请求体
    //构造数据
    HashMap<String,Object> reqData=new HashMap<>();
    reqData.put("out_trade_no",refundInfo.getOrderNo());//订单编号
    reqData.put("out_refund_no",refundInfo.getRefundNo());//退款单编号
    reqData.put("reason",refundInfo.getReason());//退款原因
    reqData.put("notify_url",notifyUrl+"/pay/order/refund-signal");//退款通知地址
    HashMap<String,Object> amount=new HashMap<>();
    amount.put("refund",refundInfo.getRefund());//退款金额
    amount.put("total",refundInfo.getTotalFee());//原订单金额
    amount.put("currency","CNY");//币种
    reqData.put("amount",amount);
    //将参数转换成json字符串
    String jsonData=new Gson().toJson(reqData);
    log.info("请求参数 ===> {}"+jsonData);
    StringEntity entity=new StringEntity(jsonData,"utf-8");
    httpPost.setEntity(entity);//将请求报文放入请求对象
    //请求头
    httpPost.setHeader("content-type","application/json");
    httpPost.setHeader("Accept","application/json");//设置响应报文格式
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpPost);
    try{
        //解析响应结果
        String bodyAsString=EntityUtils.toString(response.getEntity());
        int statusCode=response.getStatusLine()
                               .getStatusCode();
        if(statusCode==200){
            log.info("成功, 退款返回结果 = "+bodyAsString);
            return bodyAsString;
        }
        else{
            if(statusCode!=204){
                log.warn("退款异常:"+bodyAsString);
            }
            return null;
        }
    }
    finally{
        response.close();
    }
}
退款通知

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_11.shtml

@PostMapping("/refund-signal")
public HashMap<String,String> refundSignal(@RequestBody Map<String,Object> signalRes,HttpServletResponse response){
    log.debug("收到微信回调");
    try{
        Map<String,String> resource=(Map<String,String>)signalRes.get("resource");
        String ciphertext=resource.get("ciphertext");
        String associatedData=resource.get("associated_data");
        String nonce=resource.get("nonce");
        //解密出明文
        String plainText=new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
        //转换
        HashMap<String,Object> data=new Gson().fromJson(plainText,HashMap.class);
        //从数据库中查出对应的退款信息
        QueryWrapper<RefundInfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("refund_no",data.get("out_refund_no"));
        RefundInfo refundInfo=refundInfoService.getOne(queryWrapper);
        synchronized(this){
            if(RefundInfo.REFUND_PROCESSING.equals(refundInfo.getRefundStatus())){
                //将退款状态设置为退款成功
                refundInfo.setRefundStatus(RefundInfo.REFUND_SUCCESS);
                //存放全部数据(json)以备不时之需
                refundInfo.setContentNotify(plainText);
                //更新退款
                refundInfoService.updateById(refundInfo);
                //更新订单的状态
                String orderNo=refundInfo.getOrderNo();
                QueryWrapper<OrderInfo> orderInfoQueryWrapper=new QueryWrapper<>();
                orderInfoQueryWrapper.eq("order_no",orderNo);
                OrderInfo orderInfoToUpdate=new OrderInfo();
                orderInfoToUpdate.setOrderStatus(OrderInfo.REFUNDED);
                orderInfoService.update(orderInfoToUpdate,orderInfoQueryWrapper);
                log.debug("退款成功,退款单为{},对应的订单为{}.",refundInfo.getRefundNo(),refundInfo.getOrderNo());
            }
            else{
                log.debug("退款单{}状态为{},回调处理退出.",refundInfo.getRefundNo(),refundInfo.getRefundStatus());
            }
        }
        HashMap<String,String> map=new HashMap<>();
        map.put("code","SUCCESS");
        map.put("message","成功");
        return map;
    }
    catch(Exception e){
        log.error(e.getMessage());
        response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
        HashMap<String,String> map=new HashMap<>();
        map.put("code","FAIL");
        map.put("message","失败");
        return map;
    }
}
查询退款

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_10.shtml

private Map<String,Object> queryRefund(String refundNo) throws Exception{
    //请求构造
    HttpGet httpGet=new HttpGet(String.format(domain+WechatPayConstant.QUERY_REFUND_URL,refundNo));
    //请求头
    httpGet.setHeader("Accept","application/json");
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpGet);
    Map<String,Object> dataMap=null;
    try{
        int statusCode=response.getStatusLine()
            .getStatusCode();
        String body=EntityUtils.toString(response.getEntity());
        //成功
        if(statusCode<400){
            dataMap=new Gson().fromJson(body,HashMap.class);
            log.info("查询退款{}成功",refundNo);
        }
        //失败
        else{
            log.warn("查询退款{}失败,返回数据为{}.",refundNo,body);
        }
    }
    finally{
        response.close();
    }
    return dataMap;
}

账单

查询交易账单(注重交易双方)下载URL

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_6.shtml

/**
 * @param billDate 格式:yyyy-MM-dd 5.6日的账单记录的时间为05-06 9:00到05-07 9:00,并且在05-07 9:00后才能查到.
 * @param billType ALL(支付成功且未退款+支付成功且退款) SUCCESS(支付成功且未退款) REFUND(支付成功且退款)
 * @return 账单下载url(30s后则失效)
 */
private String queryTradeBillDownloadUrl(String billDate,String billType)throws Exception{
    //请求构造
    HttpGet httpGet=new HttpGet(String.format(domain+WechatPayConstant.TRADE_BILL_URL,billDate,billType));
    //请求头
    httpGet.setHeader("Accept","application/json");
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpGet);
    String downloadUrl=null;
    try{
        int statusCode=response.getStatusLine()
                               .getStatusCode();
        String body=EntityUtils.toString(response.getEntity());
        //成功
        if(statusCode<400){
            downloadUrl=(String)new Gson().fromJson(body,HashMap.class)
                                          .get("download_url");
            return downloadUrl;
        }
        //失败
        else{
            log.warn("查询downloadUrl失败,返回数据为{}.",body);
            return null;
        }
    }
    catch(Exception e){
        log.warn("查询downloadUrl失败");
        return null;
    }
    finally{
        response.close();
    }
}
查询流水账单(只注重商户)下载URL

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_7.shtml

/**
 * @param billDate 格式:yyyy-MM-dd 5.6日的账单记录的时间为05-06 9:00到05-07 9:00,并且在05-07 9:00后才能查到.
 * @return 账单下载url(30s后则失效)
 */
private String queryFlowBillDownloadUrl(String billDate) throws Exception{
    //请求构造
    HttpGet httpGet=new HttpGet(String.format(domain+WechatPayConstant.FLOW_BILL_URL,billDate));
    //请求头
    httpGet.setHeader("Accept","application/json");
    //完成签名并执行请求
    CloseableHttpResponse response=(CloseableHttpResponse)httpClient.execute(httpGet);
    String downloadUrl=null;
    try{
        int statusCode=response.getStatusLine()
                               .getStatusCode();
        String body=EntityUtils.toString(response.getEntity());
        //成功
        if(statusCode<400){
            downloadUrl=(String)new Gson().fromJson(body,HashMap.class)
                                          .get("download_url");
            return downloadUrl;
        }
        //失败
        else{
            log.warn("查询downloadUrl失败,返回数据为{}.",body);
            return null;
        }
    }
    catch(Exception e){
        log.warn("查询downloadUrl失败");
        return null;
    }
    finally{
        response.close();
    }
}
获取账单(包括交易/流水)数据

https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_8.shtml

/**
 * 调用微信支付的接口只返回数据,然后我们把数据返回给前端,前端将其转化为excel.
 * @param downloadUrl 交易/流水账单的下载URL(即上面两个方法的返回值)
 */
private String downloadBill(String downloadUrl)throws Exception{
    //请求构造
    HttpGet httpGet=new HttpGet(downloadUrl);
    //请求头
    httpGet.addHeader("Accept","application/json");
    //完成签名并执行请求(注意:这里必须用httpClientWithNoSign,因为这个请求返回的数据是没有签名的.)
    CloseableHttpResponse response=(CloseableHttpResponse)httpClientWithNoSign.execute(httpGet);
    try{
        String bodyAsString=EntityUtils.toString(response.getEntity());
        int statusCode=response.getStatusLine()
                               .getStatusCode();
        if(statusCode<400){
            log.debug("下载账单成功");
            //存放数据
            return bodyAsString;
        }
        else{
            log.warn("下载账单失败,返回结果为:{}",bodyAsString);
            return null;
        }
    }
    catch(Exception e){
        log.warn("下载账单失败");
        return null;
    }
    finally{
        response.close();
    }
}
完整下载账单的操作
@GetMapping("/download-trade-bill")
public AjaxResult downloadTradeBill(String billDate,@RequestParam(defaultValue="ALL") String billType)throws Exception{
    //获取downloadUrl
    String downloadUrl=queryTradeBillDownloadUrl(billDate,billType);
    log.debug("downloadUrl:{}",downloadUrl);
    //访问downloadUrl获取数据
    String returnData=downloadBill(downloadUrl);
    HashMap<String,String> resultMap=new HashMap<>();
    resultMap.put("result",returnData);
    return AjaxResult.success(AjaxResult.QUERY_SUCCESS,resultMap);
}
@GetMapping("/download-flow-bill")
public AjaxResult downloadFlowBill(String billDate) throws Exception{
    //获取downloadUrl
    String downloadUrl=queryFlowBillDownloadUrl(billDate);
    log.debug("downloadUrl:{}",downloadUrl);
    //访问downloadUrl获取数据
    String returnData=downloadBill(downloadUrl);
    HashMap<String,String> resultMap=new HashMap<>();
    resultMap.put("result",returnData);
    return AjaxResult.success(AjaxResult.QUERY_SUCCESS,resultMap);
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值