一、Struts2提供了基于验证框架的输入校验,在这种校验方式下,所有的输入校验只需要编写简单的配置文件,Struts2的验证框架将会负责进行服务器校验和客户端校验。
校验失败后将Struts2将自动返回名为“input”的Result,如需制定错误显示页面,则通过struts.xml来配置“input”的Result。在Result视图中使用<s:fielderror/>标签即可输入校验失败的提示信息。
User.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package models; import java.util.Date; import com.opensymphony.xwork2.validator.annotations.RegexFieldValidator; import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator; public class User { private String username; private String password; private Date birth; public String getUsername() { return username; } // 基于注解的输入校验 @RequiredStringValidator(key = "username.requried", message = "") @RegexFieldValidator(regex = "\w{4,25}", key = "username.regex", message = "") public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } @Override public int hashCode() { // TODO Auto-generated method stub return getUsername().hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj != null && obj.getClass() == User.class) { User objUser = (User) obj; if (objUser.getUsername().equals(this.getUsername())) { return true; } } return false; } }
login.jsp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title><s:text name="login page"></s:text></title> </head> <body> <s:form action="login.action" validate="true"> <s:textfield name="user.username" key="username" /> <s:password name="user.password" key="password" /> <s:textfield name="user.birth" key="birth" /> <s:submit value="login" /> </s:form> </body> </html>
LoginAction.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package actions; import models.User; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String execute() throws Exception { if (getUser().getUsername().equals("yangys") && getUser().getPassword().equals("666666")) { return SUCCESS; } return ERROR; } }
Struts2的校验文件规则为:每个Action都有一个校验文件,该文件的文件名应该遵守的规则<ActionClassName>-validation.xml,如果Action中有多个处理逻辑,即在struts.xml中某个Action指定了多个method属性,对应的每个method都有一个校验规则文件,命名规则为<ActionClassName>-<ActionName>-validation.xml.
LoginAction-validation.xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="GBK"?> <!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="user.username"> <field-validator type="requiredstring"> <param name="trim">true</param> <message key="user.username.requried"/> </field-validator> </field> <field name="user.password"> <field-validator type="requiredstring"> <param name="trim">true</param> <message key="user.password.requried"/> </field-validator> <field-validator type="regex"> <param name="regex"><![CDATA[(w{4,25})]]></param> <message key="user.password.regex"/> </field-validator> </field> <field name="user.birth"> <field-validator type="date"> <param name="min">1900-01-01</param> <param name="max">2016-02-14</param> <message key="user.birth.range"/> <!-- <message>生日必须在1900-01-01到2016-02-14之间</message> --> </field-validator> </field> </validators>
其中message标签内为校验失败后的提示信息,可以直接写在<message></message>标签内,也可以通过<message key=""/>从国际化资源文件中提取显示。
LoginAction_zh_CN.properties(native2ascii处理过)
user.username.requried=u5FC5u987Bu8F93u5165u7528u6237u540D user.password.requried=u5FC5u987Bu8F93u5165u5BC6u7801 user.password.regex=u5BC6u7801u5FC5u987Bu662Fu5B57u6BCDu6216u6570u5B57uFF0Cu957Fu5EA6u57284u523025u4E4Bu95F4 user.birth.range=u751Fu65E5u5FC5u987Bu5728${min}u548C${max}u4E4Bu95F4
二、将输入页面的表单元素改为使用Struts2标签,并将<s:form.../>元素增加validate="true"即可实现客户端校验。
客户端校验只支持如下几种校验器:
- required(必填校验器)
- requiredstring(必填字符串校验器)
- stringlength(字符串长度校验器)
- regex(表达式校验器)
- email(邮件校验器)
- url(网址校验器)
- int(整数校验器)
- double(双精度数校验器)
使用客户端校验时应注意:
- <s:form.../>元素有一个theme属性,不能将该属性指定为simple。
- 浏览着不能直接访问启用客户端校验的表单,否则会引发异常。
- 如果客户端校验希望输出国际化提示信息,那就需要使用全局国际化资源文件,不能使用Action范围的国际化资源文件。
- 启用客户端校验的表单页面的action和namespace要分开写。
三、无论服务器端校验还是客户端校验,校验配置文件都有两种风格的写法。
1.字段风格
<validators> <field name="字段名"> <field-validator type="校验类型"> <param name="参数名">参数值</param> <message>校验失败提示信息</message> </field-validator> </field> </validators>
2.非字段风格
<validators> <validator type="校验类型"> <param name="fieldName">需校验的字段名</param> <param name="参数名">参数值</param> <message>校验失败提示信息</message> </validator> </validators>
两种风格写法效果一样,但是一般推荐字段风格写法,逻辑清晰,易读。
三、短路校验器的概念
配置文件中对同一字段的多种校验如触发后默认全部显示校验失败提示信息,如果在某个校验标签<validator.../>或<field-validator.../>中增加short-vircuit="true"即可实现短路校验,即该校验条件失败后,此字段位于该校验器后面的校验将不再校验。那么就不得不将Struts2的校验文件搜索规则即校验规则做一下介绍。
如果Action之间存在继承关系,则搜索规则如下:
- SuperActionClassName-validation.xml
- SuperActionClassName-SuperActionName-validation.xml
- ActionClassName-validation.xml
- ActionClassName-ActionName-validation.xml
注意:这种搜索与Struts2其它配置文件搜索不同,即使找到第一个校验规则,系统还是会继续搜索,不管有没有或者是否找到,都会按顺序继续搜索,并且校验规则是这四份规则文件里的总和,如果有冲突,则后面的文件有效。在同一个文件中,非字段风格校验器优于字段风格校验器,同类型按顺序执行
短路原则如下:
- 所有非字段校验器是最优先执行,如果某个非字段校验器校验失败了,则该字段上所有字段校验器都不会获得校验的机会。
- 非字段校验器的校验失败,不会阻止其它非字段校验的执行。
- 如果一个字段校验器失败后,则该字段校验器下且排在该校验失败的校验器之后的其它字段校验器不会获得校验机会。
- 字段校验器永远不会阻止非字段校验器的执行。
四、手工校验
重写Action的validate方法即可,当然,与前面类似,对于同一个Action中不同处理逻辑的校验,Struts2允许提供validateXxx()方法对特定逻辑进行校验。其中addFieldError方法就是添加校验失败提示信息,第一个参数是fieldName,第二个参数是message。
@Override public void validate() { if (!getUser().getUsername().contains("yang")) { addFieldError("user.username", "没有包含yang"); } }