Struts Validator 使用方法

使Struts支持Validator
要在Struts项目中使用Validator功能,首先需要配置Struts项目,使其支持Validator框架.Struts通过一个插件(Plugin)来使Struts项目支持Validator.这个Plugin由Struts默认提供,用户也可以自己开发自己的ValidatorPlugin.Struts默认提供的Plugin为:

org.apache.struts.validator.ValidatorPlugIn.

用户必须在struts-config.xml文件中配置这个Plugin,才能使Struts项目支持Validator.配置方法比较简单,通过任何文本编辑器打开struts-config.xml文件,在这个文件的末尾加上下面的代码,重新启动J2EE服务器就可以实现对Validator的支持了.

<plug-inclassName="org.apache.struts.validator.ValidatorPlugIn">

<set-propertyproperty="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>

</plug-in>

在Jbuilder开发环境中可以通过下面的方法使Struts项目支持Validator框架.

1.在项目管理器中用鼠标右键点击Web项目(在我们的项目中是WebModule).

2.选择菜单的“Properties…”菜单项.

3.在弹出的对话框的左边树型结构中选中“web”节点.

4.在右边的“JSP/Servletframeworks”框中勾选“sturts1.1”节点以及“struts”节点下的“validation”子节点.

5.点击“OK”按钮完成配置.

6.检查struts-config.xml文件,可以看到配置文件里已经加入了ValidatorPlugin.

Validator-rules.xml文件

Validator-rules.xml文件是校验器的定义文件.指定了每一个校验器的基本信息和执行校验的JavaScript代码.Struts默认提供了十四个校验器,这些校验器可以满足我们平时项目开发中碰到的绝大多数的输入校验要求.如果这些校验器不能满足用户的校验要求,那么我们也可以开发自己的校验器.我们项目主就实现了一个校验密码的一致性的Validator.

Struts提供的校验器包括RequiredValidator,RequiredifValidator,MinLengthValidator,MaxLengthValidator,MaskValidator,ByteValidator,ShortValidaotr,IntegerValidator,LongValidator,FloatValidator,DoubleValidator,DateValidator,RangeValidator,IntRangeValidator,FloatRangeValidator,CrediteCardValidator,EmailValidator等校验器.后面我将讲述一些比较常用的校验器的使用方法.
Validator.xml文件
Validator.xml文件用来定义用户需要校验的每一个JSPForm中的每一个字段的校验规则,这个文件是我们在Struts项目开发中使用Validator框架所需要配置的文件.这个文件的根节点是<form-validator>,在根节点下的<formset>节点的<form>子节点就对应了我们在开发JSP文件是所定义的Form标记,也对应这struts-config.xml中的formbean的定义.一个<form>节点由多个<field>节点组成,每个<field>节点的结构大概如下:
<fieldproperty="password"depends="required,minlength,twofields">

<msgname="required"key="test.required"/>

<msgname="minlength"key="test.minlength"/>

<msgname="twofields"key="test.twofields"/>

<arg0key="test.password"/>

<arg1name="minlength"key="${var:minlength}"resource="false"/>

<var>

<var-name>minlength</var-name>

<var-value>8</var-value>

</var>

<var>

<var-name>secondProperty</var-name>

<var-value>password2</var-value>

</var>

</field>

其中一个<Field>对应于一个FormBean的一个Field,<Field>标记的property属性说明了这个Field对应的FormBean的Field名称,这个名称要跟struts-config.xml文件中的<form-bean>中定义的名字一致.depends属性说明了这个Field依赖于那些校验器的校验,可以使用多个校验器,各个校验器之间使用逗号隔开.<msg>标记说明了当这个Field通不过校验的时候向用户提供的错误信息.name属性指定了对应的校验器,key属性指定了定义在ApplicationResources.properties文件中的错误信息.<arg0>和<arg1>是传递给校验器的参数.<var>标记定义了参数的名字和参数值.上面的这个例子说明了password字段由Required,Minlength,Twofields校验器进行校验.指定了这个Field不能为空,而且最小长度不能小于8为,并且必须和同一个Form中的另一个名为password2的字段相同.如果用户的输入不能满足这些要求,校验器将会抛出异常.
下面开始将怎么在这个配置文件中配置各个校验器实现对form中的多中类型的field进行校验.
RequiredValidator
这个校验器用来校验Form的输入数据不能为空.如果某一个Form的Field依赖于这个校验器,那么如果用户在Form中没有输入这个Field对应的输入数据时,Required校验器将会触发一个Exception,这个Exception的错误信息可以在页面或者服务端被捕捉到.
例子:
<fieldproperty="test"depends="required">
<msgname="required"key="test.required"/>
<arg0key="test.testField.displayName"/>
</field>
上面的例子说明了test字段的校验规则是不能为空,在ApplicationResources.properties中的相应的定义信息可能是下面这样的情况:
Test.testField.displayName=测试字段#上面在<arg0>标记中定义的key=“test.testField”对应这个信息
Test.required={0}不能为空,请重新输入.#在上面定义的<msg>标记对应这个信息
如果Validator校验到用户没有输入test这个字段,就会将test.testField对应的信息作为test.required的参数传递给校验器,如果在JSP页面中捕捉了错误信息,错误信息将会是下面的这个形式:
“测试字段不能为空,请重新输入”
MaskValidator
MaskValidator校验用户输入的数据是否遵照一定的规则,这个规则由开发者在validator.xml文件中定义.
例子:
<fieldproperty="postalCode"depends="mask">
<arg0key="test.postalCode.displayname"/>
<arg1name=”mask”key="${var:mask}"resource="false"
<var>
<var-name>mask</var-name>
<var-value>^0\d*$</var-value>
</var>
</field>
上面的<arg1>标记说明了这个校验的第二个参数是定义在下面的<var>标记的名为mask的值.<var-value>的值说明了这个字段必须是以数字0开头,以任意数字字符结尾的一个串.
RangeValidator
这个校验器校验字段是否在一个数字范围内.
例子:
<fieldproperty="age"depends="range">
<msgname="range"key="test.rang"/>
<arg0key="test.age"/>
<arg1name="range"key="${var:min}"resource="false"/>
<arg2name="range"key="${var:max}"resource="false"/>
<var>
<var-name>min</var-name>
<var-value>1</var-value>
</var>
<var>
<var-name>max</var-name>
<var-value>100</var-value>
</var>
</field>
RangeValidator需要三个参数(arg),第一个参数arg0是指定这个字段的名字,第二个和第三个参数指定范围的最大和最小值,分别的名称是max和min.
MaxlengthValidator
Maxlength校验器校验一个字符串的最大长度,它需要两个参数,arg0说明字段的名称,arg1说明最大长度.
例子:
<fieldproperty="password"depends="maxlength">
<msgname="maxlength"key="test.minlength"/>
<arg0key="test.password"/>
<arg1name="maxlength"key="${var:maxlength}"resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>8</var-value>
</var>
</field>
MinlengthValidator
这个校验器类似于上面的MaxlengthValidator,参数一样,校验规则也一样,只是作为参数的变量名字为minlength
<fieldproperty="password"depends="minlength">
<msgname="minlength"key="test.minlength"/>
<arg0key="test.password"/>
<arg1name="minlength"key="${var:minlength}"resource="false"/>
<var>
<var-name>minlength</var-name>
<var-value>8</var-value>
</var>
</field>
EmailValidator
这个校验器校验电子邮件字段,当用户输入的电子邮件地址不合法的时候,校验器抛出异常.
例子:
<fieldproperty="email"depends="required,email">
<msgname="required"key="test.required"/>
<msgname="email"key="test.error.email"/>
<arg0key="test.email"/>
</field>
FormBean的编写要使用Struts的Validator框架进行自动校验的FormBean不能继承自普通的ActionForm,必须继承自ValidatorForm或者ValidatorActionForm.我们项目组都是继承自ValidatorForm.
ValidatorForm根据struts-config.xml文件中的action的name属性为当前form的调用相应的验证器,因此在validator-rules.xml中的<form-bean>元素的名称属性(name)应该与<action>的name属性值相匹配。
ValidatorActionForm使用struts-config.xml中action的path属性,所以path属性的值相应的应该与validator.xml中的Form的name属性匹配。
Struts-config.xml文件的配置
要使用Validator框架的自动校验机制,还必须在Struts-config.xml文件中作相应的配置.除了前面已经说明了的配置ValidatorPlugin意外,还需要对需要校验的form的action进行配置.主要有两个地方需要配置,一个是<action>的input属性,一个是<action>的validate属性.input属性必须指定包含校验Form的jsp页面的路径,以便Struts的校验框架校验失败的时候可以重新导向到原来的页面让用户重新输入.validator属性是一个boolean类型的属性,必须设置为truestruts才会启动自动校验机制.
在JSP页面捕捉错误信息
Validator的校验机制可以定义在服务端进行校验或者通过Javascript在浏览器端进行校验.这两种不同的方式在JSP页面编写的时候有很大的区别.
捕捉服务端的错误信息
要捕捉服务端校验的错误信息比较简单.只需要在JSP页面中嵌入一下的代码就可以在页面中显示错误信息,这些错误信息也可以自定义显示风格.

<logic:messagesPresent>
<bean:messagekey="test.error.descript"/>
<html:messagesid="error">
<li><bean:writename="error"/></li>
</html:messages>
</logic:messagesPresent>
<bean:messagekey=”test.error.descript”/>通过ApplicationResources.properties文件中定义的信息向用户报告错误发生的原因和简单说明.
<html:messagesid=”error”>
<li><bean:writename=”error”/></li>
</html:messages>
则是显示具体的由Validator框架产生的错误信息.
捕捉JavaScript的错误信息
要捕捉JavaScript产生的错误信息首先要使JSP页面产生Validator生成的Javascript代码,并在用户点击提交按钮的时候让提交按钮触发相应的校验函数.实现方法如下:
首先要让JSP触发校验函数,使用这样的HTML代码:
<html:formaction="/testAction.do"οnsubmit="returnvalidateTestForm(this);">
其中action指定这个form对应的action,这个跟普通的form没有区别,onsubmit属性就指定了校验函数,它的规则是:return+空格+validator+ValidatorForm的名字+(this)
注意这样的组合规则是不能变的,否则会导致页面错误并不能实现校验功能.还要注意ValidatorForm的名字的第一个字母一定要大写,不管在Struts-congfig.xml文件中的定义是否大写,这里都要把它作为大写字母.然后还要在JSP页面中产生可以实现校验的JavaScript代码,这个步骤也很简单,只需要在JSP页面的末尾加上下面一句:
<html:javascriptformName="testForm"staticJavascript="true"/>

其中formName的名字要跟struts-config.xml文件中配置的一致,大小写也要一致.staticJavascript为true的时候Validator将使用JavaScript代码进行校验(这些Javascript代码由Struts的validator框架自动产生,我们只需要配置validator.xml文件),staticJavascript为false的时候validator将使用服务端代码进行校验,这些服务端的校验代码也不需要我们编写


Commons-Validator(一)
Commons -Validator包用来把验证规则程序提取出来,以供重复使用。这个包可以使用在Struts中,也可以独立的应用在任何其它的应用中。用户可以通过 java类的方式自定义验证方法,也可以在配置文件中通过正则表达式配置验证方法。它不但支持服务器端的验证,客户端的验证也支持,具体需要使用tag把 相应的js方法写入相应的页面中。
一、综述:
整个Validator框架可以有若干个FormSet, 而每个FormSet又可以有若干个Form,每个Form中可以有若干个Field。FormSet的process(...)方法,逐个调用其中的 Form的process(...)方法,而Form的process(...)方法又是逐个调用Field的process(...)方法。 Validator类作为验证的起始点,调用与其一一对应的Form的validate(...)方法,而Form的validate(...)方法又是 逐个调用其中Field的validate(...)方法实现的。
二、配置文件说明:
<form-validation>
<global>
<constant>
<constant-name>验证方法的标志名</constant-name>
<constant-value>正则表达式</constant-value>
</constant>
<validator name="这个验证方法的标志名,供下面的depends调用"
classname="这个验证方法在哪个类中,为类全名"
method="验证方法的名称"
methodParams="这个验证方法需要的参数类型,依次以逗号格开,为类全名"
depends="基于什么验证之上,可以为多个值,以逗号格开,值为方法的标志名"
jsFunction="js的方法全名,格式为文件路径.方法名。文件路径以点隔开,
如果不填,默认为org.apache.commons.validator.javascript.xxxx"
msg="对应于properties文件中的一条,作为不通过验证时返回的信息"/>
</global>
<formset language="语言" country="城市" variant="方言?">
<constant>
<constant-name>验证方法的标志名</constant-name>
<constant-value>正则表达式</constant-value>
</constant>
<form name="bean 对象名称">
<field property="bean中的属性名"depends="需要什么样的验证,可以为多个值,以逗号格开,值为方法的标志名">
<arg name = "变量名" key = "properties文件的key,或者来自Var的name" resource = "是/否来自资源文件"/>
<var>
<var-name>变量名</var-name>
<var-value>变量值</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Commons-Validator(二)
在Validator的配置文件中,一共有如下几个基本元素。
一、org.apache.commons.validator.Var
它的作用是为配置文件(validator.xml)中的其它标签提供可取用的变量,为Field提供执行验证所需要的其它参数值,比如最大长度。这个类 有如下属性:name,变量的名称;value,变量的值;jsType,当要自动生成js的时候,js的类型。
二、org.apache.commons.validator.Arg
它的作用是替换信息中的某一部分,或者为验证方法提供必需的参数值。这个类有如下属性:bundle,资源文件名,用来存放所需要的信息。key,表示 Arg的key或者value。name,表示Arg的名称。position,这个Arg中的值用来替换信息中的哪一部分,需要替换的部分以{n}标 志。resource:key所指定的信息是否来自外部的资源文件,默认为true;如果为true,则代表key为buddle属性所指定的资源文件中 的key。
三、org.apache.commons.validator.Msg
它的作用是在验证不 通过时,应该返回什么的信息。这个类有如下属性:bundle,资源文件名,用来存放所需要的信息。key,表示Msg的key或者value。 name,表示Msg的名称。resource:key所指定的信息是否来自外部的资源文件,默认为true;如果为true,则代表key为 buddle属性所指定的资源文件中的key。
四、org.apache.commons.validator.FormSet
这个类管理通过一个Map所有要检验的Form对象,key为Form的name;同时通过一个Map管理在<formset/>中定义的 Constant,key为<constant-name>。同时其内部有language,country, variant这几个属性,用来实现国际化。一个配置文件可以有多个FormSet,这些FormSet的区别是要求不同的本地化。
五、org.apache.commons.validator.Form
这个类有如下属性:name,这个form的名称。lFields,一个保存所有Field的List。hFields,一个保存所有Field的 FastHashMap,这个FastHashMap的key值是对应Field的key属性(对应配置文件中的property)。这个类通过 validate(...)方法用来对这个Form中的所有位置低于page的Field进行验证。它实际是在一个循环中逐个调用每个field的 validate(...)方法,然后把结果保存在一个ValidatorResults对象中。
六、org.apache.commons.validator.Field
这个类有如下属性:depends,依赖于什么验证规则。dependencyList保存了以逗号为分隔符把depends分割生成的list。 page,如果是多步提交的话当前是第几步,值等于或小于表单中page性质的值,JavaBean 才会得到处理;args,是一个数组;这个数组的元素为HashMap,每个HashMap在数组的位置就是其中的Arg中的position属性的值; HashMap中的key值为Arg的name,如果这个name为null则为默认的值:DEFAULT_ARG (org.apache.commons.validator.Field.DEFAULT),value为Arg对象。hVars,是一个 FastHashMap,用来管理所有的Var对象,key为Var的name,值为Var对象。getIndexedListProperty表明这个 property为JavaBean中的一个数组元素的index。
1、process(Map globalConstants, Map constants)
这个方法用来执行配置文件中变量的替换。它的两个参数分别为在<global/>和<formset/>中定义的 constant。在这个Map中,key为<constant/>标签中的constant-name,value为< constant-value>。在配置文件中,可以实现如下的变量使用方式:Form的property属性,Var中的value属性,Arg 中的key属性,Msg的key属性,他们均可以通过{constant-name}的方式,引用在<global/>或者< formset/>标签中定义的constant。Arg中的key属性,可以通过{Var:var-name}的方式引用在< var/>中定义的Var。
FormSet中的process(...)方法依次调用其中的Form的process(...)方法,而Form的process(...)方法又依次调用其中的Field的process(...)方法。
2、validate(Map params, Map actions)
执行验证,其中actions保存了所有的ValidatorAction对象。它首先会从params取出key为 Validator.BEAN_PARAM(java.lang.Object)的值作为要验证的JavaBean。然后通过generateKey() 方法判断当前要验证的Field是否是IndexedList。如果是,则需要分别对这个List中的各个元素进行验证;否则直接执行对与 JavaBean的特定属性(property)执行验证。
3、validateForRule(...)
接受要执行的 ValidatorAction对象的同时,还是会接受Map actions参数,这是因为这个要执行的ValidatorAction可能会依赖于其它的ValidatorAction。它会先查找以前的验证结 果,如果以前没有执行过这个验证,那么执行runDependentValidators(...)方法,执行它所依赖于的 ValidatorAction;如果通过,那么再对要执行的ValidatorAction,执行验证。
Commons-Validator(三)
在Validator包中提供了一些Util类,同时提供了对基本数据类型,时间,E-mail,信用卡等格式的验证方法。
一、org.apache.commons.validator.util.Flags
这个类用来管理一系列的Flag,其中的每个Flag的值都是2的N次方。然后每个Flag之间位与(&)就得到了整个Flags的值。
二、org.apache.commons.validator.util.ValidatorUtils
这个类为Validator提供一些Utility的操作,共有三个方法。
1、replace(...)
这个方法用来将一个字符串中某个特性的字符串替换为另一个字符串,注意这是一个全局替换方法。
2、getValueAsString(...)
这个方法用来获取某个Bean中的一个特定的属性,然后把属性值转换为字符串返回。注意,String[]和Collection类型的值,如果里面不包含任何值,则直接返回""。
3、copyFastHashMap(...)
很显然的是对一个特定的FashHashMap执行copy。这里要注意的是,如果value为Msg,Arg,Var类型的时候需要执行clone,然后再保存。
三、org.apache.commons.validator.ValidatorUtil
这个类完全通过调用上面的ValidatorUtils方法,实现自己的同名方法。只是多了一个getDelimitedRegExp(...)方法,用来生成一个正则表达式。
四、org.apache.commons.validator.DateValidator
实现了单例模式。这个类用来检查日期类型是否合法,日期的类型要通过参数传递给这个Validator。同时还有一个strict属性,表示时候检查过渡 匹配所要求的日期格式。这个日期检查就是通过formatter.parse(value)方法检查时候有异常抛出。
五、org.apache.commons.validator.EmailValidator
实现了单例模式。这个类用来检查Email类型是否合法。它通过正则表达式实现验证。
六、org.apache.commons.validator.GenericTypeValidator
这个类实现了对基本类型(Byte,Short,Int,Long,Float, Date)的检测,方法很简单,就是通过每个类型的构造函数创建相应的对象,如果抛出异常就说明不符合,否则符合。同时,这个类还提供对CreditCard验证的实现。
Commons-Validator(四)
通过调用Validator的validate(...)方法,启动验证。
一、org.apache.commons.validator.Validator
这个类是对一个Form执行验证的起点,通过调用这个类的validate(...)方法,启动验证。这个类中的formName属性,对应于Form中 的name属性。resources属性,记录这个Validator属于哪一个ValidatorResources。parameters用来管理执 行validateXXX(...)方法时所需要的参数,它是一个Map,key为类全名,value为这个类全名所指的类的一个对象。注意,这个 parameters是这个Form中所有Field所要执行的所有validateXXX(...)方法时所需要的参数集合。每个 validateXXX(...)方法,根据自己需要的参数名(类全名),从这个parameters中查取自己所需要的参数。
二、org.apache.commons.validator.ValidatorAction
每个ValidatorAction对应于配置文件中的一个<validator/>。它有如下属性:name,这个验正动作的标志名,用在 depends属性的配置中。classname,这个验证方法在哪个类中,为类全名。validationClass,由classname生成的 Class。method,这个验证方法的名称。validationMethod,由method生成的Method。methodParams,执行 这个验证方法所需要的参数,值为逗号隔开的类全名,默认值为Validator.BEAN_PARAM, Validator.VALIDATOR_ACTION_PARAM,Validator.FIELD_PARAM。parameterClasses, 由methodParams生成的Class数组。depends,依赖何ValidatorAction之上。msg,如果没有通过此验证,应该返回什 么消息。javascript,为对应的javascript方法的代码内容。jsFunction,为对应的js文件名称。 jsFunctionName,对应的js中方法的名称。
1、executeValidationMethod(...)
这个方法用对Field中的值进行检测。它实际上就是通过反射,根据类名、方法名和参数类型执行相应的验证方法。要注意的是,如果这个Field为 indexList类型的,则需要把Java Bean替换为对应的Array中pos指定的元素。同时Field的key属性中的[]要变为[pos]。
2、这个类还提供了对js的基本操作,解释如下:
*generateJsFunction()
用来生成名为org.apache.commons.validator.javascript.validateXxxx的js文件名。其中Xxxx与name相对应。
*readJavascriptFile(...)
用来读取js文件。由于一个js文件只包含一个方法,因此会读取所有的内容后,直接返回所读取的所有内容。
三、org.apache.commons.validator.ValidatorResults
这个类管理对一个Form中的所有Field执行验证的结果。它有如下属性:hResults,用来管理对所有Field验证的结果,它的key为field的kye属性,它的value为ValidatorResult对象。
四、org.apache.commons.validator.ValidatorResult
这个类用来管理对于一个Field执行验证的时候,所有的验证方法的结果。它有如下属性:field,所要验证的Field对象。hAction,用来保 存所有验证结果的Map,它的key为ValidatorAction中的name属性,value为ResultStatus对象。
五、org.apache.commons.validator.ResultStatus
它封装了对某个Field执行某个验证后的结果。它有如下属性:valid,表示是否通过验证。result:为执行验证后的结果。
Commons-Validator(五)
最后,说明Validator是如何初始化的。
一、org.apache.commons.validator.ValidatorResourcesInitializer
这个类用来初始化Validator框架,通过Digester包解析用户自定义的xml配置文件。然后把解析的结果保存到ValidatorResources对象中,最后返回这个ValidatorResources对象。
二、org.apache.commons.validator.ValidatorResources
这个类用来管理Validator框架中的资源。它包含如下属性:hFormSets,一个FastHashMap,用来管理所有的FormSet,这个 FastHashMap的key为根据FormSet中的本地信息生成的。hConstants,一个FastHashMap,用来管理< global/>中定义的constant。hActions,一个FastHashMap,用来管理ValidatorAction,它的key 为ValidatorAction的name属性。
三、与struts整合时需要增加的配置:
在struts-config.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>
其中validator-rules.xml,为Struts自带的配置文件,配置了所有的验证方法;而validation.xml为用户自己配置,配置要验证的对象。
四、org.apache.struts.validator.FieldChecks
这个是Struts使用的核心验证类,用来实现各种验证规则。其中,validateXXX(...)就是想要创建的方法名,只要规则名没有重复即可。validateXXX(...)方法的参数说明:
Object 验证是在此JavaBean 对象上完成的
ValidatorAction当前所执行的ValidatorAction
Field被验证的字段对象
ActionErrors 如果验证失败,新增ActionError 对象的错误对象
HttpServletRequest 当前的请求对象
五、org.apache.commons.validator.ValidatorResources
这个类用来通过Arg替换Msg中格式为{N}的字符串
六、org.apache.commons.validator.ValidatorPlugIn
这个类用来初始化Validator,然后把初始化生成的ValidatorResources对象保存到ServletContext中,key为VALIDATOR_KEY + config.getPrefix()。
七、org.apache.struts.validator.Resources
这 个类用来初始化一个Validator对象,它首先通过key值VALIDATOR_KEY + config.getPrefix()从ServletContext取得相应的ValidatorResources对象。它再以这个对象为参数构造一 个Validator对象,然后把验证方法需要的参数保存到Validator对象的parameters属性中

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值