协同使用 WebSphere Studio V5 与 Struts Framework: 第二部分:使用 Struts 验证器

引言

Web 表单验证是开发 Web 应用程序的一个不可缺少的部分。Apache Software Foundation 开发的 Jakarta 通用验证器(Jakarta Commons Validator)提供了一个分离验证逻辑与应用程序业务逻辑的框架。您可以协同或不协同使用 Struts 与 Commons Validator。Struts 发行版附带的通用验证器(Commons Validator)通常称为 Struts 验证器(Struts Validator)

Writing a Simple Struts Application using WebSphere Studio V5一文介绍了未使用 Struts 验证器的 Struts 验证。 ActionForm 中的 validate() 方法是通过程序化的验证逻辑实现的。然而,这种方法将验证逻辑与特定的动作表单紧紧地耦合在一起。为了重用其他表单中的验证逻辑,您可能需要进行很多复制和粘贴。

Struts 验证器通过应用基于组件的设计理念解决了这个问题。Struts 验证器使得 ActionForms 能够共享一组验证规则,这组验证规则是 XML 文件的形式保存的。另外,Struts 验证器同时支持客户端和服务器端验证。两种方法共享同一组验证规则。

本文向您展示了如何使用 Struts 验证器。我们假定您具有 Struts 框架方面的基本知识。要了解基本的Struts 框架,请参看上面提到的文章。

先决条件

启动 IBM® WebSphere® Studio Application Developer Version 5.0(带或不带 V5.01包):

  1. 移动鼠标到 Windows® Start 菜单。
  2. 选择 Programs => IBM WebSphere Studio => Application Developer 5.0




回页首


Struts 验证器基础

步骤 1. 安装 Struts 应用程序

本节将指导您安装一个现有的 Struts 应用程序。

导入 Struts 应用程序 EAR:

  1. 下载 StrutsValidator.zip 并解压 DefaultEAR.ear
  2. 在工作区中,选择 File => Import => EAR File。单击 Next
  3. 找到下载的 EAR。
  4. 输入 DefaultEAR 作为项目名,然后单击 Finish

在 WebSphere Test Environment 中运行 Struts 应用程序以确保安装正确:

  1. 切换到 Web 透视图。
  2. 展开 SimpleValidatorWeb => Web Content。右键单击 submitpage.jsp并选择 Run on Server
  3. 确保 WebSphere Test Environment V5 Server被选中。单击 OK
  4. 在装载完 submitpage.jsp 之后,随便输入点什么,然后单击 Submit看看结果。
  5. 在测试完成之后,停止服务器。在 Web 透视图的 Server 视图中,右键单击 WebSphere Test Environment V5 Server并选择 Stop

步骤 2. 使用 Struts 验证器

验证规则保存在一个名为 validator-rules.xml 的 XML 文件中。Struts提供了包含 14 个基本验证器的 validator-rules.xml 文件。最常用的一些文件列举如下:


验证器名称 功能
required验证一个必须填写的字段是否填写
mask通过一个常规的 Jakarta RegExp 表达式检查字段值。要了解更多关于 RegExp 的信息,请参见 Jakarta RegExp 页。例如:
^[a-zA-Z]*$ 表示该值必须只包含字母
^\d{5}\d*$ 表示该值必须是五位数字
range检查该值是否在指定范围内。
date检查该值是否为一个有效值。它还能确保以期望的格式提供该数据,例如 MM/DD/YYYY 或 DD-MM-YYYY。
email验证该值是以有效的电子邮件地址的格式提供。
creditCard确认该值是一个有效的信用卡号码。

validator-rules.xml 导入 /Web Content/WEB-INF 文件夹。

  1. 下载 StrutsValidator.zip 并解压 validator-rules.xml
在 Web Perspective 中,右键单击 /SimpleValidatorWeb/Web Content/WEB-INF并选择 Import => File System。 找到并选择下载的 validator-rules.xml 文件。单击 Finish。 在文件夹 /SimpleValidatorWeb/Web Content/WEB-INF 中,双击 validator-rules.xml 以在 XML 编辑器中打开它。 切换到 Source 页面。

validator-rules.xml 文件的代码如下。验证器规则必须封装在标签 <form-validation> 中。验证器包含验证逻辑。在以下示例中,验证器为 required ,它包含客户端和服务器端验证的验证代码。用黄色显示的代码定义了服务器端验证器类和方法,用绿色显示的代码定义了客户端验证的JavaScript 代码。该文件中的其余验证器采用了相同的结构。

<form-validation>
<global>
<validator name="required"

            classname="org.apache.struts.util.StrutsValidator"
method="validateRequired"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.required">


  <javascript><![CDATA[
function validateRequired(form) {
var bValid = true;
var focusField = null;
var i = 0;
var fields = new Array();
oRequired = new required();
for (x in oRequired) {
if ((form[oRequired[x][0]].type == 'text' ||
form[oRequired[x][0]].type == 'textarea' ||
form[oRequired[x][0]].type == 'select-one' ||
form[oRequired[x][0]].type == 'radio' ||
form[oRequired[x][0]].type == 'password') &&
(form[oRequired[x][0]].value == '')) {
if (i == 0) {
focusField = form[oRequired[x][0]];
}
fields[i++] = oRequired[x][1];
bValid = false;
}
}
if (fields.length > 0) {
focusField.focus();
alert(fields.join('\n'));
}
return bValid;
}]]> </javascript>

      </validator>
</global>
</form-validation>

如何使用这些验证器?

在大部分情况下,内置的验证器对于一个 Web 应用程序来说就足够了。为了在一个字段中使用验证器,需要在一个 XML 文件中指定验证器和字段之间的映射关系。在我们的示例中,它被命名为 validation.xml

  1. 在 Web Perspective 中,右键单击 /SimpleValidatorWeb/Web Content/WEB-INF并选择 New => Other => XML。单击 Next两次。
  2. 输入 validation.xml 作为文件名。单击 Finish
  3. 用以下代码修改 XML 文件并保存。
   <form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required">
<arg0 key="submitForm.name" />
</field>
</form>
</formset>
</form-validation>

validation.xml 文件包含表单和每个字段依赖的验证器之间的映射, submitForm 中的字段 name 依赖于 required 验证器。 arg0 是当错误消息产生时传递给验证器的参数。参数的键在资源绑定文件中有一个映射。由于该字段是比需的,所以将会产生一个错误消息(如果这个字段为空的话)。

将错误消息保存在哪儿?

将错误消息保存在 ApplicationResources.properties 中,它是由WebSphere Studio 创建并由 Struts 框架使用的缺省资源绑定。

用编辑器打开特性文件:

  1. 在 Web Perspective 中,展开 SimpleValidatorWeb => Java™ source => com.ibm.simplevalidatorweb.resources,然后双击 ApplicationResources.properties
  2. 用以下黑体代码修改该文件并保存。
# Optional header and footer for <errors/> tag.
#errors.header=<ul>
#errors.footer=</ul>

# Errors
errors.footer=
errors.header=<h3><font color="red">Validation Error</font></h3>
You must correct the following error(s) before proceeding:
errors.ioException=I/O exception rendering error messages: {0}
error.database.missing=<li>User database is missing, cannot validate logon credentials</li>
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be an byte.
errors.short={0} must be an short.
errors.integer={0} must be an integer.
errors.long={0} must be an long.
errors.float={0} must be an float.
errors.double={0} must be an double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is not a valid credit card number.
errors.email={0} is an invalid e-mail address.

submitForm.name = text field label



在这个示例中,将会显示错误消息 {0} is required ,其中 {0} 由通过 <arg0 key="submitForm.name" />validation.xml 传递而来的参数替代。在这个示例中, submitForm.name 映射到(资源束文件resource bundle file)中的 text filed label ,因此,最后的错误消息将会是 text field label is required

如果启用了服务器端验证,则错误消息将会在浏览器中作为 HTML 返回。对于客户端验证,错误消息将会作为 JavaScript 弹出窗口返回。

配置 Struts 配置文件以启用验证器插件

要启用验证器插件,请遵循下列步骤:

  1. 在编辑器中打开 struts-config.xml。展开 /SimpleValidatorWeb/Web Content/WEB-INF并双击 struts-config.xml
  2. 切换到 Source 页。
  3. 将以下代码插到 </struts-config> 结束标签前并保存修改。以下代码可以启用验证器组件并且指示该插件使用 validator-rules.xmlvalidation.xml 来验证动作表单:
    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml"/>
    </plug-in>

  4. 切换到 struts-config.xml 编辑器的 Actions页,选择 /submit并在 Input字段中输入 /submitpage.jsp 。保存修改。

下面的步骤 3 和 4 将指导您完成各个必需的过程以启用服务器端验证和客户端验证。

步骤 3. 使用服务器端验证

为了使用服务器端验证, Action Form 实现类应该扩展 ValidatorForm 而不是 ActionForm 。当提交表单时,会执行 ValidatorForm 中的 validate() 方法,它将根据 validation-rules.xmlvalidation.xml 文件进行验证。

要在编辑器中打开 SubmitForm 类,请遵循下列步骤。

  1. 在 Web Perspective 中,双击 /SimpleValidatorWeb/Java Source/com.ibm.simplevalidatorweb.forms 内的 SubmitForm.java
  2. 如下所示修改 SubmitForm.java 并保存。
package com.ibm.simplevalidatorweb.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

import org.apache.struts.validator.ValidatorForm;
/**
* Form bean for a Struts application.
* Users may access 1 field on this form:
* <ul>
* <li>name - [your comment here]
* </ul>
* @version 1.0
* @author
*/
public class SubmitForm extends

ValidatorForm {
private String name = null;
/**
* Get name
* @return String
*/
public String getName() {
return name;
}
/**
* Set name
* @param <code>String</code>
*/
public void setName(String n) {
name = n;
}
/**
* Constructor
*/
public SubmitForm() {
super();
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
// Reset values are provided as samples only. Change as appropriate.
name = null;
}
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {


return super.validate(mapping, request);
}
}



您需要在 JSP 文件中添加 <html:errors/> 行以使错误显示出来:

  1. 在编辑器中打开 submitpage.jsp 并切换到 Source 页。
  2. 在文件的开头(即 <html:form> 前)输入行 <html:errors/> 。保存该修改。

运行该应用程序

要在 WebSphere Test Environment 中运行 submitpage.jsp ,请遵循下列步骤:

  1. 右键单击 submitpage.jsp并选择 Run on Server
  2. 确保 WebSphere Test Environment V5 Server 被选中。单击 OK

当在浏览器中装载 submitpage.jsp 时,单击 Submit,然后您将会接收到一个验证错误,告知 text field label 是必需的。



图 1. 运行 http://localhost:9080/SimpleValidatorWeb/submitpage.jsp

步骤 4. 使用客户端验证

为了使用客户端验证, Action Form 应该扩展 ValidatorActionForm 而不是 ActionForm 。如前所述,对于服务器端验证, Action Form 扩展的是 ValidatorForm 类。

在编辑器中打开 SubmitForm 类。

  1. 在 Web 透视图中,双击 /SimpleValidatorWeb/Java Source/com.ibm.simplevalidatorweb.forms 内的 SubmitForm.java
  2. 如下所示修改 SubmitForm.java 并保存。 validate() 方法注释掉了。要注释一段代码,可以选中该代码块,然后选择 Source => Comment
package com.ibm.simplevalidatorweb.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

import org.apache.struts.validator.ValidatorActionForm;
import org.apache.struts.validator.ValidatorForm;
/**
* Form bean for a Struts application.
* Users may access 1 field on this form:
* <ul>
* <li>name - [your comment here]
* </ul>
* @version 1.0
* @author
*/
public class SubmitForm extends

ValidatorActionForm {
private String name = null;
/**
* Get name
* @return String
*/
public String getName() {
return name;
}
/**
* Set name
* @param <code>String</code>
*/
public void setName(String n) {
name = n;
}
/**
* Constructor
*/
public SubmitForm() {
super();
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
// Reset values are provided as samples only. Change as appropriate.
name = null;
}


// public ActionErrors validate(
// ActionMapping mapping,
// HttpServletRequest request) {
// return super.validate(mapping, request);
// }

}



修改 submitpage.jsp 以启用服务器端验证:

  1. 在编辑器中打开 submitpage.jsp
  2. 如下所示修改该文件并保存。服务器端验证时必需的行 <html:errors /> 在客户端验证时不再需要。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="theme/Master.css" rel="stylesheet"
type="text/css">
<TITLE></TITLE>
</HEAD>
<BODY>
<html:form action="/submit"

οnsubmit="return validateSubmitForm(this);">
<bean:message key="submitForm.name"/>: <html:text property="name"/>
<html:submit/>
</html:form>
</BODY>

<html:javascript formName="submitForm"/>
</html:html>



<html:javascript formName="submitForm"/> 中的 formName submitForm 必须与 validation.xmlstruts-config.xml 文件中的表单名称相匹配。

运行该应用程序

由于我们对应用程序做了修改,所以我们必须重新启动该 EAR 项目:

  1. 在 Server 视图中,右键单击 WebSphere V5 Test Environment然后选择 Restart Project => DefaultEAR
  2. 项目重新启动后,右键单击 submitpage.jsp并选择 Run on Server

submitpage.jsp 装载到浏览器中后,单击 Submit,然后您将会看到一个弹出的 JavaScript 消息,告知字段 text field label 是必需的:



图 2. 客户端验证中的 JavaScript 弹出窗口

步骤 5. 使用其他验证器

有时,业务要求一个字段上有多个验证器。Struts 验证器使得一个字段可以由多个验证器进行验证。

例如,要添加一个电子邮件验证器,可以如下编辑 validation.xml 并保存它:

<form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required,

email">
<arg0 key="submitForm.name"/>
</field>
</form>
</formset>
</form-validation>



重新启动 DefaultEAR 项目并再次运行 submitpage.jsp 。输入一个无效的电子邮件地址并提交,您将会接收到一个错误消息,告知它不是一个有效的电子邮件地址。另外, required 验证器仍将继续工作。



图 3. e-mail 验证器发出的错误消息

在 某些情况下,您可能想提供一个更具体的错误消息而不是在资源束文件中定义的缺省错误消息。例如,如果您有一个 Mask 验证器,缺省错误消息是,该值是无效的,而没有关于无效性的详细情况。您可以用另一个消息覆盖 Mask 验证器的错误消息,方式是将如下一行代码添加到 validator.xml 中: <msg name="mask" key="some.other.error.msg"/>

将如下一行代码添加到文件 ApplicationResources.properties 中并保存:

some.other.error.msg = {0} is not a 5-digit number

如下编辑 validation.xml 并保存:

<form-validation>
<formset>
<form name="submitForm">
<field property="name" depends="required,

mask">


<msg name="mask" key="some.other.error.msg"/>
<arg0 key="submitForm.name"/>


<var>
<var-name>mask</var-name>
<var-value>^\d{5}\d*___FCKpd___12lt;/var-value>
</var>

</field>
</form>
</formset>
</form-validation>



重新启动 DefaultEAR 项目并再次运行 submitpage.jsp 。一个更具体的错误消息将会显示出来。



图 4. 一个自定义的错误消息

正在在使用的 Struts 验证器

如前所述,随 Struts 一起发布大约有 14 种基本的 Struts 验证器。每个验证器都可能要求不同的参数,而您必须提供正确的参数以使用它们。在本节中,您将在一个更为复杂的 Struts 应用程序中看到更多正在使用的验证器。

StrutsValidation.war 文件导入 DefaultEAR

  1. 下载 StrutsValidator.zip 并解压 StrutsValidation.war
  2. 在工作区中,选择 File => Import => WAR file。单击 Next
  3. 找到下载的 WAR 文件。
  4. 确保 NewWeb 项目被选中。输入 StrutsValidationWeb 作为该 Web 项目名。
  5. 确保 Existing企业应用程序被选中。找到 DefaultEAR
  6. 单击 Finish
  7. 如果出现一个对话框,通知您该 Web 项目将添加到服务器中,则单击 OK

重新启动服务器并在 StrutsValidationWeb 中运行 submitpage.jsp

  1. 在 Web 透视图--Server 视图中,右键单击 WebSphere V5 Test Environment并选择 Restart
  2. 展开 StrutsValidationWeb => Web Content,右键单击 submitpage.jsp并选择 Run on Server
  3. 在该 JSP 页面装载完毕之后,单击 Submit,您将会接收到这些错误消息:


图 5. 正在使用的 Struts 验证器

让我们来分析一下 validation.xml 。在编辑器中打开 validation.xml 。它在 /StrutsValidationWeb/Web Content/WEB-INF 中。

<form-validation>
<global>
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})___FCKpd___13lt;/constant-value>
</constant>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}\d*___FCKpd___13lt;/constant-value>
</constant>
</global>
<formset>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}(-\d{4})?___FCKpd___13lt;/constant-value>
</constant>
<form name="submitForm">
<field property="customer.firstName"
depends="required,mask,minlength">
<arg0 key="submitForm.customer.firstname"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+___FCKpd___13lt;/var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value> </var>
</field>
<field property="customer.lastName"
depends="required,mask,maxlength">
<msg name="mask" key="submitForm.lastname.maskmsg"/>
<arg0 key="submitForm.customer.lastname"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*___FCKpd___13lt;/var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>10</var-value>
</var>
</field>
<field property="customer.address"
depends="required">
<arg0 key="submitForm.customer.address"/>
</field>
<field property="customer.city"
depends="required,mask">
<arg0 key="submitForm.customer.city"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*___FCKpd___13lt;/var-value>
</var>
</field>
<field property="customer.state"
depends="required,mask">
<arg0 key="submitForm.customer.state"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*___FCKpd___13lt;/var-value>
</var>
</field>
<field property="customer.zip"
depends="required,mask">
<arg0 key="submitForm.customer.zip"/>
<var>
<var-name>mask</var-name>
<var-value>${zip}</var-value>
</var>
</field>
<field property="customer.phone"
depends="mask">
<arg0 key="s
ubmitForm.customer.phone"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
<field property="customer.email"
depends="required,email">
<arg0 key="submitForm.customer.email"/>
</field>
<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
<var>
<var-name>datePatternStrict</var-name>
<var-value>MM-dd-yyyy</var-value>
</var>
</field>
<field property="creditcard.number"
depends="required,creditCard">
<arg0 key="submitForm.creditcard.number"/>
</field>
</form>
</formset>
</form-validation>

下面是 Last Name 字段的代码。它依赖于 3 个验证器: required、maskmaxlengthrequired 验证器,如前所述,确保填写了该字段。 mask 验证器在这个示例中检查是否所有的值都是字母。 mask 验证器的 RegExp 表达式检查字母是否是 ^[a-zA-Z]*$maxlength 验证器确保这个示例中的字段的长度小于或等于 10。

示例 1. Last Name 字段的验证器映射

<field property="customer.lastName"
depends="required,mask,maxlength">
<msg name="mask" key="submitForm.lastname.maskmsg"/>
<arg0 key="submitForm.customer.lastname"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*___FCKpd___14lt;/var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>10</var-value>
</var>
</field>

下面的示例是使用 mask 验证器的一个小小的变种。这段代码是为 Phone 字段而写的。 mask 验证器包含参数 ${phone} ,它是在 validation.xml 文件的开头定义的一个常量(请参见示例3)。

示例 2. Phone 字段的验证器映射

<field property="customer.phone"
depends="mask">
<arg0 key="submitForm.customer.phone"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>

示例 3.phone 常量

<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})___FCKpd___16lt;/constant-value>
</constant>

下面的代码是为 Date 字段而写的。您可以在 date 验证器上使用它本身,如示例 4所示--它根据地区验证日期的格式。您也可以指定一个日期模式,如示例 5 所示:

示例 4.Date 验证器

<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
</field>

示例 5. 带 datePatternStrict 的 Date 验证器

<field property="creditcard.date"
depends="required,date">
<arg0 key="submitForm.creditcard.date"/>
<var>
<var-name>datePatternStrict</var-name>
<var-value>MM-dd-yyyy</var-value>
</var>
</field>

这个示例也适用于 emailcreditCard 验证器。由于这两个验证器都很简单,所以您可以自己去分析它们。





回页首


结束语

Struts 验证器框架使您能够使用服务器端和客户端验证。您可以在大多数 Web应用程序中不加修改地使用内置的规则集。出于性能方面的考虑,客户端验证通常是更好的选择。

Struts 框架通过应用模型-视图-控制器(Model-View-Controller)范式解耦 Web 组件。Struts Tiles框架将页面布局与表示层分离开来,而 Struts 验证器框架将验证逻辑和业务逻辑分离开来。使用 Struts 与 Struts 的相关框架可以使您的Web 应用程序具有更好的可维护性和可重用性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值