java实现微信小程序支付功能

 

微信支付-开发者文档:

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

生成订单

    /**
     * 生成订单
     */
    @User
    @ApiOperation("生成订单")
    @PostMapping
    public AjaxResult add(@RequestBody WxOrder wxOrder, HttpServletRequest request) {
        return wxOrderService.insertWxOrder(wxOrder, request);
    }
    /**
     * 生成订单
     * 
     * @param wxOrder 订单
     * @return 结果
     */
    public AjaxResult insertWxOrder(WxOrder wxOrder, HttpServletRequest request);

    /**
     * 生成订单
     * 
     * @param wxOrder 订单
     * @return 结果
     */
    @Override
    public AjaxResult insertWxOrder(WxOrder wxOrder, HttpServletRequest request) {
        if (wxOrder == null || StringUtils.isEmpty(wxOrder.getPid())) {
            return AjaxResult.error("订单支付数据不能为空,请检查参数再试");
        }
        WxScenicSpot wxScenicSpot = new WxScenicSpot();
        wxScenicSpot.setPid(wxOrder.getPid());
        List<WxScenicSpot> wxScenicSpots = wxScenicSpotMapper.selectWxScenicSpotList(wxScenicSpot);
        if (CollectionUtils.isEmpty(wxScenicSpots)) {
            return AjaxResult.error("未找到支付产品,请检查参数再试");
        }

        wxOrder.setUserId(JwtUtil.getUser(request.getHeader(ConstantUtil.TOKEN)).getId());
        // 订单编号
        wxOrder.setOrderNo(CustomCodeUtil.createOrderCode());
        // 商品冗余信息
        wxOrder.setScenicSpotId(wxScenicSpots.get(0).getId());
        wxOrder.setName(wxScenicSpots.get(0).getName());
        wxOrder.setAddress(wxScenicSpots.get(0).getAddress());
        wxOrder.setOpeningHours(wxScenicSpots.get(0).getOpeningHours());
        wxOrder.setPhone(wxScenicSpots.get(0).getPhone());
        wxOrder.setImage(wxScenicSpots.get(0).getImage());
        // 成人单价
        BigDecimal adultPrice = wxScenicSpots.get(0).getAdultPrice();
        // 成人票数量
        Long adultCount = wxOrder.getAdultCount();
        // 成人票总价
        BigDecimal adultTotalPrice = new BigDecimal(Arith.mul(adultPrice.doubleValue(), (double)adultCount));
        wxOrder.setAdultTotalPrice(adultTotalPrice);

        // 儿童单价
        BigDecimal childPrice = wxScenicSpots.get(0).getChildPrice();
        // 儿童票数量
        Long childCount = wxOrder.getChildCount();
        // 儿童票总价
        BigDecimal childTotalPrice = new BigDecimal(Arith.mul(childPrice.doubleValue(), (double) childCount));
        wxOrder.setChildTotalPrice(childTotalPrice);

        // 总票价
        BigDecimal totalPrice = new BigDecimal(Arith.add(adultTotalPrice.doubleValue(), childTotalPrice.doubleValue()));
        if (totalPrice.doubleValue()<0) {
            return AjaxResult.error("非法价格,价格不能为负数");
        }
        wxOrder.setTotalPrice(totalPrice);
        // 总票数量
        wxOrder.setTotalCount(adultCount+childCount);
        // 订单创建时间
        wxOrder.setCreateDate(DateUtils.getNowDate());
        if (totalPrice.doubleValue()==0) {
            wxOrder.setStatus(1);
            wxOrder.setPayDate(DateUtils.getNowDate());
            wxOrderMapper.insertWxOrder(wxOrder);
            return AjaxResult.success("生成免费订单成功");
        }

        // 获取微信预支付订单号
        JSONObject jsonObject = wxPayUtils.getPrepayId(wxOrder);
        String prepay_id = (String) jsonObject.get("prepay_id");
        // 获取预支付订单号成功
        if (StringUtils.isNotEmpty(prepay_id)) {
            wxOrder.setPrepayId(prepay_id);
            int i = wxOrderMapper.insertWxOrder(wxOrder);
            if (i > 0) {
                // 返回给前端调起微信支付的必要参数
                Map<String, Object> map = wxPayUtils.returnToReceptionJson(wxOrder.getOrderNo(), prepay_id);
                return AjaxResult.success(map);
            } else {
                return AjaxResult.error("生成订单失败");
            }
        } else {
            return AjaxResult.error("生成订单失败");
        }
    }
微信支付工具类
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.wx.api.controller.order.domain.WxOrder;
import com.ruoyi.wx.api.controller.user.domain.WxUser;
import com.ruoyi.wx.api.controller.user.service.IWxUserService;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.*;

/**
 * 微信支付工具类
 */
@Component
public class WxPayUtils {

    @Autowired
    private IWxUserService iWxUserService;

    // 证书编码
    public static final String serial_no = "xxx";
    // 商户号
    public static final String mchId = "xxx";
    // appid
    public static final String appId = "xxx";

    // 证书私钥
    public static final String privateKey = "-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBJn3bVt9BbLhs\n" +
            "+ZjULV7Odh4rtBBd2wc7uZ8RlN/9E8sJfAefowiSTPwOkTYKDlyhpG131a4VKj+N\n" +
            "zaTu0Y5zQGyl29ElHVVuPw4mVni7xyqVdJ5VUxyJMKHmQsGpngHS4sF28c5Aihfi\n" +
            "Gkydt6BRF8xwFC9u+D0r4PY9dwHTn4jyaFd25CMUxVO+rfjOWFuGa/rEjtQw03KU\n" +
            "UVR6np6FmNXdWalQbmbETyUqGjCac6J7hDZ1LIRU4YtqMqqsXhnk3FaoS23MOgaZ\n" +
            "RE3nIgpYqGgfXfLOKDt5n4zLALJkV0xmk3VErbheWpzRVFae/JMtsf/8ySgtiOga\n" +
            "n8fvShJNAgMBAAECggEAf+P+vbb9yJI2Y2G5QfRwrAAl5gYqOBsI5RD5NGkBDs+G\n" +
            "RtdrLNaEnGqBExwvTeVIjHcVTJ2d0MHSpxAdP0xeKA3mYsPz7cFIieESe2wSMTOl\n" +
            "DKTVGeYYJPagnJhjJu5KgtpGA34EdVN6kOmdBWlKq6c4ZJXY+n8/8cfZA8XC3d3B\n" +
            "favo104podp8cC2IVNMs21OzbjD4V+6VV9X/5BA6x7bDcarlJXSyCehdXgjhjNmT\n" +
            "/9gz7MFhOsUlAG7P03easIRcZCQL6z9MebD3xfVYcXnS4L3CcVw1FWEdLXxe/3IG\n" +
            "Q8UPTPHhTLFRbURHI00x1jEvcD9qKXYgKeU/N7IY+QKBgQD93r2SotKM5EDxM3L2\n" +
            "5UFrmEVnf4bwg5QDyZFpjAJ+/uMSsEX3f1m8Mst82Y4Mybz8XVMNsUJmoY8eJoM+\n" +
            "sqRbI5HXySsFEbDqh7jrtBoN7R1rl3jQw4qxqWYR8GQJ6VqAXuEFbrxgE1YFgqw5\n" +
            "40HAYbv417h0h5A1rcRKegoW9wKBgQDCxVaCmBzcYYFc2leRy6qH965OEedqbSCV\n" +
            "QPprCDBoBM6jrq97ZfWyfmLNSjjFhTSz9h8z5dQcePZrrI3+evlE8V18hUmWN6rM\n" +
            "CvPCb+4q8CwiHmLFqVp+m11MR8EOBcWCW/HlioqBKTLglijY53RUjW7No/T+32sf\n" +
            "5R1qYq672wKBgQC3dztFN4o169bK+UWCDBgFK9wsecsJEe3r9sWxo09Ce+2aWe2W\n" +
            "eWBeU88fARJZR4neT4tv/8Re6y7EuUxsCSoh+0iwy17doPVb6I3JOTUDD3MNiD/1\n" +
            "jvsyfZuYJ0QErbGLyAWSqX5VaGPoQ5E3nHauE3OG2E8jV7zuLhAHSr7z7QKBgAF8\n" +
            "Z/CPIIk95TLEJ67hEuf+p8HIuS9CreD1ofN3GIdyofD1wDj8yicWd8KBMnWvUnud\n" +
            "ARfwRPICqj6gDmVGoug3vzLYAXu36QGtg7aUDAkf0/ZerPo9FIeqv8d5NKvat2sL\n" +
            "MIlDyVK68bxs6NreyTBr89B108SuB68ynErXfeXJAoGBAMCoJyWdFAQKVvycHyv4\n" +
            "914+v7niQahws23wxHlzvup8/doCS1XVQAoEyQ4iIPDHYmiOCcmzCQnb1CWgMbIl\n" +
            "oBY3baP1GWOwEWw/HYKOwHW3fLkYC/xaRi+b5IxyEzR7hlCm/A6gCnCUYqIdU8gd\n" +
            "jYE4kGB2O/5vdbITdSMai47o\n" +
            "-----END PRIVATE KEY-----";


    /**
     * 获取微信预支付订单号
     * @return
     */
    public JSONObject getPrepayId(WxOrder wxOrder){
        WxUser wxUser = iWxUserService.selectWxUserById(wxOrder.getUserId());

        JSONObject jsonObject = new JSONObject();
        JSONObject amountJsonObject = new JSONObject();
        JSONObject payerJsonObject = new JSONObject();
        amountJsonObject.put("total",wxOrder.getTotalPrice());
        payerJsonObject.put("openid",wxUser.getOpenid());
        // 应用ID
        jsonObject.put("appid",appId);
        // 商户号
        jsonObject.put("mchid",mchId);
        // 商品描述
        jsonObject.put("description",wxOrder.getName());
        // 商户订单号
        jsonObject.put("out_trade_no",wxOrder.getOrderNo());
        // 通知地址
        jsonObject.put("notify_url","https://zc.xxx.com/wx/api/pay/notifyUrl");
        // 订单金额信息
        jsonObject.put("amount",amountJsonObject);
        // 支付者信息
        jsonObject.put("payer",payerJsonObject);
        String body = jsonObject.toString();
        System.out.println(body);
        String authorization = signStr("POST", "/v3/pay/transactions/jsapi", body);

        String result = HttpRequest.post("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi")
                .body(body)
                .header("Content-Type","application/json")
                .header("Accept","application/json")
                .header("Authorization","WECHATPAY2-SHA256-RSA2048 " + authorization)//头信息,多个头信息多次调用此方法即可
                .timeout(10000)//超时,毫秒
                .execute().body();
        JSONObject jsonObject1 = JSONUtil.parseObj(result);
        String prepay_id = jsonObject1 == null ? "":(String) jsonObject1.get("prepay_id");
        JSONObject resultJsonObject = new JSONObject();
        resultJsonObject.put("prepay_id",prepay_id);
        resultJsonObject.put("chatPrice",wxOrder.getTotalPrice());
        return resultJsonObject;
    }

    /**
     * 成功获取微信预支付订单号后, 返回给前端调起微信支付的必要参数
     * @param orderNo   商户订单号
     * @param prepay_id 预支付订单号
     * @return
     */
    public Map<String, Object> returnToReceptionJson(String orderNo, String prepay_id){
        HashMap<String, Object> map = new HashMap<>();
        long timeStamp = System.currentTimeMillis() / 1000;
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String paySign = getPaySign(timeStamp, uuid, prepay_id);
        map.put("orderId", orderNo);
        map.put("timeStamp", timeStamp);
        map.put("nonceStr", uuid);
        map.put("package", "prepay_id=" + prepay_id);
        map.put("signType", "RSA");
        map.put("paySign", paySign);
        return map;
    }

    public String getPaySign(long timestamp, String randString, String prepay_id){
        String data =  appId + "\n" +
                timestamp + "\n" +
                randString + "\n" +
                "prepay_id=" + prepay_id + "\n";
        String signature = null;
        try {
            signature = sign(data.getBytes("utf-8"));
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return signature;
    }

    public String signStr2(String method, String url){
        String nonceStr = UUID.randomUUID().toString();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage2(method, url, timestamp, nonceStr);
        String signature = null;
        try {
            signature = sign(message.getBytes("utf-8"));
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("签名后:[" + signature + "]");
        return  "mchid=\"" + mchId + "\","
                + "serial_no=\"" + serial_no + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "signature=\"" + signature + "\"";
    }

    public String buildMessage2(String method, String url, long timestamp, String nonceStr) {
        String str = method + "\n"
                + url + "\n"
                + timestamp + "\n"
                + nonceStr + "\n\n";
        System.out.println("签名数据[" + str + "]");
        return str;
    }

    public String signStr(String method, String url, String body){
        String nonceStr = UUID.randomUUID().toString();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        System.out.println("message:[" + message + "]");
        String signature = null;
        try {
            signature = sign(message.getBytes("utf-8"));
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("signature=[" + signature + "]");
        return  "mchid=\"" + mchId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + serial_no + "\","
                + "signature=\"" + signature + "\"";
    }

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

    public String sign(byte[] message) throws SignatureException {
        Signature sign = null;
        try {
            sign = Signature.getInstance("SHA256withRSA");
            PrivateKey privateKey = getPrivateKey();
            sign.initSign(privateKey);
            sign.update(message);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(sign.sign());
    }
    /**
     * 获取私钥。
     */
    public static PrivateKey getPrivateKey() throws IOException {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                new ByteArrayInputStream(privateKey.getBytes("utf-8")));
        return merchantPrivateKey;
    }

    // xml解析
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if(null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            m.put(k, v);
        }
        //关闭流
        in.close();
        return m;
    }

    /**
     * 获取子结点的xml
     *
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }
}

 支付接口

import cn.hutool.json.JSONObject;
import com.ruoyi.wx.api.controller.pay.service.IWxPayService;
import com.ruoyi.wx.response.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Api(value = "微信小程序支付接口",tags = {"微信小程序支付接口"})
@RestController
@RequestMapping("/wx/api/pay")
public class WxPayController {

    @Autowired
    private IWxPayService wxPayService;

    /**
     * 查询订单支付状态
     * @param orderNo 商户订单号
     * @return
     */
    @ApiOperation("查询订单支付状态")
    @GetMapping("/transactions")
    public ResponseResult<Object> transactions(@RequestParam("orderNo") String orderNo){
        return wxPayService.transactions(orderNo);
    }

    /**
     * 支付通知(回调)
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @ApiOperation("支付通知(回调)")
    @RequestMapping(value = "/notifyUrl", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public JSONObject payNotifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return wxPayService.payNotifyUrl(request,response);

    }
}
import cn.hutool.json.JSONObject;
import com.ruoyi.wx.response.ResponseResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface IWxPayService {
    ResponseResult<Object> transactions(String orderNo);

    JSONObject payNotifyUrl(HttpServletRequest request, HttpServletResponse response)throws IOException;
}

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.wx.api.controller.order.domain.WxOrder;
import com.ruoyi.wx.api.controller.order.mapper.WxOrderMapper;
import com.ruoyi.wx.api.controller.pay.service.IWxPayService;
import com.ruoyi.wx.response.ResponseResult;
import com.ruoyi.wx.utils.WxPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class WxPayServiceImpl implements IWxPayService {

    // 格式化时间日期
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private WxPayUtils wxPayUtils;
    @Autowired
    private WxOrderMapper wxOrderMapper;

    @Override
    public ResponseResult<Object> transactions(String orderId) {
        WxOrder wxOrder = wxOrderMapper.apiSelectWxOrderByOrderId(orderId);

        String authorization = wxPayUtils.signStr2("GET", "/v3/pay/transactions/out-trade-no/" + orderId + "?mchid="+WxPayUtils.mchId);
        String result = HttpRequest.get("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + orderId + "?mchid="+WxPayUtils.mchId)
                .header("Content-Type","application/json")
                .header("Accept","application/json")
                .header("Authorization","WECHATPAY2-SHA256-RSA2048 " + authorization)//头信息,多个头信息多次调用此方法即可
                .timeout(10000)//超时,毫秒
                .execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(result);
        String trade_state = (String) jsonObject.get("trade_state");
        // 支付成功
        if ("SUCCESS".equals(trade_state)) {
            String success_time = (String) jsonObject.get("success_time");
            Date payDate = null;
            try {
                payDate = simpleDateFormat.parse(success_time.replace("T", " ").replace("+08:00", ""));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            wxOrder.setStatus(1);
            wxOrder.setPayDate(payDate);
            wxOrderMapper.updateWxOrder(wxOrder);
        } else {
            // 支付失败
        }
        return ResponseResult.createBySuccess(jsonObject);
    }

    @Override
    public JSONObject payNotifyUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
        BufferedReader reader = null;

        reader = request.getReader();
        String line = "";
        String xmlString = null;
        StringBuffer inputString = new StringBuffer();

        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        xmlString = inputString.toString();
        request.getReader().close();
        log.info("----接收到的数据如下:---" + xmlString);

        Map<String, Object> map = new HashMap<String, Object>();
        String summary = "";
        String resource = "";
        String create_time = "";
        Map<String, Object> value = getValue(xmlString);

        map = value;
        summary = (String) map.get("summary");
        resource = (String) map.get("resource");
        create_time = (String) map.get("create_time");
        log.info("回调接口 summary == 》" + summary);
        log.info("回调接口 resource == 》" + resource);
        log.info("回调接口 create_time == 》" + create_time);



        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code","SUCCESS");
        jsonObject.put("message","成功");
        return jsonObject;
    }

    /**
     * 处理支付回调的方法
     * @param param
     * @return
     */
    public static Map<String, Object> getValue(String param) {
        Map<String, Object> map = new HashMap<>();
        String str = "";
        String key = "";
        Object value = "";
        char[] charList = param.toCharArray();
        boolean valueBegin = false;
        for (int i = 0; i < charList.length; i++) {
            char c = charList[i];
            if (c == '{') {
                if (valueBegin == true) {
                    value = getValue(param.substring(i, param.length()));
                    i = param.indexOf('}', i) + 1;
                    map.put(key, value);
                }
            } else if (c == '=') {
                valueBegin = true;
                key = str;
                str = "";
            } else if (c == ',') {
                valueBegin = false;
                value = str;
                str = "";
                map.put(key, value);
            } else if (c == '}') {
                if (str != "") {
                    value = str;
                }
                map.put(key, value);
                return map;
            } else if (c != ' ') {
                str += c;
            }
        }
        return map;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yixian123.com

谢谢打赏,祝老板心想事成

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值