腾讯API调用(以文字识别OCR为例)

OcrDemo.java

腾讯API调用通过工具类,只要修改相应的参数即可。

public class OcrDemo {
    
    public static void main(String[] args) throws TencentCloudSDKException {

        //以文字识别为例
        String base64 = imgToBase64("https://xxxx.png");

        //修改Action,verstion等参数,这个接口是通用的
        JSONObject requestParams = new JSONObject();
        requestParams.put("RequestMethod", "POST");
        requestParams.put("Nonce", new Random().nextInt(java.lang.Integer.MAX_VALUE));
        requestParams.put("Timestamp", System.currentTimeMillis() / 1000);
        requestParams.put("Action", "GeneralBasicOCR");
        requestParams.put("Version", "2018-11-19");
        requestParams.put("Region", "ap-guangzhou");
        requestParams.put("ImageBase64", base64);
        TencentUtil tencentUtil = new TencentUtil();
        String result = tencentUtil.callTencentApi("ocr","GeneralBasicOCR",
                "ocr.tencentcloudapi.com","/","填入你的appid",
                "填入你的secret",
                requestParams);
        JSONObject jsonObject = JSONObject.parseObject(result);
        System.out.println(jsonObject.toJSONString());
    }

    /**
     * 服务器图片转换base64 path:服务器图片路径  返回 base64编码(String 类型)
     * @param path
     * @return
     */
    public static String imgToBase64(String path){
        byte[] data = null;
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try{
            URL url = new URL(path);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            in = connection.getInputStream();
            out = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int len = 0;
            while((len =in.read(b)) != -1){
                out.write(b,0,len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(in != null ){
                    in.close();
                }
            }catch (IOException e){
                e.getStackTrace();
            }
        }
        System.out.println("转换后的图片大小:"+out.toByteArray().length/1024);
        BASE64Encoder base = new BASE64Encoder();
        return base.encode(out.toByteArray());
    }

}
TencentUtil.java
@Component
public class TencentUtil {

    public String callTencentApi(String productCode, String action, String productDomain, String productDomainSuffix, String secretId, String secretKey, JSONObject requestParams) throws TencentCloudSDKException {
        String result = "";
        String url = "https://"+productDomain+productDomainSuffix;
        TreeMap<String, Object> treeMap = new TreeMap<>();
        treeMap.putAll(requestParams);
        String requestMethod = "";
        if(treeMap.get("RequestMethod")==null) {
            requestMethod = "GET";
        } else {
            requestMethod = treeMap.get("RequestMethod").toString();
        }
        if(StringUtils.isBlank(requestMethod)){
            requestMethod = "GET";
        }
        if (treeMap.containsKey("RequestMethod")) {
            treeMap.remove("RequestMethod");
        }
        if (!treeMap.containsKey("SecretId")) {
            treeMap.put("SecretId", secretId);
        }
        if (!treeMap.containsKey("Action")) {
            treeMap.put("Action", action);
        }
        if (!treeMap.containsKey("Nonce")) {
            treeMap.put("Nonce", new Random().nextInt(Integer.MAX_VALUE));
        }
        if (!treeMap.containsKey("Timestamp")) {
            treeMap.put("Timestamp", System.currentTimeMillis() / 1000L);
        }
        if("GET".equalsIgnoreCase(requestMethod)){
            //计算v1签名
            String signatureMethod = "HmacSHA1";
            if (treeMap.containsKey("SignatureMethod") && treeMap.get("SignatureMethod").toString().equals("HmacSHA256")) {
                signatureMethod = "HmacSHA256";
            }
            String plainText = Sign.makeSignPlainText(treeMap,"GET",productDomain,productDomainSuffix);
            try {
                treeMap.put("Signature", Sign.sign(plainText, secretKey, signatureMethod));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
            //调用腾讯接口
            result = sendTencentGet(url,treeMap,requestMethod);
        }else {
            //计算v3签名
            result = sendTencentPost(url,treeMap,requestMethod,productCode,productDomain,secretId,secretKey);
        }
        return result;
    }

    public static String sendTencentPost(String url, TreeMap<String, Object> requestParams,String requestMethod,String service,String host,String secretId,String secretKey) {
        String action = requestParams.get("Action").toString();
        String version = requestParams.get("Version").toString();
        String region = requestParams.get("Region").toString();
        String algorithm = "TC3-HMAC-SHA256";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 注意时区,否则容易出错
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
        // ************* 步骤 1:拼接规范请求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "";
        String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
        String signedHeaders = "content-type;host";
        String payload = getBodyString(requestParams);
        String hashedRequestPayload = sha256Hex(payload);
        String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;

        // ************* 步骤 2:拼接待签名字符串 *************
        String credentialScope = date + "/" + service + "/" + "tc3_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);
        String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;

        // ************* 步骤 3:计算签名 *************
        byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(StandardCharsets.UTF_8), date);
        byte[] secretService = hmac256(secretDate, service);
        byte[] secretSigning = hmac256(secretService, "tc3_request");
        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();

        // ************* 步骤 4:拼接 Authorization *************
        String authorization = algorithm + " " + "Credential=" + secretId + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
        //调用腾讯接口
        StringBuffer stringBuffer =new StringBuffer();
        BufferedReader responseReader = null;
        InputStream in1 = null;
        // 创建url资源
        try {
            URL urlClient = new URL(url);
            // 建立http连接
            HttpsURLConnection conn = (HttpsURLConnection) urlClient.openConnection();
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置允许输出
            conn.setDoOutput(true);
            // 设置允许输入
            conn.setDoInput(true);
            conn.setInstanceFollowRedirects(true);
            // 设置传递方式
            conn.setRequestMethod(requestMethod);
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.setRequestProperty("Authorization", authorization);
            conn.setRequestProperty("Host", host);
            conn.setRequestProperty("X-TC-Action", action);
            conn.setRequestProperty("X-TC-Timestamp", timestamp);
            conn.setRequestProperty("X-TC-Version", version);
            conn.setRequestProperty("X-TC-Region", region);
            // 开始连接请求
            conn.connect();
            //一定要用BufferedReader 来接收响应, 使用字节来接收响应的方法是接收不到内容的
            // utf-8编码
            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            out.append(payload);
            out.flush();
            out.close();
            // 请求返回的状态
            if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
                System.out.println("连接成功");
                // 请求返回的数据
                in1 = conn.getInputStream();
                String readLine;
                responseReader = new BufferedReader(new InputStreamReader(in1,"UTF-8"));
                while((readLine=responseReader.readLine()) != null){
                    stringBuffer.append(readLine);
                }
            } else {
                System.out.println("error++");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if (null != responseReader){
                    responseReader.close();
                }
                if (null != in1){
                    in1.close();
                }
            }catch (IOException e){}
        }
        return stringBuffer.toString();
    }
        /**
         * 请求腾讯API
         * @param requestParams
         * @param requestMethod
         * @return
         */
    public static String sendTencentGet(String url, TreeMap<String, Object> requestParams,String requestMethod){
        final long t = System.currentTimeMillis();
        String result = "";
        BufferedReader in = null;
        String paramStr = "";
        final JSONObject log_info = new JSONObject();
        for (final String key : requestParams.keySet()) {
            if (!paramStr.isEmpty()) {
                paramStr += '&';
            }
            try {
                paramStr = paramStr + key + '=' + URLEncoder.encode(requestParams.get(key).toString(), "utf-8");
            } catch (UnsupportedEncodingException e) {
                result = "{\"code\":-2300,\"location\":\"com.qcloud.Common.Request:129\",\"message\":\"api sdk throw exception! "
                        + e.toString() + "\"}";
            } catch (NullPointerException ex) {
                out.println("NLL>>" + key);
            }
        }
        try {
            if (requestMethod.equals("GET")) {
                if (url.indexOf(63) > 0) {
                    url = url + '&' + paramStr;
                } else {
                    url = url + '?' + paramStr;
                }
            }
            log_info.fluentPut("param", requestParams).fluentPut("url", url);
            final String BOUNDARY = "---------------------------"
                    + MD5.stringToMD5(String.valueOf(System.currentTimeMillis())).substring(0, 15);
            final URL realUrl = new URL(url);
            URLConnection connection = null;
            if (url.toLowerCase().startsWith("https")) {
                final HttpsURLConnection httpsConn = (HttpsURLConnection) (connection = realUrl.openConnection());
            } else {
                connection = realUrl.openConnection();
            }
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.setConnectTimeout(1000);
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e2) {
            result = "{\"code\":-2700,\"location\":\"com.qcloud.Common.Request:225\",\"message\":\"api sdk throw exception! "
                    + e2.toString() + "\"}";
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e3) {
                result = "{\"code\":-2800,\"location\":\"com.qcloud.Common.Request:234\",\"message\":\"api sdk throw exception! "
                        + e3.toString() + "\"}";
            }
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e4) {
                result = "{\"code\":-2800,\"location\":\"com.qcloud.Common.Request:234\",\"message\":\"api sdk throw exception! "
                        + e4.toString() + "\"}";
            }
        }
        log_info.fluentPut("resp", JSON.parse(result)).fluentPut("spk", (System.currentTimeMillis() - t));
        System.out.println(log_info.toJSONString());
        return result;
    }

    public static String getBodyString(TreeMap<String, Object> requestParams){
        if (requestParams.containsKey("Action")) {
            requestParams.remove("Action");
        }
        if (requestParams.containsKey("Timestamp")) {
            requestParams.remove("Timestamp");
        }
        if (requestParams.containsKey("Version")) {
            requestParams.remove("Version");
        }
        if (requestParams.containsKey("Region")) {
            requestParams.remove("Region");
        }
        if (requestParams.containsKey("Nonce")) {
            requestParams.remove("Nonce");
        }
        if (requestParams.containsKey("SecretId")) {
            requestParams.remove("SecretId");
        }
        JSONObject jsonObject = new JSONObject(requestParams);
        return jsonObject.toJSONString();
    }
    public static String sha256Hex(String s) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

    public static byte[] hmac256(byte[] key, String msg)  {
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        try {
            mac.init(secretKeySpec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
    }


}
Base64.java
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Base64 {
	private static final char[] base64EncodeChars;
	private static final byte[] base64DecodeChars;

	public static String encode(final byte[] data) {
		final StringBuilder sb = new StringBuilder();
		final int len = data.length;
		int i = 0;
		while (i < len) {
			final int b1 = data[i++] & 0xFF;
			if (i == len) {
				sb.append(Base64.base64EncodeChars[b1 >>> 2]);
				sb.append(Base64.base64EncodeChars[(b1 & 0x3) << 4]);
				sb.append("==");
				break;
			}
			final int b2 = data[i++] & 0xFF;
			if (i == len) {
				sb.append(Base64.base64EncodeChars[b1 >>> 2]);
				sb.append(Base64.base64EncodeChars[(b1 & 0x3) << 4 | (b2 & 0xF0) >>> 4]);
				sb.append(Base64.base64EncodeChars[(b2 & 0xF) << 2]);
				sb.append("=");
				break;
			}
			final int b3 = data[i++] & 0xFF;
			sb.append(Base64.base64EncodeChars[b1 >>> 2]);
			sb.append(Base64.base64EncodeChars[(b1 & 0x3) << 4 | (b2 & 0xF0) >>> 4]);
			sb.append(Base64.base64EncodeChars[(b2 & 0xF) << 2 | (b3 & 0xC0) >>> 6]);
			sb.append(Base64.base64EncodeChars[b3 & 0x3F]);
		}
		return sb.toString();
	}

	public static byte[] decode(final String str) throws UnsupportedEncodingException {
		final StringBuilder sb = new StringBuilder();
		final byte[] data = str.getBytes(StandardCharsets.US_ASCII);
		final int len = data.length;
		int i = 0;
		while (i < len) {
			int b1;
			do {
				b1 = Base64.base64DecodeChars[data[i++]];
			} while (i < len && b1 == -1);
			if (b1 == -1) {
				break;
			}
			int b2;
			do {
				b2 = Base64.base64DecodeChars[data[i++]];
			} while (i < len && b2 == -1);
			if (b2 == -1) {
				break;
			}
			sb.append((char) (b1 << 2 | (b2 & 0x30) >>> 4));
			int b3;
			do {
				b3 = data[i++];
				if (b3 == 61) {
					return sb.toString().getBytes(StandardCharsets.ISO_8859_1);
				}
				b3 = Base64.base64DecodeChars[b3];
			} while (i < len && b3 == -1);
			if (b3 == -1) {
				break;
			}
			sb.append((char) ((b2 & 0xF) << 4 | (b3 & 0x3C) >>> 2));
			int b4;
			do {
				b4 = data[i++];
				if (b4 == 61) {
					return sb.toString().getBytes(StandardCharsets.ISO_8859_1);
				}
				b4 = Base64.base64DecodeChars[b4];
			} while (i < len && b4 == -1);
			if (b4 == -1) {
				break;
			}
			sb.append((char) ((b3 & 0x3) << 6 | b4));
		}
		return sb.toString().getBytes(StandardCharsets.ISO_8859_1);
	}

	static {
		base64EncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
				'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
				'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
				'6', '7', '8', '9', '+', '/' };
		base64DecodeChars = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
				-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
				-1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
				9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
				29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
				-1, -1 };
	}
}
MD5.java
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;

@Slf4j
public class MD5 {
	public static String stringToMD5(final String str) {
		try {
			final byte[] strTemp = str.getBytes();
			final MessageDigest mdTemp = MessageDigest.getInstance("MD5");
			mdTemp.update(strTemp);
			return toHexString(mdTemp.digest());
		} catch (Exception e) {
			return null;
		}
	}

	public static String fileNameToMD5(final String fileName) {
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(fileName);
			return streamToMD5(inputStream);
		} catch (Exception e2) {
			return null;
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					log.error(e.getMessage(),e);
				}
			}
		}
	}

	public static String streamToMD5(final InputStream inputStream) {
		try {
			final MessageDigest mdTemp = MessageDigest.getInstance("MD5");
			final byte[] buffer = new byte[1024];
			int numRead = 0;
			while ((numRead = inputStream.read(buffer)) > 0) {
				mdTemp.update(buffer, 0, numRead);
			}
			return toHexString(mdTemp.digest());
		} catch (Exception e) {
			return null;
		}
	}

	private static String toHexString(final byte[] md) {
		final char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		final int j = md.length;
		final char[] str = new char[j * 2];
		for (int i = 0; i < j; ++i) {
			final byte byte0 = md[i];
			str[2 * i] = hexDigits[byte0 >>> 4 & 0xF];
			str[i * 2 + 1] = hexDigits[byte0 & 0xF];
		}
		return new String(str);
	}
}

Sign.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.TreeMap;

public class Sign {

	public static String sign(final String signStr, final String secret, final String signatureMethod)
			throws NoSuchAlgorithmException, InvalidKeyException {
		final Mac mac1 = Mac.getInstance("HmacSHA1");
		final Mac mac2 = Mac.getInstance("HmacSHA256");
		byte[] hash;
		if (signatureMethod.equals("HmacSHA256")) {
			final SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8),
					mac2.getAlgorithm());
			mac2.init(secretKey);
			hash = mac2.doFinal(signStr.getBytes(StandardCharsets.UTF_8));
		} else {
			final SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8),
					mac1.getAlgorithm());
			mac1.init(secretKey);
			hash = mac1.doFinal(signStr.getBytes(StandardCharsets.UTF_8));
		}
		final String sig = Base64.encode(hash);
		return sig;
	}

	public static String makeSignPlainText(final TreeMap<String, Object> requestParams, final String requestMethod,
			final String productDomain,final String productDomainSuffix) {
		String retStr = "";
		retStr += requestMethod;
		retStr += productDomain;
		retStr += productDomainSuffix;
		retStr += buildParamStr(requestParams, requestMethod);
		return retStr;
	}


	protected static String buildParamStr(final TreeMap<String, Object> requestParams, final String requestMethod) {
		String retStr = "";
		for (final String key : requestParams.keySet()) {
			if(requestParams.get(key)==null) {
				continue;
			}
			final String xx = requestParams.get(key).toString();
			if ("POST".equals(requestMethod) && !xx.isEmpty() && xx.substring(0, 1).equals("@")) {
				continue;
			}
			if (retStr.length() == 0) {
				retStr += '?';
			} else {
				retStr += '&';
			}
			if (requestParams.get(key) == null) {
				retStr = retStr + key.replace("_", ".") + '=';
			} else {
				retStr = retStr + key.replace("_", ".") + '=' + requestParams.get(key).toString();
			}
		}
		return retStr;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,使用腾讯OCR进行文字识别需要以下步骤: 1. 注册并登录腾讯云账号,在控制台中开通腾讯OCR服务,获取API密钥。 2. 在代码中引入腾讯OCR SDK,并使用API密钥进行身份验证。 3. 准备要识别的图片,并将其转换为Base64格式。 4. 调用腾讯OCRAPI,传入图片数据并设置识别类型(如通用文字识别、身份证识别等)。 5. 解析API返回的识别结果,获取识别出的文字内容。 以下是一个Python示例代码,用于使用腾讯OCR进行通用文字识别: ``` import base64 import json import requests # 设置密钥和API地址 app_id = "your_app_id" app_key = "your_app_key" api_url = "https://recognition.image.myqcloud.com/ocr/general" # 准备图片数据 with open('image.jpg', 'rb') as f: image_data = f.read() image_base64 = str(base64.b64encode(image_data), 'utf-8') # 构造请求参数 params = { "appid": app_id, "image": image_base64, "nonce_str": "random_string", "time_stamp": str(int(time.time())), } # 生成签名 sign_str = "&".join([f"{key}={params[key]}" for key in sorted(params.keys())]) sign_str += f"&appkey={app_key}" sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper() # 发送POST请求 headers = {'Content-Type': 'application/json'} data = { "appid": app_id, "image": image_base64, "nonce_str": "random_string", "time_stamp": str(int(time.time())), "sign": sign, } response = requests.post(api_url, headers=headers, data=json.dumps(data)) # 解析结果 result = json.loads(response.text) if result.get("code") == 0: words_list = result.get("data").get("item_list") for words in words_list: print(words.get("itemstring")) else: print(result.get("message")) ``` 需要注意的是,使用腾讯OCR服务需要收取一定的费用,具体费用标准可以在腾讯云控制台中查看。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值