SCA(Tascany)+Spring+Hibernate开发与使用范例

1. 概述
本文档描述了基于Eclipse3.5和Apache Tascany基础之上的Spring快速入门的使用范例。感兴趣的朋友MSN:huangyungang@hotmail.com交流,也可mail说明。
本文将着手了解或解决如下内容:
 Spring 开发 SCA 组件时需要掌握的一些基本设计原则。
 如何将 Spring beans 公开为 SCA 服务,
 如何在 Spring 应用程序中访问 SCA 服务和属性。
 如何使用 Spring Framework 和 Apache Tuscany SCA Java 运行时来设计和开发 SCA 组件。。
 如何结合 SCA 与 Spring 来创建分布式服务应用程序。

2. 开发环境
2.1. 环境准备
为了在实践中完成下面文中描述的内容,您需要以下工具:

[img]http://dl.iteye.com/upload/attachment/237398/8b5213d5-8a95-3b56-83b7-466c1010e1e2.png[/img]
表1-开发环境要素
2.2. 环境搭建(参考SCA(Tascany)环境搭建和使用范例)


3. SCA 与 Spring 两者相结合的优势
  Spring Framework 与 SCA 采用许多相同的设计原则。SCA 将 Spring 视为其组件的一种实现技术。SCA Sprig Component Implementation Specification 定义了如何采用这种方式来使用 Spring。
与 Spring bean 类似,SCA 组件可以包含到其他组件所提供的服务的引用,并且有一些属性可供配置。
与 Spring 形成对比的是,SCA 是一种跨语言的分布式组件架构,它支持多种组件通信机制。通过将 Spring beans 发布为可由其他组件访问的服务并为 Spring beans 提供关联到其他(可能为远程)组件的服务的引用,SCA 可以扩展 Spring 组件的功能。
4. SCA与Spring 结合的原则
要将 SCA 与 Spring 相结合,一种有效的方法是使用 Spring 来构建 “粗粒度” 的服务组件实现,并引入到 SCA 中以便公开服务、关联服务组件以及处理异构和分布式系统。SCA 可以在使用 Spring 实现的应用程序中添加一些有用的功能,比如说:
 对远程组件以及多种协议的扩展支持
 支持使用不受 JVM 支持的各种编程语言来编写组件
 支持 WS-Policy 针对安全性和事务等活动指定的策略
 易于测试组件是 Spring 的一项优异的特性。
缺少 API 和注入技术导致您只能使用简单的模拟对象进行测试。SCA 在服务方面对此进行了补充,因为关于服务组件的 SCA 复合集可以方便地切换到模拟配置以进行测试。
5. Tuscany SCA与Spring结合的步骤
5.1. 将 Spring 应用程序定义为 SCA 组件
创建一个包含一个 Spring 组件的 SCA 复合集
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" 
   xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.0" 
   targetNamespace="http://calc" 
   xmlns:c="http://calc" 
   name="Calculator"> 
  <component name="CalculatorServiceComponent"> 
       <implementation.spring location="targetURI"/> 
  </component> 
</composite> 

其中:
<implementation.spring> 元素的位置属性可以指定目标 URI 指向某个存档文件 (.jar) 或 目标,或者 直接指向 Spring 应用程序上下文。
以下列表给出了指定 <implementation.spring> 位置属性的目标 URI 的可能方法。

[img]http://dl.iteye.com/upload/attachment/237401/195413c7-b8ca-31b5-9a80-4a62c6aa5814.png[/img]
一个 Spring 应用程序可被定义为 SCA 复合集(即 SCDL:SCDL is used to describe SCA elements such as modules, references, imports, and exports)内的一个 SCA 组件。其形式如下图所示:


[img]http://dl.iteye.com/upload/attachment/237403/c785388e-8b63-3f75-a326-96f5e5688be4.png[/img]

其中<implementation.spring>用于指定实现component的Spring bean配置文件。而location则指定的bean文件的位置或目录(关于目录下面的示例中包含)。


6. 示例程序(WebService+SCA+Spring+Hibernate)
下面我们来开发一个示例程序。在本示例中,您将看到如何利用SCA集成现有的Spring组件,并对其进行向外发布。

6.1. 创建工程
首先我们在d:\TuscanyWorkspace\工作区下,创建一个名为SpringDemo “Dynamic Web Project”的工程。加载TuscanyLibrary(在开发环境建立一文中已经指出)。并将apache-tuscany-sca-1.6.zip的lib目录中的.jar文件COPY到工程的lib目录中。
以上是一个Java Application中对OSOA包的使用。当然对于Java Web Application需要将这些包加到Web Application的lib目录下。同时本示例还需要将hibernate和c3p0的JAR包加入到lib目录下。
6.2. 代码
下面的我们要实现的是基于Apache Tomcat来发布一个tuscany的SCA组件。
程序代码的包结构如下图所示:

[img]http://dl.iteye.com/upload/attachment/237405/37a8770c-4c27-3bd0-a899-761c3e791f6b.png[/img]
图6-示例程序的包结构
6.2.1. 创建基于Hibernate的数据访问程序
6.2.1.1. 创建Hibernate工具类—HibernateUtil.java
此类主要用于实现对数据库的CRUD基本操作,需要注意的是hibernate.cfg.xml文件是通过注入的方式来实现的。
package net.jite.waf.persistent.util;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

/**
* desc: Hibernate的通用类 <br/>
* 用于对Hibernate SessionFactory的初始化以及Hibernate Session的管理
* @author <a href="mailto:huangyungang@hotmail.com">huangyungang </a>
*
*/
public class HibernateUtil {
private SessionFactory _sf;
private static final ThreadLocal session = new ThreadLocal();
private String configFile;
/**
* 设置默认的配置文件名
*
* @param cfgFile
*/
public void setConfigFile(String cfgFile){
configFile=cfgFile;
}
/**
* 初始化此对象
*
*/
public void init(){
try {
Configuration config = new Configuration().configure(configFile);
if ("true".equals(config.getProperty("createtable"))) {
new SchemaExport(config).create(true, true);
}
if ("true".equals(config.getProperty("updatetable"))) {
new SchemaUpdate(config).execute(true, true);
}
_sf = config.buildSessionFactory();
} catch (HibernateException e) {
throw new RuntimeException("初始化Hibernate SessionFactory失败", e);
}
}
/**
* 获取一个Session
* @return Session
* @throws HibernateException
*/
public Session currentSession() throws HibernateException {
Session s = (Session) session.get();
if (s == null) {
s = _sf.openSession();
session.set(s);
}
return s;
}
/**
* 关闭Session
*
* @throws Exception
*/
public void closeSession() throws HibernateException {
Session s = (Session) session.get();
if (s != null)
s.close();
session.set(null);
}
}

6.2.1.2. 创建一个CommonDao类
CommonDao实现了基本的数据访问操作,这里的CommonDao可以被Service层去调用。代码如下:
import java.io.Serializable;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import user.util.HibernateUtil;

public class CommonDao {
private Session _session;
private HibernateUtil util;

public Session get_session() {
return _session;
}
public void set_session(Session session) {
_session = session;
}
public HibernateUtil getUtil() {
return util;
}
private boolean isOSIV;
//***********************增加的内容********************************
/**
* 根据主键ID删除obj
*
* @throws Exception
* 删除时出错则抛出
*/
public void deleteById(Class po, String id) throws Exception {
// Object obj = getById(po, id);
// delete(obj);
_session=getSession();
Transaction tx = _session.beginTransaction();
try
{

_session.delete(_session.get(po,id));
tx.commit();
}
catch (HibernateException e) {
// 在目前的HRibernate版本中当无对应的id的主键记录存在时抛出的异常
tx.rollback();
} finally {
closeSession();
}
}
/**
*
* desc:新添加的方法,用于匹配CMS数据库中的字符串主键
* @author huangyg
*
**/

public Object getById(Class po,String id) throws Exception {
_session = getSession();
try {
//return _session.load(po,id);
return _session.get(po, id);
} catch (HibernateException e) {
// 在目前的Hibernate版本中当无对应的id的主键记录存在时抛出的异常
return null;
} finally {
closeSession();
}
}
//***************************end*************************************
//***************************************************************
/**
* 设置获取Hibernate Session的通用类
*/
public void setUtil(HibernateUtil util) {
this.util = util;
}

/**
* 持久化obj
*
* @throws Exception
* 持久化过程时出错则抛出
*/
public void save(Object obj) throws Exception {
_session = getSession();
Transaction tx = _session.beginTransaction();
try {
_session.save(obj);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
// log.error("Hibernate进行持久化Object时错误", e);
throw new Exception("Hibernate进行持久化Object时错误");
} finally {
closeSession();
}
}

/**
* 更新obj
*
* @throws Exception
* 更新时出错则抛出
*/
public void update(Object obj) throws Exception {
_session = getSession();
Transaction tx = _session.beginTransaction();
try {
_session.update(obj);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
// log.error("Hibernate更新Object时错误", e);
throw new Exception("Hibernate更新Object时错误");
} finally {
closeSession();
}
}

/**
* 删除obj
*
* @throws Exception
* 删除时出错则抛出
*/
public void delete(Object obj) throws Exception {
_session = getSession();
Transaction tx = _session.beginTransaction();
try {
_session.delete(obj);
tx.commit();
} catch (HibernateException e) {
tx.rollback();
// log.error("Hibernate删除Object时错误", e);
throw new Exception("Hibernate删除Object时错误");
} finally {
closeSession();
}
}

/**
* 根据主键ID删除obj
*
* @throws Exception
* 删除时出错则抛出
*/
public void deleteById(Class po, int id) throws Exception {
Object obj = getById(po, new Integer(id));
delete(obj);
}

/**
* 清空某po所有的数据 强烈建议尽量不要使用此方法,一般来说不要物理删除数据,置状态比较合适
*
* @param po
* @throws Exception
*/
public void deleteAll(Class po) throws Exception {
_session = getSession();
Transaction tx = _session.beginTransaction();
try {
_session.createQuery("delete from " + po.getName()).executeUpdate();
tx.commit();
} catch (HibernateException e) {
tx.rollback();
// log.error("Hibernate清空PO中数据时错误", e);
throw new Exception( "Hibernate清空PO中数据时错误");
} finally {
closeSession();
}
}

/**
* 根据为int型的主键ID获取对应的Object
*
* @param obj
* @param id
* @return Object
* @throws Exception
*/
public Object getById(Object obj, int id) throws Exception {
return getById(obj.getClass(), new Integer(id));
}

/**
* 根据主键ID获取对应的Object
*
* @param obj
* @param id
* @return Object
* @throws Exception
*/
public Object getById(Object obj, Serializable id) throws Exception {
return getById(obj.getClass(), id);
}

/**
* 根据为int型的主键ID获取对应的Object
*
* @param obj
* @param id
* @return Object
* @throws Exception
*/
public Object getById(Class po, int id) throws Exception {
return getById(po, new Integer(id));
}

/**
* 根据主键ID获取对应的Object
*
* @param obj
* @param id
* @return Object
* @throws Exception
*/
public Object getById(Class po, Serializable id) throws Exception {
_session = getSession();
try {
return _session.get(po, id);
} catch (HibernateException e) {
// 在目前的Hibernate版本中当无对应的id的主键记录存在时抛出的异常
return null;
} finally {
closeSession();
}
}

// For Business Method

/**
* 根据需执行的hql返回List <br>
* 建议对于数据量小或一次进行频繁查询的使用
*
* @param hql
* @return java.util.List
* @throws Exception
*/
public List getListByHql(String hql) throws Exception {
return null;
}


/**
* 获取Session
*
* @throws Exception
*/
public Session getSession() {
return util.currentSession();
}
/**
* 关闭Session
*
* @throws Exception
*/
public void closeSession() {
// Use Open Session In View,so we don't close session
if (!isOSIV) {
util.closeSession();
}
}

// ============================== get/set

public void setOSIV(boolean isOSIV) {
this.isOSIV = isOSIV;
}

}

6.2.1.3. 创建一个POJO类和Hibernate的.hbm.xml映射文件
POJO类代码如下:
package user.domain;

public class User {
private Integer id;
private String username;
private String password;
private int sex;
private String address;
public String toString(){
return null;
}
public Integer getId(){
return this.id;
}
public void setId(Integer id){
this.id=id;
}
public String getUsername(){
return this.username;
}
public void setUsername(String username){
this.username=username;
}
public String getPassword(){
return this.password;
}
public void setPassword(String password){
this.password=password;
}
public void setSex(int sex){
this.sex=sex;
}
public int getSex(){
return this.sex;
}
public void setAddress(String address){
this.address=address;
}
public String getAddress(){
return this.address;
}
}

User.hbm.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping
>
<class
name="user.domain.User"
table="userinfo"
>
<id
name="id"
column="ID"
type="java.lang.Integer"
length="10"
unsaved-value="0"

>
<generator class="increment" />
</id>
<property
name="username"
type="java.lang.String"
update="true"
insert="true"
column="username"
not-null="false"
unique="false"
/>
<property
name="password"
type="java.lang.String"
update="true"
insert="true"
column="password"
not-null="false"
unique="false"
/>
<property
name="address"
type="java.lang.String"
update="true"
insert="true"
column="address"
not-null="false"
unique="false"
/>
</class>

</hibernate-mapping>


6.2.1.4. 创建hibernate.cfg.xml文件
hibernate.cfg.xml内容如下:
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/soademo?useUnicode=true&
characterEncoding=GBK</property>
<property name="connection.username">root</property>
<property name="connection.password">admin</property>
<!-- org.hibernate.dialect.OracleDialect -->
<!-- org.hibernate.dialect.MySQLDialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="jdbc.fetch_size">50</property>
<property name="show_sql">true</property>
<property name="createtable">false</property>
<property name="updatetable">true</property>
<property name="c3p0.min_size">1</property>
<property name="c3p0.max_size">30</property>
<property name="c3p0.max_statements">100</property>
<property name="c3p0.idle_test_period">5000</property>
<!--浮标管理-->
<mapping resource="user/domain/User.hbm.xml" />
<!--缓存配置-->
</session-factory>
</hibernate-configuration>

6.2.2. 创建基于SCA容器并集成Spring的Composite
6.2.2.1. 在web.xml中添加tuscany过滤器
<filter>
<filter-name>tuscany</filter-name>
<filter-class>org.apache.tuscany.sca.host.webapp.TuscanyServletFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>tuscany</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

需要注意的是,这里不需要添加Spring ContextLoaderListener,SCA具备自已独立的容器,直接访问Spring容器内部的Beans比较困难,因为它们不在同一容器内。下面的代码我们是不需要加到web.xml文件中的。
<!--
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
-->

6.2.2.2. 创建Spring Bean配置
Spring bean的配置共包括三部分内容:
 Bean的自身定义
 供外部调用Service定义
 聚合其它Service的引用定义

在WebContent/spring-context目录下创建beans-user.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:sca="http://www.springframework.org/schema/sca"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/sca http://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd"
>
<sca:service name="UserService"
type="user.service.UserService"
target="userServiceBean"/>

<bean id="userServiceBean" class="user.service.UserServiceImpl">
<property name="dao" ref="CommonDaoService"/>
</bean>
<sca:reference name="CommonDaoService" type="user.dao.CommonDao" ></sca:reference>
</beans>

创建beans-commondao.xml,内容如下:
<?xml version="1.0" encoding="gbk"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sca="http://www.springframework.org/schema/sca"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/sca http://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd"
>
<!--Bean对外提供 -->
<sca:service name="CommonDaoService"
type="user.dao.CommonDao"
target="commonDaoBean"/>
<!--Bean自身定义 -->
<bean id="commonDaoBean" class="user.dao.CommonDao">
<property name="util" ref="HibernateUtilService"></property>

</bean>
<!--Bean引用别的 -->
<sca:reference name="HibernateUtilService" type="user.util.HibernateUtil" ></sca:reference>
</beans>

创建beans-hibernate-util.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:sca="http://www.springframework.org/schema/sca"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/sca http://www.osoa.org/xmlns/sca/1.0/spring-sca.xsd"
>
<sca:service name="HibernateUtilService"
type="user.util.HibernateUtil"
target="HibernateUtilBean"/>
<bean id="HibernateUtilBean" class="user.util.HibernateUtil" init-method="init">
<property name="configFile" value="/hibernate.cfg.xml"/>
</bean>
</beans>


6.2.2.3. 创建SCA包装
User.composite文件
<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns:c="http://User"
targetNamespace="http://User"
name="User">
<service name="UserService" promote="UserServiceComponent">
<binding.ws></binding.ws>
</service>
<component name="UserServiceComponent">
<implementation.spring location="spring-context/beans-user.xml"/>
<reference name="CommonDaoService" target="CommonDaoServiceComponent"></reference>
</component>
</composite>
其中:
 spring-context/beans-user.xml的完全路径是WebContent/Spring-context/beans-user.xml
 此处使用<binding.ws></binding.ws>将UserService发布成了一个WebService
 Component的引用关系注意描述,由于UserService中需要使用CommonDao的内容,在SCA的Component层面也需要进行定义。例如<reference name="CommonDaoService" target=
"CommonDaoServiceComponent"></reference>。
CommonDao.composite
<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns:c="http://User"
targetNamespace="http://User"
name="CommonDao">
<service name="CommonDaoService" promote="CommonDaoServiceComponent">
</service>
<component name="CommonDaoServiceComponent">
<implementation.spring location="spring-context/beans-commondao.xml"/>
<reference name="HibernateUtilService" target="HibernateUtilServiceComponent"></reference>
</component>
</composite>

HibernateUtil.composite

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns:c="http://User"
targetNamespace="http://User"
name="HibernateUtil">
<service name="HibernateUtilService" promote="HibernateUtilServiceComponent">

</service>
<component name="HibernateUtilServiceComponent">
<implementation.spring location="spring-context/beans-hibernate-util.xml"/>
</component>
</composite>


6.2.2.4. 创建MySQL数据表
在本机的MySQL数据库soademo中,建一张userinfo表。
/*
Navicat MySQL Data Transfer
Source Host : localhost:3306
Source Database : soademo
Target Host : localhost:3306
Target Database : soademo
Date: 2010-04-19 17:35:13
*/

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for userinfo
-- ----------------------------
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
`id` int(11) NOT NULL default '0',
`username` varchar(200) default NULL,
`password` varchar(100) default NULL,
`sex` int(2) default NULL,
`address` varchar(200) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of userinfo
-- ----------------------------
INSERT INTO `userinfo` VALUES ('1', '1', '1', null, '1');

6.2.3. 执行情况
在SOAPUI工具中调用已经发布的WebService,运行http://localhost:8080/springdemo/UserService?wsdl得到如下结果:

[img]http://dl.iteye.com/upload/attachment/237408/9de23882-3b1e-3975-baa0-8b32061ca6ce.png[/img]
SOAPUI调用情况如下(SOAPUI工具可从网络中下载):


[img]http://dl.iteye.com/upload/attachment/237408/9de23882-3b1e-3975-baa0-8b32061ca6ce.png[/img]
Tomcat结果如下图所示:

[img]http://dl.iteye.com/upload/attachment/237413/51fb7fc4-cc7f-3e6d-b347-f3801c1a9075.png[/img]
最终显示Hibernate完成了向MySQL数据库添加一行记录。
主要内容:本文详细介绍了一种QRBiLSTM(分位数回归双向长短期记忆网络)的时间序列区间预测方法。首先介绍了项目背景以及模型的优势,比如能够有效利用双向的信息,并对未来的趋势上限和下限做出估计。接着从数据生成出发讲述了具体的代码操作过程:数据预处理,搭建模型,进行训练,并最终可视化预测结果与计算分位数回归的边界线。提供的示例代码可以完全运行并且包含了数据生成环节,便于新手快速上手,深入学习。此外还指出了模型未来发展的方向,例如加入额外的输入特性和改善超参数配置等途径提高模型的表现。文中强调了时间序列的标准化和平稳检验,在样本划分阶段需要按时间序列顺序进行划分,并在训练阶段采取合适的手段预防过度拟合发生。 适合人群:对于希望学习和应用双向长短时记忆网络解决时序数据预测的初学者和具有一定基础的研究人员。尤其适用于有金融数据分析需求、需要做多一步或多步预测任务的从业者。 使用场景及目标:应用于金融市场波动预报、天气状况变化预测或是物流管理等多个领域内的决策支持。主要目的在于不仅能够提供精确的数值预计还能描绘出相应的区间概率图以增强结论置信程度。 补充说明:本教程通过一个由正弦信号加白噪构造而成的简单实例来指导大家理解和执行QRBiLSTM流程的所有关键步骤,这既方便于初学者跟踪学习,又有利于专业人士作为现有系统的补充参考工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值