Http接口调用方法:常规http接口与返回值转换为对象&xml请求参数方法与xml返回值解析&使用线程池处理接口返回数据

一:HTTP接口调用:

        1,线程池准备

         场景:erp接口返回数据量为几万条,为提高性能,使用线程池

        @Transactional      //为代码加锁,保证数据完整性 由于数据量可能比较大,所有设置超时时间为300秒,放后台慢慢跑,不影响别的代码执行

executorService.submit(new DataOperationMaterialThread(batch,iMaterialService));
每个线程需要执行的代码
    @Override
    //为代码加锁,保证数据完整性 由于数据量可能比较大,所有设置超时时间为300秒,放后台慢慢跑,不影响别的代码执行
    @Transactional(rollbackFor = Exception.class,timeout = 300)
    public Boolean getMaterial() {
        List<ErpMaterialVO> mList = null;
        try {
            //erp接口调用,返回参数为mList
            mList = erpMagerial();
        } catch (IOException e) {
            logger.info("ERP物料接口调用失败:{}", e.getMessage());
        }
        int threadCount = 10; // 线程数量
        int batchSize = 900; // 每批数据数量
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        List<List<ErpMaterialVO>> dataBatches = new ArrayList<>();
        //根据线程数拆分接口返回数据
        for (int i = 0; i < mList.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, mList.size());
            List<ErpMaterialVO> batch = mList.subList(i, endIndex);
            dataBatches.add(batch);
        }

        for (List<ErpMaterialVO> batch : dataBatches) {
//new DataOperationMaterialThread为每个线程需要执行的代码
            executorService.submit(new DataOperationMaterialThread(batch,iMaterialService));
        }

        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            return true;
        }
    }

2,erpMagerial() 调用erp接口

http接口请求方式一

        将返回值转为实体类
//实体类中可以包括list属性
Gson gson = new Gson();
Type listType = new TypeToken<List<ErpMaterialVO>>() {}.getType();
material =  gson.fromJson(response,listType);
请求方法: 
HttpGet httpGet = new HttpGet(url);
HttpPost httpPost = new HttpPost(url);
HttpPut httpPut = new HttpPut(url);
HttpDelete httpDelete = new HttpDelete(url);
    //调用erp接口获取物料信息
    public static List<ErpMaterialVO> erpMagerial() throws IOException {
        String url ="接口地址;
        logger.info("ERP物料接口----接口地址"+url);
        List<ErpMaterialVO> material = new ArrayList<>();
        try {
            HttpClient httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);

            // 执行请求
            HttpResponse httpResponse = httpClient.execute(httpGet);

            // 获取响应码
            int responseCode = httpResponse.getStatusLine().getStatusCode();
            System.out.println("Response Code: " + responseCode);

            // 读取响应内容
            String response = EntityUtils.toString(httpResponse.getEntity());

            Gson gson = new Gson();
            Type listType = new TypeToken<List<ErpMaterialVO>>() {}.getType();
            material =  gson.fromJson(response,listType);
            logger.info("ERP物料接口----接口地址"+url+"接口返回共"+material.size()+"条数据");
        } catch (Exception e) {
            logger.info("ERP物料接口----接口地址"+url+"接口调用失败"+e.getMessage());
            e.printStackTrace();
        }finally {
            return material;
        }
    }
 run方法 DataOperationMaterialThread
public class DataOperationMaterialThread implements Runnable{

    private IMaterialService iMaterialService;

    private List<ErpMaterialVO> dataList;
    private static int count = 0;

    public DataOperationMaterialThread(List<ErpMaterialVO> dataList, IMaterialService iMaterialService) {
        this.dataList = dataList;
        this.iMaterialService = iMaterialService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class,timeout = 120)
    public void run() {
            //根据实际需求写字机的run方法;每个线程需要执行的操作
    }

 http接口方法二

实体类总包含一个对象数组 如:
@Data
@ApiModel(value = "已排产(生产任务)", description = "已排产(生产任务)")
public class DailyPickingListVO {
    @ApiModelProperty(value = "日期")
    private String date;

    @ApiModelProperty(value = "投料单编号")
    private String ppbomBillNo;

    @ApiModelProperty(value = "日期")
    private List<DailyPickingListTwoVO> entries;


}

@Data
@ApiModel(value = "已排产(生产任务)", description = "已排产(生产任务)")
public class DailyPickingListTwoVO {
        @ApiModelProperty(value = "序号 原投料单对应的序号")
        private Integer index;

        @ApiModelProperty(value = "物料代码")
        private String itemNumber;

        @ApiModelProperty(value = "计量单位代码")
        private String unitNumber;

        @ApiModelProperty(value = "应发数量")
        private Double qtyMust;

        @ApiModelProperty(value = "投料单行号")
        private Integer ppbomIndex;
}
 将实体类转为json字符串
//调用每日投料单创建接口
dailyPickingListVO.setEntries(dailyPickingListTwoVOS);
//实体转为JSON字符串 实体类中包括list
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(dailyPickingListVO);
System.out.println("JSON字符串: 投料单号"+pickNo+"明细数据" + jsonString);
Integer code = erpProPickService.DailyPickingList(jsonString);
  调用接口时携带json参数
    //ERP接口创建每日投料单
    @Override
    public Integer DailyPickingList(String json) throws Exception {
        int responseCode = 0;
        try {
            String targetURL ="接口地址";
            logger.info("ERP标签接口----接口地址"+targetURL+"接口参数 --- :"+"明细数据"+json);
            URL url = new URL(targetURL);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置连接超时时间,根据实际情况调整
            connection.setConnectTimeout(5000);
            // 设置读取超时时间,根据实际情况调整
            connection.setReadTimeout(5000);
            // 设置请求方法为POST
            connection.setRequestMethod("POST");
            // 启用输出流(默认是不启用)
            connection.setDoOutput(true);
            // 设置请求头,指定数据格式为JSON
            connection.setRequestProperty("Content-Type", "application/json");
            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8);
            writer.write(json);
            writer.flush();
            writer.close();
            // 获取响应码
            responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);
            if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
            } else {
                // 读取错误响应
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
                String inputLine;
                StringBuilder errorResponse = new StringBuilder();

                while ((inputLine = errorReader.readLine()) != null) {
                    errorResponse.append(inputLine);
                }
                errorReader.close();
                // 打印结果
                logger.info("ERP标签接口返回值 Error Response code :"+responseCode+"------"+errorResponse.toString());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            return responseCode;
        }
    }

二:HTTP接口调用参数返回值为xml格式字符串

方法一:无需处理返回结果

1,组合请求参数:主参数

根据需求拼接xml中的data.file请求参数 

    @Override
    //生产报工保存批次 工序报工
    public String openumZjOrderSaveErp(ProReportDTO search, ProWorkOrderEntity workOrder) {
        //参数
        String file = "";
        //工单号
        String mfgnum = workOrder.getMfgnum();
        //工序
        Integer openum = workOrder.getOpenum();
        ErpMfgitmEntity mfgitm = new ErpMfgitmEntity();
        List<ErpMfgitmEntity> mfgitms =  erpMfgitmMapper.selectBYMfgnum(mfgnum);
        if(mfgitms.size() > 0){
            mfgitm = mfgitms.get(0);
        }
        //生产地点
        String mfgfcy = mfgitm.getMfgfcy();
        //工艺路线
        String itmref = mfgitm.getItmref();
        //工艺路线代码
        Integer routingVersion = workOrder.getRoutingVersion();
        //单位
//        ErpInventoryEntity erpInventory = new ErpInventoryEntity();
//        erpInventory.setMaterialNo(itmref);
//        ErpInventoryEntity material = erpInventoryMapper.getMaterialId(erpInventory);
//        String unit = material.getUnit();
        String unit =  erpInventoryMapper.getRouopeByItmref(workOrder);
        //时间
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyyMMdd");
        String format = dateFormat.format(date);
        //完成数量  proMeter
        BigDecimal numSum = search.getZjReport().getProMeter();
        //调整时间
        ProPlanEntity byId = proPlanService.getById(workOrder.getPlanId());
        Integer changeDate = byId.getChangeDate();
        //操作时间 minutesDifference 下达时间 取工时字段
        long minutesDifference = search.getZjReport().getWorkHour();
        //工单号,工序,生产地点,工艺路线,工艺路线代码选择,单位,工序单位转换,总的完成数量(实际数量),不合格完成数量(实际退回数量),已完成工作中心,
        // 实际调整时间,实际操作时间,员工编号(0),拒绝(0),消息(0),过账日期 ;;;;工艺路线,工艺路线代码选择,0;0
        //M;C01240602834;5;C0101;PS000277;40;KG;1;1;0;CM01;0.0417;1;0;0;0;20240611;;;;PS000277;40;0;0;
        //LC;DPT;BU;PRJ;;;
        file += "M;"+mfgnum+";"+openum+";"+mfgfcy+";"+itmref+";"+routingVersion+";"+unit+";1;"+numSum+";0;"+workOrder.getExtwst();
        file += ";"+changeDate+";"+minutesDifference+";0;0;0;"+format+";;;;"+itmref+";"+routingVersion+";"+"0;0;|";
        file += "LC;DPT;BU;PRJ;;;|END";

        //调用x3工序追踪接口
        logger.info("工序追踪接口参数》》》》》》》》》》》》》》》"+file);
        return openumX3(file);
    }

2,接口请求方法

endpoint接口地址
//工序追踪x3接口
    public String openumX3(String file){
        String mtk = "";
        try {
            JSONObject data = new JSONObject();
            //工序追踪模版  ZMKO1
            data.set("I_MODIMP", "ZMKO1");
            data.set("I_AOWSTA", "NO");
            data.set("I_EXEC", "REALTIME");
            data.set("I_RECORDSEP", "|");
//            data.set("I_FILE", "M;C01240401952;C0101;1000;5;015;1;20240416;;;;|L;LC010124020069;;200101;-0.004|L;LC010124030817;;200101;-0.996|ad|M;C01240401952;C0101;1000;60;208;1;20240416;;;;|L;LC010124030363;;200101;-1|ad|END");
            data.set("I_FILE",file);
            // 创建SOAP请求的XML数据  "<poolAlias xsi:type=\"xsd:string\">TEST1</poolAlias>\n"  TEST1  X3测试环境   SOLIV 正式环境
            String soapRequest = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" +
                    "\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n" +
                    "\txmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \n" +
                    "\txmlns:wss=\"http://www.adonix.com/WSS\">\n"
                    + "<soapenv:Header/>\n"
                    + "<soapenv:Body>\n"
                    + "<wss:run soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
                    + "<callContext xsi:type=\"wss:CAdxCallContext\">\n"
                    + "<codeLang xsi:type=\"xsd:string\">ENG</codeLang>\n"
                    + "<poolAlias xsi:type=\"xsd:string\">"+poolAlias+"</poolAlias>\n"
                    + "<poolId xsi:type=\"xsd:string\"></poolId>\n"
                    + "<requestConfig xsi:type=\"xsd:string\">\n"
                    + "<![CDATA[adxwss.optreturn=JSON&adxwss.beautify=true&adxwss.trace.on=off]]>\n"
                    + "</requestConfig>\n"
                    + "</callContext>\n"
                    + "<publicName xsi:type=\"xsd:string\">ZOWSIMPORT</publicName>\n"
                    + "<inputXml xsi:type=\"xsd:string\">\n"
                    + "<![CDATA[{\n"
                    + "\"GRP1\":\n"
                    + data.toString()
                    + "}]]>\n"
                    + " </inputXml>\n"
                    + "</wss:run>\n"
                    + "</soapenv:Body>\n"
                    + "</soapenv:Envelope>\n";


            // 发送SOAP请求,并接收返回的响应

            HttpURLConnection connection = (HttpURLConnection) new URL(endpoint).openConnection();
            String AccountPassword = "账号:密码";
//加密账号密码使用base64编码
            String basicAuth = "Basic " + DatatypeConverter.printBase64Binary(AccountPassword.getBytes());
            connection.setRequestProperty("Authorization", basicAuth);
            connection.setRequestMethod("POST");
//请求参数为xml
            connection.setRequestProperty("Content-Type", "application/xml");
            connection.setRequestProperty("Accept", "*/*");
            connection.setRequestProperty("soapAction", "saveRequest");
            // 设置连接超时时间,根据实际情况调整
            connection.setConnectTimeout(15000);
            // 设置读取超时时间,根据实际情况调整
            connection.setReadTimeout(5000);
            connection.setDoOutput(true);

            OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream());
            osw.write(soapRequest);
            osw.flush();
            //1.创建Reader对象
            SAXReader reader = new SAXReader();
            //2.加载xml
            Document document = reader.read(new InputStreamReader(connection.getInputStream()));
            String ec = document.asXML();
            logger.info("工序接口请求参数:"+ soapRequest);
            logger.info("工序追踪接口返回值》》》》》》》》" +ec);
            //3.获取根节点
            Element rootElement = document.getRootElement();
//有多少层循环取决于返回值参数是中有多少层,可以使用post调用完接口那这道一层一层解析,
//直到拿到你需要的数据
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()){
                Element stu = (Element) iterator.next();
                List<Attribute> attributes = stu.attributes();
                System.out.println("======获取属性值======");
                for (Attribute attribute : attributes) {
                    System.out.println(attribute.getValue());
                }
                System.out.println("======遍历子节点======");
                Iterator iterator1 = stu.elementIterator();
                while (iterator1.hasNext()){
                    Element stuChild = (Element) iterator1.next();
                    Iterator iterator2 = stuChild.elementIterator();
                    while (iterator2.hasNext()){
                        Element next = (Element) iterator2.next();
                        Iterator iterator3 = next.elementIterator();
                        if (next.getStringValue().indexOf("Creation of WO tracking") != -1){
                            int creationOfWoTracking = next.getStringValue().indexOf("Creation of WO tracking");
                            creationOfWoTracking = creationOfWoTracking+24;
                            mtk = next.getStringValue().substring(creationOfWoTracking);
                            System.out.println(">>>>>>"+"所在位置"+creationOfWoTracking+next.getName()+":"+next.getStringValue()+">>"+mtk);
                        }
                        while (iterator3.hasNext()){
                            Element next1 = (Element) iterator3.next();
                            if (next1.getName().equals("status")){
                                System.out.println(""+next1.getName()+":"+next1.getStringValue()+"");
                            }
                            //最后的子节点
                            Iterator iterator4 = next1.elementIterator();
                            while (iterator4.hasNext()){
                                Element next2 = (Element) iterator4.next();
                                System.out.println(""+next2.getName()+":"+next2.getStringValue()+"");
                            }
                        }
                    }
                }
            }
            document.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            return mtk;
        }
    }

 方法二:需要处理返回结果

 代码解释:

//因为是BigDecimal格式 所以使用以下方法
// .add 意思为相加
//.add() 中的意思为,如果下标为6的数据是空字符串,赋值为0.0,否则就将下标为6的数据装维BigDecimal格式,在于元数据相加
//举例,看一看为,int a = 0; a = a+b;
BigDecimal actualQty = new BigDecimal("0.0");
actualQty = actualQty.add(parts[6].equals("") ? new BigDecimal("0.0") : new BigDecimal(parts[6]));


// 使用split方法根据"|"分隔字符串
String[] partsa = ret.split("\\|");
//字符串根据,分隔为stating数组
String[] parts = part.split(",");

1,请求参数:mfgnum 工单号  op工序号 itmref 产品代码

 endpoint接口地址

 @Override
    public ErpToupOpItmrefVO toupChuErpByMfgnumOpItmref(String mfgnum, String op, String itmref) {
        logger.info("校验是否投料接口》》》》》》》》》》》》》》》工单号"+mfgnum+"工序"+op+"产品代码"+itmref);
        String ret = "";
        Boolean isWeting = false;
        try {
//            JSONObject data = new JSONObject();
//            data.set("I_TCRITERE", "MFGNUM="+mfgnum+"&OPENUM="+op);
            String soapRequest = "<soapenv:Envelope\n" +
                    "    xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
                    "    xmlns:wss=\"http://www.adonix.com/WSS\"\n" +
                    "    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
                    "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
                    "    <soapenv:Header/>\n" +
                    "    <soapenv:Body>\n" +
                    "        <wss:run soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
                    "            <callContext xsi:type=\"wss:CAdxCallContext\">\n" +
                    "                <codeLang xsi:type=\"xsd:string\">ENG</codeLang>\n" +
                    "                <poolAlias xsi:type=\"xsd:string\">"+poolAlias+"</poolAlias>\n" +
                    "                <poolId xsi:type=\"xsd:string\"/>\n" +
                    "                <requestConfig xsi:type=\"xsd:string\">\n" +
                    "                    <![CDATA[adxwss.optreturn=JSON&adxwss.beautify=true&adxwss.trace.on=off]]>\n" +
                    "                </requestConfig>\n" +
                    "            </callContext>\n" +
                    "            <publicName xsi:type=\"xsd:string\">AOWSEXPORT</publicName>\n" +
                    "            <inputXml xsi:type=\"xsd:string\">\n" +
                    "                <![CDATA[{\n" +
                    "                    \"GRP1\": {\n" +
                    "                        \"I_MODEXP\": \"MF1\",\n" +
                    "                        \"I_CHRONO\": \"NO\"\n" +
                    "                        },\n" +
                    "                   \"GRP2\": [{\"I_TCRITERE\": \"[F:MFM]MFGNUM='"+mfgnum+"'&[F:MFM]BOMOPE="+op+"\"}],\n" +
                    "                    \"GRP3\": {\n" +
                    "                        \"I_EXEC\": \"REALTIME\",\n" +
                    "                        \"I_RECORDSEP\": \"|\"}\n" +
                    "                }]]>\n" +
                    "            </inputXml>\n" +
                    "        </wss:run>\n" +
                    "    </soapenv:Body>\n" +
                    "</soapenv:Envelope>";

            logger.info("校验是否投料接口请求参数》》》》》》》》" + soapRequest);

//
            HttpURLConnection connection = (HttpURLConnection) new URL(endpoint).openConnection();

            String AccountPassword = "账号:密码";
//账号密码使用base64加密
            String basicAuth = "Basic " + DatatypeConverter.printBase64Binary(AccountPassword.getBytes());
            connection.setRequestProperty("Authorization", basicAuth);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/xml");
            connection.setRequestProperty("Accept", "*/*");
            connection.setRequestProperty("soapAction", "saveRequest");
            // 设置连接超时时间,根据实际情况调整
            connection.setConnectTimeout(15000);
            // 设置读取超时时间,根据实际情况调整
            connection.setReadTimeout(5000);
            connection.setDoOutput(true);

            OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream());
            osw.write(soapRequest);
            osw.flush();
            int responseCode = connection.getResponseCode();
            if (responseCode != 200){
                isWeting = false;
            }
            //1.创建Reader对象
            SAXReader reader = new SAXReader();
            //2.加载xml
            Document document = reader.read(new InputStreamReader(connection.getInputStream()));
            String ec = document.asXML();
            logger.info("校验是否投料接口返回结果》》》》》》》》" + ec);
//            File file = new File("E:\\fanhui.xml");
//            Document document = reader.read(file);
            //3.获取根节点
            Element rootElement = document.getRootElement();
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()) {
                Element stu = (Element) iterator.next();
                System.out.println("======遍历子节点======");
                Iterator iterator1 = stu.elementIterator();
                while (iterator1.hasNext()) {
                    Element stuChild = (Element) iterator1.next();
                    Iterator iterator2 = stuChild.elementIterator();
                    while (iterator2.hasNext()) {
                        Element next = (Element) iterator2.next();
                        Iterator iterator3 = next.elementIterator();
                        while (iterator3.hasNext()) {
                            Element next1 = (Element) iterator3.next();
                            if (next1.getName().equals("resultXml")) {
                                JSONObject jsonObject = new JSONObject(next1.getStringValue());
                                Object grp3 = jsonObject.get("GRP3");
                                JSONObject grp3Object = new JSONObject(grp3);
                                ret = grp3Object.get("O_FILE").toString();
                                isWeting = true;
                                logger.info("校验是否投料接口----接口地址" + endpoint + "接口返回O_FILE" + grp3Object.get("O_FILE").toString());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            isWeting = false;
            e.printStackTrace();
        }finally {
            //标准投入量合计
            BigDecimal standardQty = new BigDecimal("0.0");
            //实际投入量合计
            BigDecimal actualQty = new BigDecimal("0.0");

            //空字符串代表不需要投料,第五位为投料状态,第六位为标准投料量,第七位为实际投料量
            if (!isWeting){
                ErpToupOpItmrefVO erpToupOpItmref = new ErpToupOpItmrefVO();
                erpToupOpItmref.setIsToup(isWeting);
                erpToupOpItmref.setStandardQty(standardQty);
                erpToupOpItmref.setActualQty(actualQty);
                return erpToupOpItmref;
            }
            Boolean rasult = true;
            if(! ret.equals("")){
                // 使用split方法根据"|"分隔字符串
                String[] partsa = ret.split("\\|");
                // 打印分隔后的数组元素
                for (String part : partsa) {
                    Integer retInt = 0;
                    if(!part.equals("")){
                        String[] parts = part.split(",");
                        retInt = parts[4].equals("") ? 0 :Integer.valueOf(parts[4]);
                        BigDecimal a = new BigDecimal(parts[5]);
                        standardQty = standardQty.add(parts[5].equals("") ? new BigDecimal("0.0") : new BigDecimal(parts[5]));
                        actualQty = actualQty.add(parts[6].equals("") ? new BigDecimal("0.0") : new BigDecimal(parts[6]));
                    }
                    if (retInt < 2){
                        isWeting = false;
                        break;
                    }
                }
            }else{
                isWeting = true;
            }
            ErpToupOpItmrefVO erpToupOpItmref = new ErpToupOpItmrefVO();
            erpToupOpItmref.setIsToup(isWeting);
            erpToupOpItmref.setStandardQty(standardQty);
            erpToupOpItmref.setActualQty(actualQty);
            return erpToupOpItmref;
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值