struts2 开发集锦

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/kekeyifan/archive/2009/12/07 /4958716.aspx

struts2 开发集锦

1. Struts2的开发步骤 
1) 在classpath中添加如下包: 
    struts2-core-2.1.8.1.jar, xwork-core-2.1.6.jar, ognl-2.7.3.jar, freemarker-2.3.15.jar, common-fileupload-1.2.1.jar, common-io-1.3.2.jar 
2) 在web.xml中添加过滤器: 
    <filter> 
        <filter-name>struts2</filter-name> 
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
    </filter> 
    <filter-mapping> 
        <filter-name>struts2</filter-name> 
        <url-pattern>/*</url-pattern> 
    </filter-mapping> 
3) 在classpath中添加Struts2的配置文件struts.xml: 
4) 编写Action类。 
=======================================================================================
1. Struts2整合Spring 
1) 添加Struts2和Spring需要的Jar包到classpath中。 
2) 在应用的classpath路径下添加strut2配置文件(struts.xml)和spring配置文件 (applicationContext.xml)。 
3) 把struts2-spring-plugin-xxx.jar插件包添加到应用的classpath路径下。 
4) 把strut2框架的对象工厂设置为Spring提供:在struts.xml配置文件中添加常量配置 
    <constant name="struts.objectFactory" value="spring" /> 
5) 在web.xml中配置监听器来初始化Spring的ApplicationContext:具体配置参见Spring应用 
6) 把需要由Spring管理的Action类等配置到Spring配置文件中。 
    struts.xml中Action的配置如下: 
    <action name="login" class="accountAction"> 
<result name="success">/success.jsp</result> 
<result name="error">/error.jsp</result> 
</action> 
那么在Spring配置文件中需要添加如下bean的配置: 
<bean name="accountAction" class="com.qiujy.web.action.AccountAction"> 
<property name="accountService" ref="accountService"/> 
</bean> 
==============================================================================================
1. Struts2中基于注解的Action配置 
  1) @ParentPackage 指定父包 
  2) @Namespace 指定命名空间 
  3) @Results 一组结果的数组 
  4) @Result(name="success",location="/msg.jsp") 一个结果的映射 
  5) @Action(value="login") 指定某个请求处理方法的请求URL。注意,它不能添加在Action类上,要添加到方法上。 
  6) @ExceptionMappings 一级声明异常的数组 
  7) @ExceptionMapping 映射一个声明异常 
==============================================================================================
1. Struts2中的OGNL的使用。 
2. OGNL:对象图导航语言。通过OGNL表达式可以获取对象的属性,调用对象的方法,或构造出对象。 
  1) OGNL上下文中有一个根对象。这个根对象可以直接获取。不需要#。 
  2)支持常量: 
         字符串常量、字符常量、 
         数值常量:int、long、float、double 
         布尔常量:true、false 
    Null常量 : null 
         支持操作符:支持Java的所有操作符,还支持特有的操作符: , {}、in、not in; 
3. Struts2中的OGNL: 
  1) Struts2将ActionContext设置为OGNL上下文,并将值栈(ValueStack)作为OGNL的根对象放置到 ActionContext中。 
  2) Struts2总是把当前Action实例放置在值栈的栈顶。所以,在OGNL中引用Action中的属性也可以省略“#”。 
4. 常用标签 
1) <s:property value="OGNL"/> 
2) <s:date name="OGNL" format=""/> 
3) <s:if test="OGNL"></s:if><s:elseif test="OGNL"></s:elseif><s:else></s:else> 
★4) <s:iterator value="OGNL" status="vs">…</s:iterator> 
5) <s:debug/> 
==============================================================================================================
1. Struts2中的类型转换器 
  1) Struts2中内置了一些常用的类型转换器:可以把客户端提交的String数据转换成对应类型的数据。 
     a) 基本类型 
     b) java.util.Date: 
     c) 数组和列表 
  2) 自定义类型转换器: 
     a) 继承自org.apache.struts2.util.StrutsTypeConverter类 
  public abstract Object convertFromString(Map context, String[] values, Class toClass); 
        context:OGNL上下文的Map对象 
        values :需要转换的字符串数组 
        toClass:要转换的目标类型 
  public abstract String convertToString(Map context, Object o); 
         context:OGNL上下文的Map对象 
         o:需要转换的对象 
     b) 注册:以全局方式 
                    在应用程序的classpath下创建一属性文件,名为:xwork-conversion.properties 
                    文件内容:待转换类型的全限定名=类型转换器类的全限定名 
  3) 转换Set: 
     0) Action中的Set属性需要进行初始化:如: 
        private Set<User> userSet = new HashSet<User>(); 
     a) 添加针对某个Action的转换器配置文件:ActionName-conversion.properties 如: 
        UserAction-conversion.properties 
     b) 在这个文件中添加:Action的Set属性的相关配置 
        Element_属性名=Set中的元素类型的全限定名                 #指定Set中的元素类型 
        KeyProperty_属性名=Set中的元素类型中的某个属性  #指定Set的索引字段 
                   如下示例: 
        Element_userSet=com.qiujy.domain.User 
        KeyProperty_userSet=id 
     c) JSP页面: <input type="text" name="Set属性名.makeNew[0].属性名"/> 
                    如:<input type="text" name="userSet.makeNew[0].loginname"/> 
遗留问题 
1. Map类型怎么转换? 
2. 类型转换错误处理时,怎么不跳转到input结果页? 
================================================================================
1. Struts2中的输入校验 
2. 编码方式校验 
  1) Action一定要继承自ActionSupport 
  2) 针对某个要进行校验的请求处理方法编写一个 public void validateXxx()方法,在方法内部进行表单数据校验. 
  3) 也可针对所有的请求处理方法编写public void validate()方法。 
  4) 在校验方法中,可以通过addFieldError()方法来添加字段校验错误消息。 
  5) 当校验失败时,Struts框架会自动跳转到name为input的Result页面。在校验失败页面中,可以使用<s:fielderror/>来显示错误消息 
  6) 简单,灵活。但重用性不高。 
3. XML配置方式校验。在编码方式之前被执行。 
  1) 针对要校验的Action类,在同包下编写一个名为:Action类名-validation.xml校验规则文件。 
  2) 在校验规则文件中添加校验规则:具体的校验器名,参数可参看Struts2的reference或Struts2的API。 
     a) Field校验:针对Action类中每个非自定义类型的Field进行校验的规则。 
    <field name="要校验的Field名"> 
   <field-validator type="校验规则器名" short-circuit="是否要短路径校验(默认是false)"> 
       <param name="校验器要使用的参数名">值</param> 
            <message>校验失败时的提示消息</message> 
</field-validator> 
<!– 还可添加其它的校验规则 –> 
</field> 
     b) 非Field校验:针对Action类的某些Field使用OGNL表达进行组合校验。 
    <validator type="fieldexpression"> 
<param name="fieldName">pwd</param> 
     <param name="fieldName">pwd2</param> 
     <param name="expression"><![CDATA[pwd==pwd2]]></param><!– OGNL表达式 –> 
     <message>确认密码和密码输入不一致</message> 
</validator> 
     c) visitor校验:主要是用来校验Action类中的自定义类型Field。(针对使用模型驱动方式时) 
       i) 在Action类的的校验规则文件中针对自定义类型Field使用visitor校验规则。 
    <!– 针对自定义Field使用visitor校验 –> 
<field name="user"> 
<field-validator type="required" short-circuit="true"> 
            <message>用户的信息必填</message><!– 消息前缀 –> 
</field-validator> 
<field-validator type="visitor"><!– 指定为visitor校验规则 –> 
<param name="context">userContext</param><!– 指定本visitor校验的上下文名 –> 
            <param name="appendPrefix">true</param><!– 是否要添加校验失败消息的前缀 –> 
            <message>用户的</message><!– 消息前缀 –> 
</field-validator> 
</field> 
  ii) 针对visitor的Field编写一个校验规则文件.文件名为: visitor字段类型名[-visitor校验的上下文名]-validation.xml. 例如: 本例中的文件名为User-userContext-validation.xml 
                注意: 此文件要存放到visitor字段类型所在的包下. 
  iii) 在visitor的Field校验规则文件中针对要校验的Field添加校验规则. 
   3) 在校验失败页面(名为input的result页面)中,可以使用<s:fielderror/>来显示错误消息。 
   4) 默认情况下,XML的校验规则对Action中所有的请求处理方法生效.此时应该只针对每个要校验的请求处理方法指定校验。有两种方式: 
      i) 只为Action中的指定方法指定校验规则文件,配置文件命名为:Action类型名-别名-validation.xml, 
                      别名是要校验的方法对应的Action标签的name属性值。 
                      如:UserAction在struts2.xml的配置为: 
    <package name="my" extends="struts-default" namespace="/"> 
<action name="user_*" class="com.qiujy.web.action.UserAction" method="{1}"> 
<result name="success">/info.jsp</result> 
<result name="input">/user_{1}.jsp</result> 
</action> 
    </package>              
                ● UserAction中有registe方法和login方法,要对registe方法进行校验,则它的校验规则文件名为:UserAction- user_registe-validation.xml。 
                 ● 如果使用visitor校验器,必需指定visitor校验的上下文名。 
      ii) 在校验拦截器中指定要验证的方法。不太实用。 
   <action name="user_*" class="com.qiujy.web.action.UserAction" method="{1}"> 
    <result name="success">/info.jsp</result> 
    <result name="input">/user_{1}.jsp</result> 
     <interceptor-ref name="defaultStack"> 
        <!– 给校验拦截器指定不进行校验的方法列表:用逗号隔开 –> 
        <param name="validation.excludeMethods">*</param> 
        <!– 给校验拦截器指定要进行校验的方法列表:用逗号隔开 –> 
        <param name="validation.includeMethods">regist</param> 
      </interceptor-ref> 
   </action> 
   5) 同时使用客户端校验和服务器端校验 
      i) 设置<s:form>标签的validate属性: 
         false:默认值。校验框架只执行服务器端校验。 
         true:先执行客户端校验,然后再执行服务器端校验。 
         form标签会根据你在服务器端配置的验证规则生成对应的JavaScript验证代码。 
                      目前支持的内置校验器:required、requiredstring、stringlength、regex validator、email、url、int、double 
      ii) 不太好用,不建议使用。建议使用jQuery进行页面表单校验。 
   6) 自定义校验器: 
      i) 继承自FieldValidatorSupport抽象类。重写validate(Object obj)方法 
      ii) 注册校验器类. 在应用程序的classpath下新建一校验器注册文件。名为validators.xml,内容如下: 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE validators PUBLIC 
        "-//OpenSymphony Group//XWork Validator Config 1.0//EN" 
        "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"> 
<validators> 
  <validator name="校验器名" class="校验器类的全限定名"/> 
</validators> 
4. Annotation方式校验: Struts2提供了注解的方式校验 
  1) @Validation 指明这个类或者接口将使用基于注解的校验。Struts2.1中已被标识为过时。 
  2) @Validations() 在同一个方法上要使用多个注解校验时。 
  3) @SkipValidation 指定某个方法不需要校验。否则所有方法都会使用校验。也可以在检验拦截器中使用validateAnnotatedMethodOnly 
  4) 13个内置校验器的注解版本:(注:这些注解都只能用在方法级别上) 具体参数参见Struts2的API或Reference。 
@RequiredFieldValidator 
@RequiredStringValidator 
@StringLengthFieldValidator 
@IntRangeFieldValidator 
@DoubleRangeFieldValidator 
@DateRangeFieldValidator 
@ExpressionValidator 
@FieldExpressionValidator 
@RegexFieldValidator 
@EmailValidator 
@UrlValidator 
@VisitorFieldValidator 
@ConversionErrorFieldValidator 
====================================================================== 
5.Java对国际化的支持:java内部使用unicode编码方式: 
1)java.util.Locale 表示了特定的的地理,政治和文化地区,环境信息的对象 
有语言代码和区域代码组成; 
语言代码小写字母:en,zh 
区域代码大写字母:US,CH ,TW,HK 
2)java.util.Resourcebundle 用于绑定特定语言环境的资源对象; 
资源文件的命名规范:基本名_语言代码[_区域代码].properties 
默认资源文件名:基本名.properties; 
3)  java.util.MessageFormat 用于对含有占位符的字符进行格式化输出; 
4)编码方式 
Locale locale =Locale.CHINA; 
ResourceBundle rb =ResourceBundle.getBundle("资源文件的基本名",locale); 
String value=rb.getstring("key"); 
String str=messageFormat.format(value,Object… arguments); 
===================================================================== 
在struts2中国际化的原理: 
1 ) 在classpath中天际正对特定语言环境中的配置文件 
2 ) 在struts.xml中通过常量配置注册资源文件的基本名: 
<constant name="struts.custom.i18n.resources" value="msg"/> 
3 ) 在jsp页面中 用<s:text value="资源文件中key"/> 
4 ) 在Aciotn中,可以使用ActionSupport 类提供的getText("") 
===================================================== 
——————————————————文件上传 ———————————— 
struts2 中的文件上传 
1. 在文本应用使用common-fileupload.jar实现文件上传 
2.struts2 中文件上传: 
在jsp页面中 在Form表单中 要指定type="multpart/-data" 
在Action 中 
      File upFile; String contentType , String fileName , 提供getter,setter的方法; 
      public void copy(File srcfile,File destFile) throws IOException{ 
     BufferedInputStream bis = null; 
     BufferedOutputStream bos =null; 
     try{ 
      bis =new BufferedInputStream(new FileInputStream(srcfile)); 
      bos =new BufferedOutputStream(new FileOutputStream(destFile)); 
      byte[] buf =new byte[8192]; 
      for(int count=-1;(count=bis.read(buf))!=-1){ 
      bos.write(b,0,count); 
      bos.flush(); 
      } 
    }catch(IOException ie){ 
     throw ie; 
    }finally{ 
     if(bis!=null){ 
      bis.close(); 
     } 
      if(bos!=null){ 
      bos.close(); 
     }  
      } 
    同时也可以使用批量上传   
      ————————— 
  在struts.xml 
  public Boolean isallowtype(String type) 
  { 
   List<String>types= new ArrayList<String>(); 
   types.add("image/pjpeg"); 
   types.add(text/plain); 
   types.add(application/msword); 
   if(types.contains(type)){ 
   token .wu 
   } 
  }====================================== 
  1)页面要求; 
   Form 表单  method="post"  enctype="multipart/form-data" 
   要有file域:<input type="file" name="up"/> 
  2) 在Action中: 
   添加一个名与页面file域同名的file属性; 
   添加一个以file域名开头,后面名为ContentType 的字符串属性,这个由struts的文件传拦截器赋问价类型值。 
  添加一个以file域名开头,后面名为FileName 的字符串属性,这个有strusts2的文件上传蓝假期赋文件名的值。 
3)Io流操作,把文件的上传写到指定的目录中。 
4)批量文件上传: 在Action中添加一个List<File>类型的与页面file域同名的属性。 
通过IO流循环操作,完成文件的读写。 
==================================== 
  token 防止重复提交表单 
   1) 在页面的表单中添加<s:token/> 
   2) 在使用token 的Action配置中添加token 或tokensession拦截器 
================================================================ 
4.FreeMarker页面模板技术: 模板+数据模型=输出 
  1)FreeMarker 模板: 一个普通文本文件,其中使用了一些FreeMarker的特别标记。 
  2)数据模型: 存放了数据的数据结构,通常是一个Hash存储结构(如:hashMap) 
  3)FreeMarker 框架负责间隔一个数据模型中的书籍合并到模板中,从而生成输出 
  2.配置是使用环境,下载并把freemarker-x.x.jar 放置到应用程序中的classpath下。 
  3.java应用 
  1)创建数据模型:Map<String,Object> root=….. 
  2)创建模板:xxx.ftl 
  3)合并 
———————————————————– 
//创建个configuation实例来出示FreeMarker的配置// 也可以在classpath下添加一个freemarker.properties 
Configuarion config =new Configuration(); 
String basePath =Thread.currentThrad().getContextClassLoader().getResource("").getPath(); 
Config.setDirectoryForTemplateLoading(new file(basePath+"/templates")); 
Temlate template =config.getTmplate("first.txt"); 
//输出控制台 
template.process(getDateModel(), new OutputStreamWriter(System.out)); 
//输出到文件 
BufferedWriter bw =new bufferedWriter( new FileWriter(new File(path+"/abc.txt"))); 
template.process(getDataMoedl(), bw); 
bw.flush(); 
<#setting number_formate="#,###.00"> 
<#setting datetime_formate="yyyy年MM月dd日 HH:mm:ss"> 
${"<a href=/"#/">xxx</a>"?html} 
${true?string("男","女")} 
==================== Teachers Code======================= 
  1. FreeMarker模板引擎的使用: 模板 + 数据模型 = 输出 
  1) FreeMarker模板:一个普通文本文件,其中使用了一些FreeMarker的特别标记。 
  2) 数据模型:存放了数据的数据结构,通常是一个Hash存储结构(如:HashMap) 
  3) FreeMarker框架负责将一个数据模型中的数据合并到模板中,从而生成输出 
2. 配置使用环境: 下载并把freemarker-2.x.x.jar放置到应用程序的classpath下。 
3. Java应用: 
   1) 创建数据模型: Map<String, Object> root = …. 
   2) 创建模板: xxx.ftl 
   3) 合并: 
//创建一个Configuration实例来初始freeMarker的配置 //在classpath下添加一个名为freemarker.properties 
Configuration cfg = new Configuration(); 
//设置模板文件的存放目录 
cfg.setDirectoryForTemplateLoading(new File("templates")); 
//加载指定的模板 
Template t = cfg.getTemplate("first.ftl"); 
//处理合并 
t.process(root, new OutputStreamWriter(System.out)); 
4. web应用中直接使用FreeMarker: 在Servlet的请求处理方法中: 
//创建一个Configuration实例来初始freeMarker的配置 
Configuration cfg = new Configuration(); 
//设置模板文件的存放目录 
cfg.setServletContextForTemplateLoading(getServletContext(),"/templates"); 
//加载指定的模板 
Template t = cfg.getTemplate("first.ftl", "UTF-8"); 
//处理合并 
t.process(getDataModel(), response.getWriter()); 
★5. FTL(FreeMarker模板语言)语法: 
1) 模板文件由4部分组成: 
   a) 文本:直接输出的部分 
   b) 注释:<#–  注释内容 –>  不会输出 
   c) 插值(interpolation):${表达式} 或 #{表达式} ,将使用数据模型中的数据替换后再输出 
   d) FTL指令: 
                内置(预定义)指令:<#指令名 属性名="值">主体</#指令名>  如:<#if user??>${user.loginname}</#if>
                自定义指令: <@指令名 属性名="值">主体</@指令名> 
2) 插值规则 
a) 表达式放置在插值语法${}之中,用于输出表达式的值。 
b) 表达式的值的类型可以是:字符串、 数字、布尔、日期时间、序列、Hash结构 
c) 表达式支持Java中的所有运算符: 
    算术运算符:+、-、*、/、% 
    比较运算符:==(eq)、!=(ne)、>(gt)、>=(gte)、<(lt)、<=(lte) 
    逻辑运算符:&&(and)、||(or)、!(not) 
    三目运算符:? : 
d) 内置函数: 
    Ⅰ) 使用方式:表达式?函数名[(实参)] 
    Ⅱ) 字符串的内置函数: substring(from[, to])、html、length、trim、url 
             示例:<#setting url_escaping_charset="UTF-8"> 、exp?url[("UTF-8")] 
    Ⅲ) 数字的内置函数:c、string[(数字模式串)]、 
    Ⅳ) 布尔的内置函数:string[("男", "女")] 
    Ⅴ) 内置的日期时间函数:string[("格式模式串")]、datetime、date、time 
e) 序列: 
         在FTL中定义的序列:由方括号包括,各元素用英文逗号分隔如:<#assign seq=["winter", "spring", "summer", "autumn"]> 
         也可以用数字范围(递增、反递增)定义数字序列: <#assign nums=101..105>  或 <#assign nums=105..101> 
         在数据模型中:可以是List对象、Set对象 
         序列的内置函数:size、sort[("指定字段作排序依据")] 
f) Hash结构: 
         在FTL文件中直接定义时:由大括号包括,由逗号分隔键/值列表,键和值之间用冒号分隔。键必须是字符串。<#assign scores={"语文":78, "数学":89, "英语":87}>${scores.语文} 
         在数据模型中:可以是Map对象 
    Hash的内置函数:size、keys、values 
3) FreeMarker中的空值判断 
  a) 判断是否为空值:用??(?if_exists,?exists) 如果不为空返回true,否则返回false。 
  b) 通过Configuration设置:Configuration cfg = new Configuration(); cfg.setClassicCompatible(true); 
  c) 属性配置方式:在freemarker.properties文件中classic_compatible=true 
  d) 通过ftl设置:在ftl文件头前加入<#setting classic_compatible=true> 
  e) 在FTL中遍历序列、Hash结构时:<#if userList??><#list userList as user>….</#list></#if> 
4) 常用内置指令: 
  a) if/else 
<#if condition> 
  … 
<#elseif condition2> 
  … 
<#elseif condition3> 
  … 
… 
<#else> 
  … 
</#if> 
  b) switch/case 
<#switch value> 
  <#case refValue1> 
    … 
    <#break> 
  <#case refValue2> 
    … 
    <#break> 
  … 
  <#case refValueN> 
    … 
    <#break> 
  <#default> 
    … 
</#switch> 
  c) list 
<#list sequence as item>  <#– item_index 当前迭代项的索引 –> 
    … 
</#list> 
  d) include 包含指定文件。类似于JSP中的include标准动作 
<#include "文件路径" [encoding="charset"] [parse=true|false]> 
  e) import 导入指定模板中的所有变量。 
<#import "文件路径"  as hash> 
  f) noparse 不处理该指令中包含的内容 
<#noparse> 
  … 
</#noparse> 
  g) assign: 为当前模板页面创建或替换一个顶层变量 
<#assign name=value> 
<#assign name1=value1 name2=value2 … nameN=valueN> 
  h) global:创建或替换一个命名空间全局范围作用域的顶层变量 
  i) local:创建或替换一个局部作用域的顶层变量 
  j)setting 设置FreeMarker运行时的属性.语法:<#setting name=value> 
name常用的有: 
locale:该模板所使用的语言环境选项。en,zh,zh_CN,zh_TW 
number_format:数字格式化输出的格式 
boolean_format:布尔值格式化输出的格式 
date_format,time_format,datetime_format:日期时间格式化输出的格式 
time_zone:格式化输出日期时间所使用的时区。 
url_escaping_charset:URL编码的字符集。 
  k) 自定义指令:<#macro 指令名 属性名…>…</#macro> 
6. Web应用中整合FreeMarker:FreeMarker提供了FreemarkerServlet类来整合模板到Web应用中: 
  1) 这个Servlet在数据模型中放置了三个Hash结构:Request, Session, Application,分别用来访问请求,会话,应用上下文中的属性。 
             访问作用域中的属性时,没有指定Hash结构名,它会依次按Request,Session,Application顺序搜索。 
  2) 它还提供了一个名为RequestParameters的Hash结构,用来访问HTTP请求中的参数数据。 
7. Struts2中整合FreeMarker: Struts2默认就是使用FreeMarker来产生所有UI标签的HTML标记。 
  1) 对提供了FreeMarkerResult来支持FTL页面。 
     <result type="freemarker">/templates/info.ftl</result> 
  2) FreeMarker针对Struts2提供了以下内置Hash结构: 
     a) stack: 代表ValueStack本身,可通过如下方式来访问其中的变量"${stack.findString(‘ognl expr’)}" 
     b) action: 代表刚刚执行过的Action实例 
     c) response: 代表HpptServletResponse实例 
     d) res: 代表HpptServletResponse实例 
     e) request: 代表HpptServletRequest实例 
     f) req: 代表HpptServletRequest实例 
     g) session: 代表HpptSession实例 
     h) application: 代表ServletContext实例 
     i) base: 代表用户请求的上下文路径. 
8. 使用FreeMarker完成页面的静态化: 
—————————————————————————————————————– 
  =============================================================================
5. JFreeChar技术 画图技术

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值