首页 > 代码库 > 自定义验证器——用Struts2框架以框架师的思维灵活做好该事情
自定义验证器——用Struts2框架以框架师的思维灵活做好该事情
面对的问题:自定义一个18位身份验证器,编写验证器,在validators.xml文件中进行注册、在验证配置文件中使用?
第一部分:理解Struts2中自带的验证器
第二部分:怎样通过服务器(后台),再次对前台的数据进行验证
第三部分:用Struts2来自定义验证器(问题解决方案)
第一部分:理解Struts2中自带的验证器
Struts2框架中自带的后台服务器验证分为两种:声明式验证和编程式验证
u 声明式验证(重点)
? 对哪个 Action 或 Model 的那个字段进行验证
? 使用什么验证规则
? 如果验证失败, 转向哪一个页面, 显示是什么错误消息
u 编程式验证
声明式验证(重点)详细分析:
1、先明确对哪一个 Action 的哪一个字段进行验证: 比如说“age”字段。
2、编写配置文件:
>把 struts-2.3.15.3\apps\struts2-blank \WEB-INF\src\java\example 下的 Login-validation.xml 文件复制到当前 Action 所在的包下。
>把该配置文件改为: 把Login 改为当前 Action 的名字,比如本例用的到,如下文件.
E:\Java开发的工具包\struts2.X 开源工具包\struts-2.3.15.1\apps\struts2-blank\WEB-INF\src\java\example详细信息 |
<!DOCTYPEvalidators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators> <fieldname="username"> <field-validatortype="requiredstring"> <messagekey="requiredstring"/> </field-validator> </field> <fieldname="password"> <field-validatortype="requiredstring"> <messagekey="requiredstring"/> </field-validator> </field> </validators> |
>编写验证规则: 参见 struts-2.3.15.3/docs/WW/docs/validation.html文档即可(帮助文档——很实用的文档).
1. conversion validator 2. date validator 3. double validator 4. email validator 5. expression validator 6. fieldexpression validator 7. int validator 8. regex validator 9. required validator 10. requiredstring validator 11. short validator 12. stringlength validator 13. url validator 14. visitor validator 15. conditionalvisitor validator |
单击date validator进入相应的页面——如下图所示:
拷贝相应的文件进行TestValidationAction-validation.xml配置文件中
> 在配置文件中可以定义错误消息:
<fieldname="age">
<field-validator type="int">
<param name="min">20</param>
<param name="max">50</param>
<message>Age needs to be between ${min}and ${max}</message>
</field-validator>
</field>
> 该错误消息也可以国际化操作,详细请参看以前写的blog《用Struts2进行中英文一键切换——包含详细的源代码解析及Struts2国际化原理的理解》。
在TestValidationAction-validation.xml文件中添加如下信息 |
<field-validatortype="int"> <paramname="min">20</param> <paramname="max">60</param> <messagekey="error.int"></message> </field-validator> |
再在国际化资源文件中(src/i18n.properties)加入一个键值对: error.int=Age needs to be between ${min}and ${max}
3、若验证失败, 则转向 input 的那个 result. 所以需要配置 name=input 的 result
在src/struts.xml文件中添加如下信息: |
<actionname="testValidation"class="com.atguigu.struts2.validation.app.TestValidationAction"> <result>/success.jsp</result>
<!-- 若验证失败转向的 input --> <resultname="input">/validation.jsp</result> </action> |
类com.atguigu.struts2.validation.app.TestValidationAction的内容 |
4、如何显示错误消息呢 ?
u 若使用的是非 simple(主要是指Struts2中JSP页面《展现出》中主题的设置,一般默认的为XHTML主题,该文件在源代码中的位置为:\WebContent\WEB-INF\lib\struts2-core-2.3.15.3.jar\template.simple), 则自动显示错误消息。
u 若使用的是simple主题, 则需要 s:fielderror 标签或直接使用 EL 表达式(使用 OGNL)
<!-- 要求年龄必须在 20-50之间 --> <s:formaction="testValidation"theme="simple"> Age: <s:textfieldname="age"label="Age"></s:textfield> <%-- ${fieldErrors.age[0] } --%> <s:fielderrorfieldName="age"></s:fielderror> <s:submit></s:submit> </s:form> |
5、关键点理解:若一个 Action 类可以应答多个 action 请求, 多个 action 请求使用不同的验证规则, 怎么办 ?
u 为每一个不同的 action 请求定义其对应的验证文件: ActionClassName-AliasName-validation.xml
u 不带别名的配置文件: ActionClassName-validation.xml 中的验证规则依然会发生作用. 可以把各个 action 公有的验证规则配置在其中. 但需要注意的是, 只适用于某一个 action 的请求的验证规则就不要这里再配置了.
6、短路验证: 若对一个字段使用多个验证器, 默认情况下会执行所有的验证. 若希望前面的验证器验证没有通过, 后面的就不再验证, 可以使用短路验证。
<!-- 针对 age属性进行验证. 基于字段的验证 --> <fieldname="age"> <!-- 设置短路验证:若当前验证没有通过, 则不再进行下面的验证 --> <field-validatortype="conversion"short-circuit="true"> <message>^Conversion Error Occurred</message> </field-validator>
<field-validatortype="int"> <paramname="min">20</param> <paramname="max">60</param> <messagekey="error.int"></message> </field-validator> </field> |
7、 若类型转换失败, 默认情况下还会执行后面的拦截器, 还会进行验证. 可以通过修改 ConversionErrorInterceptor源代码的方式使当类型转换失败时, 不再执行后续的验证拦截器, 而直接返回input的result。
具体步骤如下: 1、 通过Struts-default.xml文件中找到conversionError拦截器,查看相应的信息,如下所示:<interceptorname="conversionError"class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> 2、 通过Ctrl + Shift + T,输入StrutsConversionErrorInterceptor追踪到该方法。之后追踪到该方法的父类ConversionErrorInterceptor。 3、 在自己创建的项目src先创建com.opensymphony.xwork2.interceptor包,之后创建ConversionErrorInterceptor.java的Java类。 4、 将追踪到的com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.java源代码拷贝到刚好创建的文件中。之后再添加如下语句。 |
8、关于非字段验证: 不是针对于某一个字段的验证.
(src\com.atguigu.struts2.validation.app) |
<!-- 测试非字段验证 --> <validatortype="expression"> <paramname="expression"><![CDATA[password==password2]]></param> <message>Password is not equals to password2</message> </validator> |
(WebContent\validation.jsp) |
Password: <s:passwordname="password"></s:password> Password2: <s:passwordname="password2"></s:password> |
( src\com\atguigu\struts2\validation\app\TestValidationAction.java) 在该方法中添加password和password2两个属性,及相应的get和set方法。 |
public class TestValidationAction extends ActionSupport{ private Stringpassword; private Stringpassword2; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPassword2() { return password2; } public void setPassword2(String password2) { this.password2 = password2; } } |
细节注意:显示非字段验证的错误消息, 使用 s:actionerror 标签: (单独一行就行了)<s:actionerror/>
9、不同的字段使用同样的验证规则, 而且使用同样的响应消息 ?
第二部分:怎样通过服务器(后台),再次对前台的数据进行验证
1、声明式验证框架的原理:
u Struts2 默认的拦截器栈中提供了一个 validation 拦截器
u 每个具体的验证规则都会对应具体的一个验证器. 有一个配置文件把验证规则名称和验证器关联起来了. 而实际上验证的是那个验证器.
u 该文件位于 com.opensymphony.xwork2.validator.validators下的default.xml
<interceptorname="timer"class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/> <interceptorname="logger"class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/> <interceptorname="chain"class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/> <interceptorname="staticParams"class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> <interceptorname="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/> <interceptorname="filterParams"class="com.opensymphony.xwork2.interceptor.ParameterFilterInterceptor"/> <interceptorname="removeParams"class="com.opensymphony.xwork2.interceptor.ParameterRemoverInterceptor"/> <interceptorname="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> <interceptorname="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> <interceptorname="validation"class="com.opensymphony.xwork2.validator.ValidationInterceptor"/> <interceptorname="workflow"class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/> <interceptorname="prepare"class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> <interceptorname="conversionError"class="com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor"/> <interceptorname="alias"class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> <interceptorname="exception"class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> <interceptorname="i18n"class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/> |
第三部分:怎样用Struts2来自定义验证器(详细原理阐述)
I、整个流程步骤简介:
A. 自定义的验证器都需要实现 Validator.(相当于一个JavaBean)
B. 可以选择继承 ValidatorSupport 类或 FieldValidatorSupport 类
C. 若希望实现一个一般的验证器, 则可以继承 ValidatorSupport
D. 若希望实现一个字段验证器, 则可以继承 FieldValidatorSupport
E. 具体实现可以参考目前已经有的验证器(Struts2自带的验证器).
F. 若验证程序需要接受一个输入参数, 需要为这个参数增加一个相应的属性
II、在配置文件中配置验证器(验证配置文件加载顺序):
A. 默认情况下, Struts2 会在 类路径的根目录下加载 validators.xml文件. 在该文件中加载验证器.
该文件的定义方式同默认的验证器的那个配置文件一样,可以参看其进行书写: 默认文件位于 com.opensymphony.xwork2.validator.validators 下的 xwork-default.xml |
B. 若类路径下没有指定的验证器, 则从com.opensymphony.xwork2.validator.validators 下的 default.xml 中的验证器加载
III. 自定义一个18位身份验证器,编写验证器,在validators.xml文件中进行注册、在验证配置文件中使用?
步骤一:书写18位身份证的JavaBean类代码: |
/** * 身份证第十八位(效验码)的计算方法 * 将前面的身份证号码17位数分别乘以不同的系数,从第一位到第十七位的系数分别为: * 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 * 计算规则:身份证前十七位与这些系数相乘之和相加,用加出来的和除以11,看余数是多少?余数可能是 * 0, 1, 2 , 3, 4, 5, 6, 7, 8, 9, 10,这十一位数字,其分别对应的最后一位身份证号码为: * 1, 0, ‘X‘, 9, 8, 7, 6, 5, 4, 3, 2 * */ public class IDCard { final int[] wi = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 }; final int[] vi = { 1, 0, ‘X‘, 9, 8, 7, 6, 5, 4, 3, 2 }; private int[] ai = newint[18];
public IDCard() {}
public boolean Verify(String idcard) { if (idcard.length() == 15) { idcard = uptoeighteen(idcard); } if (idcard.length() != 18) { return false; } String verify = idcard.substring(17, 18); if (verify.equals(getVerify(idcard))) { return true; } return false; }
/** * 该方法是新18位身份证,效验码的计算 * * 身份证第十八位(效验码)的计算方法 * 将前面的身份证号码17位数分别乘以不同的系数,从第一位到第十七位的系数分别为: * 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 * 计算规则:身份证前十七位与这些系数相乘之和相加,用加出来的和除以11,看余数是多少?余数可能是 * 0, 1, 2 , 3, 4, 5, 6, 7, 8, 9, 10,这十一位数字,其分别对应的最后一位身份证号码为: * 1, 0, ‘X‘, 9, 8, 7, 6, 5, 4, 3, 2 */ public String getVerify(String eightcardid) { int remaining = 0;
if (eightcardid.length() == 18) { eightcardid = eightcardid.substring(0, 17); }
if (eightcardid.length() == 17) { int sum = 0; for (int i = 0; i < 17; i++) { String k = eightcardid.substring(i, i + 1); ai[i] = Integer.parseInt(k); }
for (int i = 0; i < 17; i++) { sum = sum + wi[i] *ai[i]; } remaining = sum % 11; }
return remaining == 2 ?"X" : String.valueOf(vi[remaining]); }
/** * 如果是以前的身份证号码,则将15位的身份证号码,转换为18位的新的身份证号码 * 旧身份证号码规则:(15位) * 1-6位:地区编码 * 7、8位:出生年的后两位(特点:只能对1900年1月1日到1999年12月31日出生的人编码——千年虫问题) * 9、10、11、12位:出生月和日,不足两位的高位补零 * 13、14、15位:顺序号,无法确认,15位是性别识别码,男性为奇数,女性为偶数。 * */ public String uptoeighteen(String fifteencardid) { String eightcardid = fifteencardid.substring(0, 6); eightcardid = eightcardid + "19"; eightcardid = eightcardid + fifteencardid.substring(6, 15); eightcardid = eightcardid + getVerify(eightcardid); return eightcardid;
}
public static void main(String[] args) {
String idcard1 = "350211197607142059"; String idcard2 = "350211197607442059";
IDCard idcard = new IDCard(); System.out.println(idcard.Verify(idcard1)); System.out.println(idcard.Verify(idcard2)); } }
|
步骤二:一个18位身份验证器的Java类 |
package com.atguigu.struts2.validation.app;
import com.opensymphony.xwork2.validator.ValidationException; import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class IDCardValidator extends FieldValidatorSupport {
@Override public void validate(Object object) throws ValidationException { //1. 获取字段的名字和值 String fieldName = getFieldName(); Object value = http://www.mamicode.com/this.getFieldValue(fieldName, object);
//2. 验证 IDCard idCard = new IDCard(); boolean result = idCard.Verify((String)value);
//3. 若验证失败,则 ... if(!result){ addFieldError(fieldName, object); }
} }
|
步骤三:书写validators.xml配置文件(可以参看com.opensymphony.xwork2.validator.validators 下的 default.xml 中的配置文件,进行修改) |
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEvalidators PUBLIC "-//Apache Struts//XWork Validator Definition 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">
<!-- START SNIPPET: validators-default --> <validators> <validatorname="idcard"class="com.atguigu.struts2.validation.app.IDCardValidator"/> </validators> |
步骤四:页面展现层的代码: |
<s:actionerror/> idCard: <s:textfieldname="idCard"></s:textfield> <s:fielderror fieldName="idCard"></s:fielderror> <s:submit></s:submit> |
这样就实现了服务器后台验证身份证的程序验证器已经部署完成。 |
自定义验证器——用Struts2框架以框架师的思维灵活做好该事情