在Struts2中,我们可以在后台实现对Action的所有方法进行校验或者对Action的指定方法进行校验,那为什么要在后台进行验证呢?在前台jsp页面中不是可以通过javaScript进行验证码?之所以要通过后台验证是因为很多高手可以跳过前台的js验证,比如直接从地址栏中拼接一些参数,传到后台。
对于输入校验Struts2提供了两种实现方法:
1.采用手工编码的方式实现。
2.基于XML配置方式实现。
我们先来看看通过手工代码实现对Action中所有方法的验证:
首先Action要继承ActionSupport,然后在重写父类的validate()方法,这样就可以对Action中所有的方法进行输入校验。
示例:
validate.jsp:
<body> <form action="validateAction_add.action" method="post"> 用户名:<input type="text" name="userName"/></br> 邮箱:<input type="text" name="email"/></br> 手机号码:<input type="text" name="telePhone"/></br> <input type="submit" value="提交"/> </form> </body>
ValidateAction.java:
public class ValidateAction extends ActionSupport { private static final long serialVersionUID = 1L; private String userName; private String email; private String telePhone; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelePhone() { return telePhone; } public void setTelePhone(String telePhone) { this.telePhone = telePhone; } public String add(){ return this.SUCCESS; } public String login(){ return this.SUCCESS; } /** * 重写父类的方法,对Action中的方法进行验证 */ @Override public void validate() { /*验证用户名*/ if (userName == null || "".equals(userName)){ this.addFieldError(userName, "用户名不能为空"); } if (email == null || "".equals(email) || email.indexOf("@")<1 || email.lastIndexOf(".")<2 || email.indexOf("@") > email.lastIndexOf(".")){ this.addFieldError(email, "邮箱格式不正确"); } /*使用正则表达式验证手机号码*/ Pattern pa = Pattern.compile("^1[358][0-9]{9}$"); /*验证是否匹配*/ boolean isOK = pa.matcher(telePhone).matches(); if (!isOK){ this.addFieldError(telePhone, "手机号码格式不正确"); } } }
注:如上述代码,重写父类的validate()方法之后,可以拦截Action中的add()和login()方法,验证失败之后会自动跳转到input对应的视图。
struts.xml:
<action name="validateAction_*" method="{1}" class="com.lixue.web.action.ValidateAction"> <result name="success">/success.jsp</result> <!-- 当校验失败时会跳转到input对应的视图 --> <result name="input">/error.jsp</result> </action>
success.jsp:
<body> <s:property value="userName"/><br> <s:property value="email"/><br> <s:property value="telePhone"/><br> </body>
error.jsp(只需要一个错误字段<s:fielderror>即可):
<body> <s:fielderror></s:fielderror> </body>
往往有时候,我们不需要验证Action中所有的方法,而是验证某一个方法就可以。在struts2中我们可以写一个validateXxx()方法进行验证(注:Xxx为方法名,第一个字母要大写)。
如,修改ValidateAction.java中的代码,我们只验证add()方法:
public class ValidateAction extends ActionSupport { private static final long serialVersionUID = 1L; private String userName; private String email; private String telePhone; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelePhone() { return telePhone; } public void setTelePhone(String telePhone) { this.telePhone = telePhone; } public String add(){ return this.SUCCESS; } public String login(){ return this.SUCCESS; } /** * validateAdd()方法,只对Action中的add()方法进行验证 */ public void validateAdd() { /*验证用户名*/ if (userName == null || "".equals(userName)){ this.addFieldError(userName, "用户名不能为空"); } if (email == null || "".equals(email) || email.indexOf("@")<1 || email.lastIndexOf(".")<2 || email.indexOf("@") > email.lastIndexOf(".")){ this.addFieldError(email, "邮箱格式不正确"); } /*使用正则表达式验证手机号码*/ Pattern pa = Pattern.compile("^1[358][0-9]{9}$"); /*验证是否匹配*/ boolean isOK = pa.matcher(telePhone).matches(); if (!isOK){ this.addFieldError(telePhone, "手机号码格式不正确"); } } }
输入校验的流程:
1.类型转换器对请求参数执行类型转换,并把转换后的值赋给Action中的属性。
2.如果在执行类型转换的过程中出现异常,系统将异常信息保存ActionContext中,conversionError拦截器奖异常信息添加到fieldErrors里。不管类型转换是否出现异常,都会进入第3步。
3.系统通过反射技术先调用Action中的validateXxx()方法,Xxx为方法名。
4.在调用Action中的validate()方法。
5.经过上面4步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fieldErrors有任何错误信息,系统将执行Action中的处理方法。
使用XML配置的方式对Action的所有方法进行输入校验:
使用XML配置方式实现输入校验时,Action也需要继承actionSupport,并且提供校验文件,校验文件和Action类放在同一个包下,文件取名格式:ActionClassName-validation.xml其中ActionClassName为Action的简单类名,-validation.xml为固定写法。比如:UserAction的全类名为:com.lixue.action.UserAction,那么验证器要放在com.lixue.action这个包下,并且取名为:UserAction-validation.xml
示例:
ValidateAction.java:
public class ValidateAction extends ActionSupport { private static final long serialVersionUID = 1L; private String userName; private String email; private String telePhone; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelePhone() { return telePhone; } public void setTelePhone(String telePhone) { this.telePhone = telePhone; } public String add(){ return this.SUCCESS; } public String login(){ return this.SUCCESS; } }
ValidateAction-validation.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <validators> <field name="userName"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>用户名不能为空~!</message> </field-validator> </field> <field name="email"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>邮箱不能为空!</message> </field-validator> <field-validator type="email"> <message>电子邮箱格式不正确!</message> </field-validator> </field> <field name="telePhone"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>电话不能为空!</message> </field-validator> <field-validator type="regex"> <param name="expression"><![CDATA[^1[358]\d{9}$]]></param> <message>手机号码格式不正确!</message> </field-validator> </field> </validators>
注:如果我们没有指定上述代码中的email和telePhone为非空,那么将不会对他们进行非空验证哈。
字段校验器的配置风格:
属性文件说明:
<field>指定Action中要验证的属性。
type表示验证的类型,系统提供了能满足大部分的校验器,这些校验器的定义可以在xwork-2.x.jar中的com.opensymphony.xwork2.validator.validators下的default.xml中找到。
<message>为校验失败后提示的信息。
注:struts.xml文件中必须配置input对应的视图,因为如果校验失败系统会跳转到input对应的视图,且通过视图中的<s:fielderror>来显示错误信息。
系统提供的校验器如下:
校验器使用的例子:
required必填校验器:
<field-validator type="required"> <message>性别不能为空!</message> </field-validator>
requiredstring必填字符串校验器:
<field-validator type="requiredstring"> <param name="trim">true</param> <message>用户名不能为空!</message> </field-validator>
stringlength字符串长度校验器:
<field-validator type="stringlength"> <param name="maxLength">10</param> <param name="minLength">2</param> <param name="trim">true</param> <message><![CDATA[产品名称应在2-10个字符之间]]></message> </field-validator>
email邮件地址校验器:
<field-validator type="email"> <message>电子邮件地址无效</message> </field-validator>
regex正则表达式校验器:
<field-validator type="regex"> <param name="expression"><![CDATA[^1[358]\d{9}$]]></param> <message>手机号格式不正确!</message> </field-validator>
int整数校验器:
<field-validator type="int"> <param name="min">1</param> <param name="max">150</param> <message>年龄必须在1-150之间</message> </field-validator>
字段OGNL表达式校验器:
<field name="imagefile"> <field-validator type="fieldexpression"> <param name="expression"><![CDATA[imagefile.length() <= 0]]></param> <message>文件不能为空</message> </field-validator> </field>
XML配置方式对Action指定方法实现输入校验:
有时候我们不需要校验Action中的所有方法,而只需要校验某一个方法,此时我们只需要修改配置文件的名称即可,命名格式为:ActionClassName-ActionName-validation.xml,ActionName为strus.xml中Action的名称,如:
struts.xml:
<action name="validateAction_*" method="{1}" class="com.lixue.web.action.ValidateAction"> <result name="success">/success.jsp</result> <!-- 当校验失败时会跳转到input对应的视图 --> <result name="input">/error.jsp</result> </action>
我要校验Validation中的一个add()方法,那么我么XML文件应该取名为:ValidateAction-validateAction_add-validation.xml,validateAction_add为Action的名称,因为是通配符,所以要加上方法名。这个配置文件同样是放在要校验的Action包下。
配置文件的校验特点:
当某个Action提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml两种规范的校验文件时,系统会按以下顺序寻找校验文件:
1:ActionClassName-validation.xml
2:ActionClassName-ActionName-validation.xml
系统寻找到第一个校验文件时还会继续搜索后面的校验文件,当搜索到所有的校验文件时,会把校验文件里所有的校验规则汇总,然后全部用于Action方法的校验。如果两个校验文件中的校验规则冲突,则只使用后面文件中的校验规则。
注:如果Action继承自另外一个Action,那么父类Action的校验文件将会先被搜索到。
自定义校验器:
可以通过实现com.opensymphony.xwork2.validator接口或者继承其子类的方式来自定义校验器。
步骤:
1.继承FieldValidatorSupport类,并重写validate()方法。
2.在src目录下建立validators.xml文件,将自定义校验器配置在该文件中。
项目结构:
自定义校验器MyValidator.java代码:
/** * 自定义校验器类 * @author Liao */ public class MyValidator extends FieldValidatorSupport{ /** * 自定义规定的内容,在MyValidatorAction-validation.xml中定义了, * str必须为习近平,前台传过来的值必须和它进行比较 */ private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } /** * 重写validate()方法 */ public void validate(Object obj) throws ValidationException { /*获取用户传过来的字段名称*/ String userName = super.getFieldName(); /*根据字段名称获取用户输入的值*/ String value = (String) super.getFieldValue(userName, obj); /*判断要校验的值和用户输入的值是否相等*/ if (!str.equals(value)){ /*添加错误信息*/ super.addFieldError(super.getFieldName(), obj); } } }
MyValidatorAction.java代码:
public class MyValidatorAction extends ActionSupport { private static final long serialVersionUID = 1L; private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String add(){ return this.SUCCESS; } }
MyValidatorAction-validation.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <validators> <field name="userName"> <field-validator type="myValidator"> <!-- 指定用户必须输入的值 --> <param name="str">习近平</param> <message>用户名必须是习近平</message> </field-validator> </field> </validators>
validators.xml(在src目录下):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator Definition 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd"> <validators> <!-- 定义我们自己的校验器 --> <validator name="myValidator" class="com.lixue.web.action.MyValidator"></validator> </validators>
struts.xml:
<action name="myValidatorAction_*" method="{1}" class="com.lixue.web.action.MyValidatorAction"> <result name="success">/success.jsp</result> <!-- 当校验失败时会跳转到input对应的视图 --> <result name="input">/error.jsp</result> </action>
注:一定要 有input视图,因为校验失败时跳转到input对应的视图,并且通过<s:fielderror>标签来接收:
error.jsp:
<body> <s:fielderror></s:fielderror> </body>