webservice接口开发详解(附完整流程demo)

摘要

由于公司对接第三方系统业务较多,所以就采用webservice进行对接,本文项目框架使用SSH搭建,其他框架也可以参考下具体使用流程,本文demo都是测试通过而且发布成功,有需要的可以直接copy根据自己的业务需求进行修改,这里的demo只能给大家一个参考,不能照搬。废话不多说,直接上代码。有需要的伙伴可以参考借鉴一下。

准备工作

  1. 下载cfx所需jar包(使用cfx方式)

    1.1 下载地址:点击----->apache-cxf-2.6.16下载
    在这里插入图片描述1.2 下载完成后解压放入项目lib目录下重新编译,如下图
    在这里插入图片描述

步骤

第一步:webservice在项目中的配置,如下:

1. 创建service-ws.xml,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	
	http://cxf.apache.org/jaxws 
    http://cxf.apache.org/schemas/jaxws.xsd">
	
	<import resource="classpath:META-INF/cxf/cxf.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
	
	<!-- 企业信息同步接口 -->
	<bean id="companyImpl" class="com.hontek.webservice.service.impl.CompanyImpl">
		<property name="interAccountDao" ref="interAccountDao"/>
		<property name="enterpriseDao" ref="enterpriseDao"/>
		<property name="proTypeDao" ref="proTypeDao"/>
		<property name="proTypeQrcodeDao" ref="proTypeQrcodeDao"/>
		<property name="enterprseService" ref="enterprseService"/>
		<property name="proTypeBatchDao" ref="proTypeBatchDao"/>
		<property name="orderService" ref="orderService"/>
		<property name="zizhiDao" ref="zizhiDao"/>
		<property name="zizhiTypeDao" ref="zizhiTypeDao"/>
		<property name="zizhiAppendixDao" ref="zizhiAppendixDao"/>
		<property name="productServiceInter" ref="productService"/>
		<property name="traceService" ref="traceService"/>
		<property name="certificateDao" ref="certificateDao"/>
		<property name="certificateCheckDao" ref="certificateCheckDao"/>
		<property name="certificatePrintDao" ref="certificatePrintDao"/>
		<property name="certificateScanDao" ref="certificateScanDao"/>
		
	</bean>
	
	<jaxws:server serviceClass="com.hontek.webservice.service.inter.CompanyInter" address="/company">
		<jaxws:serviceBean>
			<ref bean="companyImpl"/>
		</jaxws:serviceBean>
	</jaxws:server>


	<!-- 检测设备接口 -->
	<bean id="detectionDeviceImpl" class="com.hontek.devicewebservice.service.impl.DetectionDeviceImpl">
		<property name="userDao" ref="userDao"/>
		<property name="enterpriseDao" ref="enterpriseDao"/>
		<property name="checkEquipmentDao" ref="checkEquipmentDao"/>
		<property name="proTypeQrcodeDao" ref="proTypeQrcodeDao"/>
		<property name="checkInfoDao" ref="checkInfoDao"/>
		<property name="checkInfoDetailDao" ref="checkInfoDetailDao"/>
		<property name="proTypeDao" ref="proTypeDao"/>
		<property name="spotCheckDao" ref="spotCheckDao"/>
		<property name="orderService" ref="orderService"/>
		<property name="dimennoRecordService" ref="dimennoRecordService"/>
		<property name="certificateService" ref="certificateServiceInter"/>
		<property name="caInfoDao" ref="caInfoDao"/>
		<property name="certificateCheckDao" ref="certificateCheckDao"/>
	</bean>

	<jaxws:server serviceClass="com.hontek.devicewebservice.service.inter.DetectionDeviceInter" address="/detectionDevice">
		<jaxws:serviceBean>
			<ref bean="detectionDeviceImpl"/>
		</jaxws:serviceBean>
	</jaxws:server>

	<!-- 圳品、菜篮子平台对接接口 -->
	<bean id="platformsImpl" class="com.hontek.platformswebservice.service.impl.PlatformsImpl">
		<property name="interAccountDao" ref="interAccountDao"/>
		<property name="enterprseService" ref="enterprseService"/>
		<property name="certificateServiceInter" ref="certificateServiceInter"/>
		<property name="proTypeDao" ref="proTypeDao"/>
		<property name="enterpriseDao" ref="enterpriseDao"/>
		<property name="proTypeQrcodeDao" ref="proTypeQrcodeDao"/>
		<property name="caInfoDao" ref="caInfoDao"/>
		<property name="userDao" ref="userDao"/>
		<property name="spotCheckDao" ref="spotCheckDao"/>
		<property name="checkReportDao" ref="checkReportDao"/>
		<property name="checkContentDao" ref="checkContentDao"/>
		<property name="xydaAppendixDao" ref="xydaAppendixDao"/>
		<property name="checkInfoDao" ref="checkInfoDao"/>
		<property name="checkInfoDetailDao" ref="checkInfoDetailDao"/>
	</bean>

	<jaxws:server serviceClass="com.hontek.platformswebservice.service.inter.PlatformsInter" address="/platform">
		<jaxws:serviceBean>
			<ref bean="platformsImpl"/>
		</jaxws:serviceBean>
	</jaxws:server>
	
	
	
</beans> 

apache-cxf-2.6.16版本需要在上面配置文件中加入下面三行

	<import resource="classpath:META-INF/cxf/cxf.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>

注意:如果你的版本是3.0以上的,因为多了下面两个xml文件,所以也会报错;只需要引入第一个就可以;如果你的CXF版本是3.0以下;那么需要引入三个配置文件。

2. 配置applicationContext.xml,如下:

	<!-- webservice 接口配置文件 -->
	<import resource="config/webservice/application/service-ws.xml"/>

3. 配置web.xml,如下:

  <servlet>
    <servlet-name>CXFService</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFService</servlet-name>
    <url-pattern>/CXFService/*</url-pattern>
  </servlet-mapping>

第二步:创建webservice接口,如下:

package com.hontek.platformswebservice.service.inter;
import com.hontek.platformswebservice.comm.*;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import java.util.List;

@WebService
@SOAPBinding(style = Style.RPC)
@SuppressWarnings("deprecation")
public interface PlatformsInter {
	
	/**
	 * 获取口令
	 * @Author yang
	 * @Date   2020/05/06 16:55
	 **/
	public String getToken(@WebParam(name="account")String account,@WebParam(name="password")String password);

	/**
	 * 更新心跳接口
	 * @Author yang
	 * @Date   2020/05/06 16:59
	 **/
	public String active(@WebParam(name = "token") String token);

	/**
	 * 退出接口
	 * @Author yang
	 * @Date   2020/05/06 16:59
	 **/
	public String logout(@WebParam(name = "token") String token);

	/**
	 * 同步产品信息
	 * @Author yang
	 * @Date   2020/05/07 18:07
	 **/
	public String syncProTypeQrCode(@WebParam(name="token")String token, @WebParam(name="proTypeQrcode") ProTypeQrcodeEntity proTypeQrcode);
}

以上webservice接口使用RPC方式,并且包含系统对接时候需要的安全验证接口(获取token、更新心跳、退出,可以根据自己的需求进行修改)

第三步:创建webservice实现类,如下

package com.hontek.platformswebservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.hontek.certificate.dao.CaInfoDao;
import com.hontek.certificate.pojo.CaInfo;
import com.hontek.certificate.pojo.Certificate;
import com.hontek.certificate.service.inter.CertificateServiceInter;
import com.hontek.comm.util.DateUtil;
import com.hontek.comm.util.DirectoryUtil;
import com.hontek.comm.util.IDUtil;
import com.hontek.comm.util.StringUtil;
import com.hontek.company.dao.CheckContentDao;
import com.hontek.company.dao.CheckReportDao;
import com.hontek.company.dao.SpotCheckDao;
import com.hontek.company.dao.XydaAppendixDao;
import com.hontek.company.pojo.CheckContent;
import com.hontek.company.pojo.CheckReport;
import com.hontek.company.pojo.SpotCheck;
import com.hontek.company.pojo.XydaAppendix;
import com.hontek.detectiondevice.comm.DetectionReportUtils;
import com.hontek.detectiondevice.dao.CheckInfoDao;
import com.hontek.detectiondevice.dao.CheckInfoDetailDao;
import com.hontek.detectiondevice.pojo.CheckInfo;
import com.hontek.detectiondevice.pojo.CheckInfoDetail;
import com.hontek.platformswebservice.comm.*;
import com.hontek.platformswebservice.service.inter.PlatformsInter;
import com.hontek.record.dao.ProTypeQrcodeDao;
import com.hontek.record.pojo.TbProTypeQrcode;
import com.hontek.review.dao.ProTypeDao;
import com.hontek.review.pojo.TbProType;
import com.hontek.sys.dao.EnterpriseDao;
import com.hontek.sys.dao.InterAccountDao;
import com.hontek.sys.dao.UserDao;
import com.hontek.sys.pojo.TbInterAccount;
import com.hontek.sys.pojo.TsEnterprise;
import com.hontek.sys.pojo.TsUser;
import com.hontek.sys.service.inter.EnterpriseServiceInter;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.log4j.Logger;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

@WebService
@SOAPBinding(style = Style.RPC)
public class PlatformsImpl implements PlatformsInter {


	private Logger logger = Logger.getLogger(PlatformsImpl.class);

	private InterAccountDao interAccountDao;
	private EnterpriseServiceInter enterprseService;
	private CertificateServiceInter certificateServiceInter;
	private ProTypeDao proTypeDao;
	private EnterpriseDao enterpriseDao;
	private ProTypeQrcodeDao proTypeQrcodeDao;
	private CaInfoDao caInfoDao;
	private UserDao userDao;


	public void setInterAccountDao(InterAccountDao interAccountDao) { this.interAccountDao = interAccountDao; }
	public void setEnterprseService(EnterpriseServiceInter enterprseService) { this.enterprseService = enterprseService; }
	public void setCertificateServiceInter(CertificateServiceInter certificateServiceInter) { this.certificateServiceInter = certificateServiceInter; }
	public void setProTypeDao(ProTypeDao proTypeDao) { this.proTypeDao = proTypeDao; }
	public void setEnterpriseDao(EnterpriseDao enterpriseDao) { this.enterpriseDao = enterpriseDao; }
	public void setProTypeQrcodeDao(ProTypeQrcodeDao proTypeQrcodeDao) { this.proTypeQrcodeDao = proTypeQrcodeDao; }
	public void setCaInfoDao(CaInfoDao caInfoDao) { this.caInfoDao = caInfoDao; }
	public void setUserDao(UserDao userDao) { this.userDao = userDao; }


	@Resource
	private WebServiceContext context;

	private HttpServletRequest getRequest(){
		MessageContext ctx = context.getMessageContext();
		HttpServletRequest request = (HttpServletRequest) ctx.get(AbstractHTTPDestination.HTTP_REQUEST);
		return request;
	}


	@Override
	public String getToken(String account, String password) {
		logger.info("-----获取token开始-----");
		ResultInfo result = new ResultInfo();
		result.setSuccess(false);
		try {
			if(account!=null&&!"".equals(account)&&password!=null&&!"".equals(password)){
				// 这里根据账号和密码获取账号信息可以根据自己业务需求进行修改
				String condition = " and account='"+account+"' and pass='"+password+"'";
				TbInterAccount interAccount = interAccountDao.getInterAccount(condition);
				if(interAccount!=null){
					String token = UUID.randomUUID().toString().replace("-", "");
					SoleManager manager = SoleManager.getInstance();
					interAccount.setTime(System.currentTimeMillis());
					manager.putAccount(token, interAccount);
					result.setCode("1000");
					result.setMsg("获取token成功");
					result.setData(token);
					result.setSuccess(true);
				}else {
					result.setCode("1003");
					result.setMsg("帐号或密码错误");
				}
			}else {
				result.setCode("1002");
				result.setMsg("帐号或密码为空");
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("获取token失败:"+e.getMessage());
			result.setCode("1001");
			result.setMsg("获取token失败");
		}
		return JSONObject.fromObject(result).toString();
	}

	@Override
	public String active(String token) {
		logger.info("-----更新心跳开始-----");
		SoleManager manager = SoleManager.getInstance();
		TbInterAccount account = manager.getAccount(token);
		ResultInfo result = new ResultInfo();
		result.setSuccess(false);
		if(account != null){
			account.setTime(System.currentTimeMillis());
			result.setSuccess(true);
			result.setCode("1000");
			result.setMsg("更新心跳成功");
		}else {
			result.setCode("1004");
			result.setMsg("该令牌无效");
		}
		return JSONObject.fromObject(result).toString();
	}

	@Override
	public String logout(String token) {
		SoleManager manager = SoleManager.getInstance();
		TbInterAccount account = manager.getAccount(token);
		ResultInfo result = new ResultInfo();
		if(account != null){
			manager.cleanMap(token);
		}
		result.setSuccess(true);
		result.setCode("1000");
		result.setMsg("退出成功");
		return JSONObject.fromObject(result).toString();
	}

	@Override
	public String syncCompanyInfo(String token, CompanyEntity company) {
		logger.info("-----同步企业信息-----");
		ResultInfo result = new ResultInfo();
		result.setSuccess(false);
		SoleManager manager = SoleManager.getInstance();
		TbInterAccount account = manager.getAccount(token);
		if(account != null){
			try {
				//更新心跳
				manager.active(account);
				if(company != null){
					TsEnterprise ent = new TsEnterprise();
					ent.setParentId(account.getEntId());
					ent.setName(company.getCompanyName());
					ent.setIntro(company.getIntro());
					ent.setOrgCode(company.getOrgCode());
					ent.setLegalPerson(company.getLegalPerson());
					ent.setRegAddr(company.getRegAddr());
					ent.setManageAddr(company.getManagerAddr());
					ent.setEmail(company.getEmail());
					ent.setDomName(company.getDomName());
					ent.setCrtUserId(account.getUserId());
					ent.setFlag("3");//设置为企业
					ent.setSts("0");
					ent.setIsReported("1");//设置为上报企业
					ent.setEntType(Integer.parseInt(company.getEntType()==null?"2":company.getEntType()));//2默认设置为私企
					ent.setCrtDt(DateUtil.formatDateTime());
					ent.setMobile(company.getMobile());
					ent.setSysCode(account.getSysCode());
					ent.setOldEntId(company.getCompanyId());
					ent.setAreaName(company.getAreaName());
					ent.setQualificationType(company.getQualificationType());
					ent.setBusiness(company.getBusiness());
					ent.setPurl("");
					ent.setMurl("");
					Map<String, String> restMap = enterprseService.addSynchCompanyInfo(ent,getRequest());

					String flag = restMap.get("flag");
					if(flag!=null&&"0".equals(flag)){
						result.setCode("1000");
						result.setSuccess(true);
						result.setMsg("同步企业数据成功");
					}else if(flag!=null&&"2".equals(flag)){
						result.setCode("1000");
						result.setSuccess(true);
						result.setMsg("企业已存在,更新企业数据成功");
					}else if(flag!=null&&"3".equals(flag)){
						result.setCode("1005");
						result.setMsg("同步企业数据失败");
					}else {
						result.setCode("1006");
						result.setMsg("参数错误");
					}
				}
			}catch (Exception e){
				e.printStackTrace();
				result.setCode("1007");
				result.setMsg("同步企业数据异常");
				logger.info(e.getMessage());
			}
		}else {
			result.setCode("1008");
			result.setMsg("登陆超时,请重新登陆");
		}
		return JSONObject.fromObject(result).toString();
	}

	@Override
	public String syncProTypeQrCode(String token, ProTypeQrcodeEntity proTypeQrcode) {
		logger.info("-----同步产品信息-----");
		ResultInfo result = new ResultInfo();
		result.setSuccess(false);
		SoleManager manager = SoleManager.getInstance();
		TbInterAccount account = manager.getAccount(token);
		if(account != null){
			try {
				//更新心跳
				manager.active(account);
				String entId = String.valueOf(proTypeQrcode.getCompanyId());
				TsEnterprise enterprise = enterpriseDao.findEnterpriseBySysCodeAndOldEndId(account.getSysCode(), entId);
				if(enterprise!=null){
					if(proTypeQrcode != null){
						TbProTypeQrcode proTypeQrcode2 = new TbProTypeQrcode();
						proTypeQrcode2.setTypeId(Integer.parseInt(proTypeQrcode.getTypeId()));
						proTypeQrcode2.setProName(proTypeQrcode.getProName());
						proTypeQrcode2.setSysCode(account.getSysCode());
						proTypeQrcode2.setOldPtqId(String.valueOf(proTypeQrcode.getPtqId()));
						proTypeQrcode2.setOldDimenno(proTypeQrcode.getProCode());
						proTypeQrcode2.setProDesc(proTypeQrcode.getProDesc());
						//检查是否存在数据
						int count = proTypeQrcodeDao.countBySql("select count(*) from tb_pro_type_qrcode where sys_code='"+account.getSysCode()+"' and old_ptq_id='"+proTypeQrcode.getPtqId()+"'");
						if(count==0){
							proTypeQrcode2.setEntId(enterprise.getEntId());
							String ptqIdStr  = IDUtil.getPrimaryID();
							proTypeQrcode2.setPtqId(ptqIdStr);
							//产生二维码
							String dimenno = "";
							dimenno = enterprise.getEntCode();//entCode = 6位行政区域编码+6位(全省)顺序码
							String dimennoSeq = "01";
							String maxDimenno = proTypeQrcodeDao.findMaxDimennoByEntId(enterprise.getEntId());
							String lastTwoStr="";
							if(maxDimenno!=null&&!"".equals(maxDimenno)){
								lastTwoStr = maxDimenno.substring(maxDimenno.length()-2);
								dimennoSeq = StringUtil.getPtqLastTwoStr(lastTwoStr);
							}
							if("Z9".equals(dimennoSeq)){
								result.setCode("1010");
								result.setMsg("产品数量超出系统允许范围!");
							}else{
								dimenno += dimennoSeq;
								proTypeQrcode2.setDimenno(dimenno);
								proTypeQrcode2.setCrrtime(DateUtil.formatDateTime());
								logger.info("同步产品:"+ JSON.toJSONString(proTypeQrcode2));
								proTypeQrcodeDao.save(proTypeQrcode2);
								result.setSuccess(true);
								result.setCode("1000");
								result.setMsg("同步产品数据成功!");
								result.setData(ptqIdStr);

							}
						}else {
							TbProTypeQrcode typeQrcode = proTypeQrcodeDao.getProTypeQrcode(" and sysCode = '"+account.getSysCode()+"' and oldPtqId = '"+proTypeQrcode.getPtqId()+"'");
							logger.info("该产品已同步:"+JSON.toJSONString(proTypeQrcode));
							result.setCode("1011");
							result.setMsg("该产品已同步!");
							result.setData(typeQrcode.getPtqId());
						}
					}
				}else {
					logger.info("同步产品失败,该企业未同步:"+JSON.toJSONString(proTypeQrcode));
					result.setCode("1012");
					result.setMsg("同步产品失败,该企业未同步!");
				}
			}catch (Exception e){
				e.printStackTrace();
				result.setCode("1013");
				result.setMsg("同步产品数据异常");
				logger.info(e.getMessage());
			}
		}else {
			result.setCode("1008");
			result.setMsg("登陆超时,请重新登陆");
		}
		return JSONObject.fromObject(result).toString();
	}

	
}


3.1 创建ResultInfo返回结果实体类,如下:

package com.hontek.platformswebservice.comm;

/**
 * 返回结果实体类
 * @Author yang
 **/
public class ResultInfo {

	private String code;		//code码
	private boolean success;	// 判断调用是否成功 true:成功 false:失败
	private Object data;		// 数据
	private String msg;			// 信息

	public String getCode() { return code; }
	public void setCode(String code) { this.code = code; }
	public boolean isSuccess() { return success; }
	public void setSuccess(boolean success) { this.success = success; }
	public Object getData() { return data; }
	public void setData(Object data) { this.data = data; }
	public String getMsg() { return msg; }
	public void setMsg(String msg) { this.msg = msg; }

}

3.1 创建SoleManager线程类实现token过期时间及更新和销毁,如下:

package com.hontek.platformswebservice.comm;

import com.hontek.sys.pojo.TbInterAccount;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


public class SoleManager {

	static final private SoleManager instance = new SoleManager();

	private Map<String, TbInterAccount> accountMap = new HashMap<String, TbInterAccount>();

	public static SoleManager getInstance(){
		return instance;
	 }

	public SoleManager() {
		TimeOut timeout = new TimeOut();
		timeout.start();
	}
	
	synchronized public TbInterAccount getAccount(String token){
		TbInterAccount interAccount = accountMap.get(token);
		if(interAccount!=null)
			interAccount.setTime(System.currentTimeMillis());
		return interAccount;
	}
	
	synchronized public void putAccount(String token,TbInterAccount interAcount){
		this.accountMap.put(token, interAcount);
	}

	
	public class TimeOut extends Thread{
		public void run(){
			long keepTime = 1000L*60*60*10;
			
			while(true){
				try {
					Thread.sleep(1000*60*60*3);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				Set<String> setKey = accountMap.keySet();
				Iterator<String> it = setKey.iterator();
				while(it.hasNext()){
					String key = it.next();
					TbInterAccount interAccount = accountMap.get(key);
					if(System.currentTimeMillis()-interAccount.getTime()>keepTime){
						accountMap.remove(key);
					}
				}
				
			}
		}
	}
	
	/**
	 * 心跳
	 * @param interaccount
	 */
	public void active(TbInterAccount interaccount){
		if(interaccount!=null){
			interaccount.setTime(System.currentTimeMillis());
		}
	}
	/**
	 * 注销
	 * @param token
	 */
	synchronized public void cleanMap(String token){
		TbInterAccount interAccount = accountMap.get(token);
		if(interAccount!=null){
		    interAccount = null;
		    accountMap.remove(token);
		}
	}
}

第四步:发布

*访问路径:域名/项目/CXFService/platform?wsdl,出现如下xml格式的数据说明发布成功*

在这里插入图片描述

第五步:测试

5.1 idea中创建webservice客户端进行测试,如下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
5.2 使用测试工具如postman、SoapUI Pro 5.1.2进行测试,如下是soapui进行测试:
在这里插入图片描述

第六步:总结:

前期接口写好后首先自己先测试下看看代码有无问题是否能调通接口,如没问题,接下来最好是写一份对接文档进行说明(如下图),再一个跟对三方进行对接时要先在测试环境或者自己本地服务器进行联调(使用内网穿透,我这边使用的是花生壳进行内网穿透),最后发布到正式环境中。

在这里插入图片描述

欢迎小伙伴留言评论,需要完整代码的加我QQ:450938667

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值