JSF详解

1.   结构:

a)        结构图:

    

b)        说明:JSFMVC模式为基础,与Struts不同,JSF的目标是希望以一个与Swing相类似的方式来开发网页,因此,从JSF的结构图当中,他的核心概念不是页面,而是控件树,也就是说,当用户提交一个请求时,JSF会先将页面上的组件先转换为与Swing当中类似的,由容器和控件组成的控件树,然后数据和事件被设置到对应的控件上,然后以一种与Swing类似的方式,来处理后续的请求。控件树是整个JSF的核心,所有其他的一切一切都是围绕着这棵控件树展开的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.   生命周期:

a)        周期图:

   

    b)        说明:

    b)        说明:

    b)        说明:

                      i.              Restore ViewJSF的处理核心是控件树,他会先将页面上所声明的控件转换为一棵控件树,后续的操作将在这颗控件树上进行。为了提高性能,系统会为之前生成的控件树提供缓存。Restore View的工作就是在缓存当中查找是否存在之前已经生成好的控件树,如果没有,则根据页面的内容,重新生成。

                   ii.              Apply Request Values:把请求当中的数据设置到控件树当中对应的控件当中去。

                iii.              Process Validations:如果某一控件有配置Validator,则这些Validator将对刚设置的数据的正确性和合法性进行验证。

                   iv.              Update Model Values:控件树上的控件更新其底层所对应的模型。

                      v.              Invoke Application:对产生的事件进行分发。

                   vi.              Render Response:构建作为响应的控件树。

 

 

 

3.   UI

a)        结构图:

b)        控件:

                      i.              说明:JSF通过标签库,提供了一些主要控件的实现。包括标签,文本框,单选框,列表等。由于JSF使用一种类似于UI的方式来组织组件,所以,除了基本的组件以外,还提供了一些用于布局的容器,例如面板等。在这里有一个要注意的地方就是,一般情况下,页面的内容应该放到JSF提供的view标签里面。

                   ii.              代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="1">

<h:outputLabel>

<h:outputText value="User ID"/>

</h:outputLabel>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

c)        事件处理:

                      i.              说明:与Struts不同,由于JSF使用以控件树为中心的方式来处理请求,所以,她提供了一种额外的类似Swing的,事件处理的方式来处理用户的输入事件。JSF提供了两种事件类型,ActionEvent,用于处理命令和ValueChangeEvent,用于处理数据更改。

                   ii.              代码:

模型代码:

package nick;

public class UserActionListener implements ActionListener {

     public void processAction(ActionEvent arg0)

throws AbortProcessingException {

         FacesContext context = FacesContext.getCurrentInstance();

         ValueBinding binding = Util.getValueBinding("#{user}");

         User user = (User) binding.getValue(context);

         String id = user.getId();

     }

}

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312" import="java.util.*"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="2">

<h:outputLabel for="id">

<h:outputText value="User ID"/>

</h:outputLabel>

<h:commandButton id="regist" value="注册">

<f:actionListener type="nick.UserActionListener"/>

</h:commandButton>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

注:通过嵌套actionListener标签,我们可以为一个控件注册监视器。

 

 

 

4.   数据绑定:

a)        说明:数据绑定要解决的问题就是如何把模型中的值,绑定到页面的控件上。在JSF当中这可以通过JSF所提供的配置文件来完成。

b)        代码:

配置文件:

<faces-config>

<managed-bean>

<managed-bean-name> user </managed-bean-name>

<managed-bean-class> nick.User </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

</faces-config>

 

 

 

模型代码:

package nick;

public class User {

     private String id = "Nick";

public void setId(String id) {

         this.id = id;

     }

     public String getId() {

         return this.id;

     }

}

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

     <head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="2">

<h:outputLabel for="id">

<h:outputText value="User ID"/>

</h:outputLabel>

<h:inputText id="id" value="#{user.id}"/>

                   </h:panelGrid>

              </h:form>

         </f:view>

     </body> 

</html>

 

 

 

注:通过配置文件,我们把nick.User类绑定到名称user上,然后页面的代码就可以直接使用#{user.xxx}来引用User这个类中的各个字段。

 

 

 

5.   页面流:

a)        页面到控制器:

                      i.              说明:JSF通过使用方法绑定的方式来定义从页面到控制器的跳转,和数据绑定相同,为了能够正确找到被绑定方法所在的类,我们需要首先在配置文件当中声明managed-bean,然后通过设置控件的action属性,定义页面到控制器的跳转逻辑。

                   ii.              代码:

配置文件:

<faces-config>

<managed-bean>

<managed-bean-name> user </managed-bean-name>

<managed-bean-class> nick.User </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

</faces-config>

 

 

 

模型代码:

package nick;

public class User {

     public String regist() {

         return "regist";

     }

     public String login() {

         return "login";

     }

}

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="2">

<h:commandButton id="regist"

action="#{user.regist}" value="注册"/>

<h:commandButton id="login"

action="#{user.login}" value="登陆"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

注:上述的页面代码,把注册按钮的动作绑定到User类的regist()方法,把登陆按钮的动作绑定到User类的login()方法。因此,当这两个按钮被点击时,对应的方法将被调用,用于实现页面流的方法,必须声明为public,而且她不接受参数,且返回值必须为String

 

 

 

b)        控制器到页面:

                      i.              说明:JSF通过名称绑定的方式,来定义从控制器到页面的跳转。为了实现从控制器到页面的跳转,我们需要在配置文件当中定义一些<navigation-rule>,这些rule主要定义了怎么根据上述action标签所绑定的方法的返回值来查找下一页面。

                   ii.              代码:

配置文件:

<faces-config>

<managed-bean>

<managed-bean-name> user </managed-bean-name>

<managed-bean-class> nick.User </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

 

 

 

<navigation-rule>

<from-view-id>/index.jsp</from-view-id>

<navigation-case>

<from-outcome>regist</from-outcome>

<to-view-id>/regist.jsp</to-view-id>

</navigation-case>

<navigation-case>

<from-outcome>login</from-outcome>

<to-view-id>/login.jsp</to-view-id>

</navigation-case>

</navigation-rule>

</faces-config>

模型代码:

package nick;

public class User {

     public String regist() {

         return "regist";

     }

     public String login() {

         return "login";

     }

}

 

 

 

注:上述的配置文件定义了一个<navigation-rule>,该rule指明了如果“/index.jsp”页面通过她内部的某个控件的action属性发生了跳转,那么当该跳转方法的返回值为字符串“regist”时,则页面将跳转到对应的“/regist.jsp”中,同理,如果返回值为“login”,则页面将跳转到“/login.jsp”。

 

 

 

6.   数据传输:

a)        页面到控制器:

                      i.              说明:在JSF的页面代码当中,通过数据绑定,我们把控件的value值,与某个后台的数据bean关联起来。而在前述的生命周期部分,我们看到,当一个JSF请求到达时,他需要经历Restore ViewApply Request Value等步骤,而Apply Request Value部分的工作,就是把请求当中的值绑定到这个后台的bean之中,因此,我们不需要考虑页面中的Form值如何传入到后台的bean当中。

进一步,如果录入控件的value属性,和命令控件的action属性都是绑定在同一个bean上的话,那么在页面跳转时,我们可以直接访问到bean的属性值。但是为了不污染模型,和实现控制与模型的分离,一般情况下,我们需要把输入控件的value值绑定到数据bean,而把命令控件的action值绑定到控制bean,由于两个bean不是同一个,所以,控制bean需要一种方法来获取数据bean中的属性值。

                   ii.              代码:

配置文件:

<faces-config>

<managed-bean>

<managed-bean-name> user </managed-bean-name>

<managed-bean-class> nick.User </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

<managed-bean>

<managed-bean-name> action </managed-bean-name>

<managed-bean-class> nick.Action </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

</faces-config>

 

 

 

模型代码:

              package nick;

public class User {

private String id = "Nick";

public void setId(String id) {

this.id = id;

}

public String getId() {

return this.id;

}

}

 

 

 

package nick;

public class Action {

     public String regist() {

         ValueBinding binding = Util.getValueBinding("#{user}");

         User user = (User)

binding.getValue(FacesContext.getCurrentInstance());

                      

         return "regist";

     }

}

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="2">

<h:outputLabel for="id">

<h:outputText value="User ID"/>

</h:outputLabel>

<h:inputText id="id" value="#{user.id}"/>

<h:commandButton id="regist"

action="#{action.regist}" value="注册"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

注:页面代码当中把输入控件的value绑定到了userid上,把命令控件的action值绑

定到actionregist上。当用户点击登陆按钮时,actionregist()方法将会被调用,

而在该方法内部,为了获取之前页面中的信息,我们可以使用ValueBinding类。该类使用

的数据绑定表达式与页面中的类似。

 

 

 

b)        控制器到页面:

                      i.              说明:通过之前的叙述,我们可以发现,当我们需要把数据从控制器传到页面时,我们同样可以使用数据绑定的方式,因为,当我们通过数据绑定表达式,获取到某个页面当中所使用的模型实例时,便可以在该实例上直接调用对应的set()方法,来设定所希望的值。

 

 

 

7.   插件功能:

a)        Converter(转换):

                      i.              说明:当模型中的某个字段需要在页面上显示时,她需要先被转换为字符串类型;而用户在页面输入的字符串值,在传到模型中时也需要根据模型对应字段的类型,进行一个转换。另外,由于国际化的要去,模型中的值在不同的地区会有不同的表示方式。为了解决以上这些问题,JSF提供了Converter的实现,她主要做的事情就是根据所在的地区,对页面数据和模型数据进行双向的转换。

                   ii.              代码:

模型代码:

package nick;

public class User {

     private Date date = new Date();

     public Date getDate() {

         return date;

     }

     public void setDate(Date date) {

         this.date = date;

     }

}

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="3">

<h:outputLabel for="date">

<h:outputText value="date"/>

</h:outputLabel>

<h:inputText id="date" value="#{user.date}">

<f:convertDateTime pattern="M/d/yyyy"/>

</h:inputText>

<h:message for="date"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

注:通过嵌套的convertXXX标签,我们可以为控件配置用于转换的转换器。我们可以使用两种方式来注册转换器,一是通过控件的convert属性,另外一种就是通过嵌套的convertXXX标签。如果在转换的时候发生错误,那么JSF将跳过转换以后的步骤,而直接跳到Render Response步骤,生成响应,并在FacesContext里添加一个出错的Message,该Message的内容可以通过message标签进行显示。

 

 

 

b)        Validate(验证):

                      i.              说明:在数据被交付后台处理以前,我们可以通过验证器,来验证输入的数据是否合法,这包括数值的大小,或者是字符串的长度等。使用验证器的好处就是我们可以把验证的代码从控制代码中单独出来,以便管理和重用。

                   ii.              代码:

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<body>

<f:view>

<h:form>

<h:panelGrid columns="3">

<h:outputLabel for="id">

<h:outputText value="User ID"/>

</h:outputLabel>

<h:inputText id="id" value="#{user.id}">

<f:validateLength minimum="3" maximum="6"/>

</h:inputText>

<h:message for="id"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

注:通过嵌套的validateXXX标签我们可以为一个控件注册一个验证器,与转换器不同,我们可以为一个控件注册多个验证器,以进行复杂的验证。注册验证器的方法也有两个,一是通过控件的validator属性,另外一种就是通过嵌套的validateXXX标签。与转换器类似,当验证失败时,失败的原因也会以Message的形式被放到FacesContext内,在页面内通过message标签可以对错误信息进行显示。

 

 

 

8.   国际化支持

a)        说明:为了提供对国际化的支持,JSF使用了与Struts类似的通过资源文件的形式,从外部获取需要显示的内容。

b)        代码:

配置文件:

<faces-config>

<application>

<message-bundle>nick.Messages</message-bundle>

<locale-config>

<default-locale>cn</default-locale>

<supported-locale>en</supported-locale>

</locale-config>

     </application>

</faces-config>

 

 

 

页面代码:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<f:loadBundle basename="nick.Messages" var="message"/>

<body>

<f:view>

<h:form>

<h:panelGrid columns="3">

<h:outputLabel for="id">

<h:outputText value="#{message.id}"/>

</h:outputLabel>

<h:inputText id="id" value="#{user.id}"/>

                            </h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

注:如果我们需要考虑国际化的问题时,那么我们需要为同一个资源提供多个地区的资源文件实现。通过在配置文件中声明message-bundle,我们可以注册资源文件的多个版本,以上面为例,她注册了两个资源文件nick.Messages_cn.propertiesnickcen.Messages_en.properties分别对应于中国和英国地区,当页面当中通过loadBundle标签读取资源时,她就会根据所在的区域,去查找对应的文件。当然,所有资源文件都应该使用java所提供的native2ascii工具,进行一下预处理。

 

 

 

9.   JSF定制:

a)        说明:该部分主要展示如何对JSF提供的转换器,验证器和控件进行定制,以扩展JSF的功能。

b)        配置文件定制:

                      i.              说明:JSF提供了比Struts更多的定制特性,包括用于实例化前端控制FacesServeltfaces-context-factory,用于实例化控件绘画RenderKitrender-kit-factory,进行声明周期管理的lifecyle-factory等。

                   ii.              代码:

配置文件:

<faces-config>

     <factory>

         <application-factory>…</application-factory>

         <faces-context-factory>…</faces-context-factory>

         <lifecycle-factory>…</lifecycle-factory>

         <render-kit-factory>…</render-kit-factory>

     </factory>

</faces-config>

 

 

 

c)        转换器定制:

                      i.              说明:通过扩展JSF提供的Converter接口,我们可以定义自己的转换器。而为了能在页面上使用自定义的转换器,我们需要在配置文件中,对转换器进行注册。

                   ii.              代码:

配置文件:

<faces-config>

<converter>

<converter-id>nameConverter</converter-id>

<converter-class>nick.NameConverter</converter-class>

</converter>

</faces-config>

 

 

 

模型文件:

package nick;

public class NameConverter implements Converter {

public Object getAsObject(FacesContext ar0, UIComponent ar1, String ar2) {

          return ar2.toLowerCase();

}

public String getAsString(FacesContext ar0, UIComponent ar1, Object ar2) {

          retrun ((String) arg2).toUpperCase();

}

}

 

 

 

页面文件:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<f:loadBundle basename="nick.Messages" var="message"/>

<body>

<f:view>

<h:form>

<h:panelGrid columns="3">

<h:outputLabel for="id">

<h:outputText value="#{message.id}"/>

</h:outputLabel>

<h:inputText id="id"

value="#{user.id}" immediate="true">

<f:converter converterId="nameConverter"/>

</h:inputText>

<h:message for="id"/>

<h:commandButton

action="#{action.regist}" value="Regist"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

注:当页面数据转换为后台数据时,ConvertergetAsObject()方法会被调用。而当需要把后台数据显示到页面中时,getAsString()方法会被调用。这里,我们注意到,我们的Converter是不能带任何配置属性的,为了让我们的Converter能够在页面中增加属性,我们需要进一步的定义自己的标签。除了可以根据converter-id来注册转换器以外,我们还可以使用converter-for-class标签来为某一特定的Java类型注册转换器。如果在转换过程中发生错误的话,那么我们可以通过抛出ConverterException来停止后续的工作。

 

 

 

d)        验证器定制:

                      i.              说明:通过扩展Validator接口,我们可以定义自己的验证器。而为了能在页面上使用自定义的验证器,我们需要在配置文件中,对验证器进行注册。

                   ii.              代码:

配置文件:

<faces-config>

<validator>

<validator-id>nameValidator</validator-id>

<validator-class>nick.NameValidator</validator-class>

</validator>

</faces-config>

 

 

 

模型文件:

package nick;

public class NameValidator implements Validator {

     public void validate(FacesContext arg0, UIComponent arg1, Object arg2)

              throws ValidatorException {

         String name = (String) arg2;

         if (!name.startsWith("nick")) {

              throw new ValidatorException(new FacesMessage(

                       "name must start with nick"));

         }

     }

}

 

 

 

页面文件:

<%@page contentType="text/html;charset=gb2312"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<html>

<head><title>Test</title></head>

<f:loadBundle basename="nick.Messages" var="message"/>

<body>

<f:view>

<h:form>

<h:panelGrid columns="3">

<h:outputLabel for="id">

<h:outputText value="#{message.id}"/>

</h:outputLabel>

<h:inputText id="id" value="#{user.id}">                      <f:validator validatorId="nameValidator"/>

</h:inputText>

<h:message for="id"/>

<h:commandButton

action="#{action.regist}" value="Regist"/>

</h:panelGrid>

</h:form>

</f:view>

</body>

</html>

 

 

 

注:定制验证器的操作与定制转换器的操作大致相同,如果我们希望通过页面的方式为验证器提供属性的话,那么我们也需要定义额外的标签。

 

 

 

e)        控件定制:

                      i.              说明:JSF允许用户基于JSF的框架,进行控件的定制,控件定制需要完成以下几部分的工作,1.需要一个控件实现类,为了能让控件在页面上使用,我们的控件还需要在配置文件中,通过component标签进行注册;2.用于控件渲染的Render类;3.用于在页面上使用控件的标签。

 

 

 

f)        控件树定制:

                      i.              说明:除了可以通过页面标签来声明控件以外,我们可以通过程序的方式来定制控件树,通过调用FacesContext上的getViewRoot()方法,我们可以获得控件树的根引用,通过该引用,我们可以动态的对控件进行增删,或者动态的为某一控件增删事件监听器,和验证器等。

g)        Web常量:

                      i.              说明:JSF提供了一组操作applicationcontextsessioncookiespage等常量的方法。通过调用FacesContext上的getExternalContext()方法,我们可以获得一个对ExternalContext的引用,通过该引用我们可以获取所有我们希望使用的sessioncookies等常量的引用,除此以外,我们还能获取request当中的头信息和请求信息等。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
JSF是一种用于构建Java Web 应用程序的标准框架(是Java Community Process 规定的JSR-127标准)。JSF(Java Server Faces)技术为开发基于网络用户界面的Java开发者提供了标准的编程接口API以及标签库。就像Struts框架一样,JSF定义了一套JSF标签 JSF的全称   1、Joint Strike Fighter (JSF)   2、Java Server Faces (JSF) Java Server Faces (JSF)   JSF是一种用于构建Java Web 应用程序的标准框架(是Java Community Process 规定的JSR-127标准)。它提供了一种以组件为中心的用户界面(UI)构建方法,从而简化了Java服务器端应用程序的开发。由于由Java Community Process (JCP) 推动,属于Java EE 5中的技术规范,而受到了厂商的广泛支持。   JSF(Java Server Faces)技术为开发基于网络用户界面的Java开发者提供了标准的编程接口API以及标签库。就像Struts框架一样,JSF定义了一套JSF标签,能够生成与JavaBean属性绑定在一起的HTML表单元素。从应用开发者的角度看,两种框架十分相似,但是JSF可能会得到更多的支持,因为JSF是Java的标准。在未来的发展中,有可能所有的J2EE应用服务器都需要支持JSF。 Java Server Faces技术好处   引入了基于组件和事件驱动的开发模式,使开发人员可以使用类似于处理传统界面的方式来开发Web应用程序。提供了行为与表达的清晰分离。 不用特别的脚本语言或者标记语言来连接UI组件和Web层。JSF技术API被直接分层在Servlet API的顶端。 技术为管理组件状态提供一个丰富的体系机构、处理组件数据、确认用户输入和操作事件。 Java Server Faces应用程序   典型的JSF应用程序包含下列部分:   一组JSP页面   一组后台bean(为在一个页面上的UI组件定义的属性和函数的JavaBean组件)   应用程序配置资源文件(定义页面导航规则、配置bean和其它的自定义对象,如自定义组件)   部署描述文件( web.xml )   一组由应用程序开发者创建的自定义对象(有可能)   一些可能包含自定义组件、约束、转换器或者监听器的对象   为在页面中表现自定义对象的一组自定义tag   包含JSP页面的JSF应用程序也使用由为了表现UI组件和在页面上的其他对象的JSF技术而定义的标准的tag库。 Java Server Faces技术的重要开发框架 sun-ri、myfaces、icefaces、richfaces、seam

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值