欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Struts 2 数据校验功能及校验问题的解决方案

程序员文章站 2024-03-13 20:19:46
通过继承actionsupport类来完成action开发,actionsupport类不仅对action接口进行简单实现, 同时增加了验证、本地化等支持 。真实开发中自定...

通过继承actionsupport类来完成action开发,actionsupport类不仅对action接口进行简单实现, 同时增加了验证、本地化等支持 。真实开发中自定义action都需要继承该类。对用户登录添加表单验证功能

actionsupport类的作用:

struts2不要求我们自己设计的action类继承任何的struts基类或struts接口,但是我们为了方便实现我们自己的action,大多数情况下都会继承com.opensymphony.xwork2.actionsupport类,并重写此类里的public string execute() throws exception方法。因为此类中实现了很多的实用借口,提供了很多默认方法,这些默认方法包括国际化信息的方法、默认的处理用户请求的方法等,这样可以大大的简化acion的开发。 struts2中通常直接使用action来封装http请求参数,因此,action类里还应该包含与请求参数对应的属性,并且为属性提供对应的getter和setter方法。

那么action 接口和 actionsupport类的区别是什么呢?

action接口有:

public static final string success = "success";
public static final string none = "none";
public static final string error = "error";
public static final string login = "login";
public string execute() throws exception;

可以看到有五个静态常量和返回类型为string 的execute()

而actionsupport这个工具类在实现了action接口的基础上还定义了一个validate()方法,重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该action时配置input属性。

另外,actionsupport还提供了一个gettext(string key)方法还实现国际化,该方法从资源文件上获取国际化信息.

这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化。

actionsupport类有(源码):

public class actionsupport implements action, validateable, validationaware, textprovider, localeprovider, serializable {
protected static logger log = loggerfactory.getlogger(actionsupport.class);
private final validationawaresupport validationaware = new validationawaresupport();
private transient textprovider textprovider;
private container container;
public void setactionerrors(collection<string> errormessages) {
validationaware.setactionerrors(errormessages);
}
public collection<string> getactionerrors() {
return validationaware.getactionerrors();
}
public void setactionmessages(collection<string> messages) {
validationaware.setactionmessages(messages);
}
public collection<string> getactionmessages() {
return validationaware.getactionmessages();
}
@deprecated
public collection<string> geterrormessages() {
return getactionerrors();
}
@deprecated
public map<string, list<string>> geterrors() {
return getfielderrors();
}
public void setfielderrors(map<string, list<string>> errormap) {
validationaware.setfielderrors(errormap);
}
public map<string, list<string>> getfielderrors() {
return validationaware.getfielderrors();
}
public locale getlocale() {
actioncontext ctx = actioncontext.getcontext();
if (ctx != null) {
return ctx.getlocale();
} else {
if (log.isdebugenabled()) {
log.debug("action context not initialized");
}
return null;
}
}
public boolean haskey(string key) {
return gettextprovider().haskey(key);
}
public string gettext(string atextname) {
return gettextprovider().gettext(atextname);
}
public string gettext(string atextname, string defaultvalue) {
return gettextprovider().gettext(atextname, defaultvalue);
}
public string gettext(string atextname, string defaultvalue, string obj) {
return gettextprovider().gettext(atextname, defaultvalue, obj);
}
public string gettext(string atextname, list<?> args) {
return gettextprovider().gettext(atextname, args);
}
public string gettext(string key, string[] args) {
return gettextprovider().gettext(key, args);
}
public string gettext(string atextname, string defaultvalue, list<?> args) {
return gettextprovider().gettext(atextname, defaultvalue, args);
}
public string gettext(string key, string defaultvalue, string[] args) {
return gettextprovider().gettext(key, defaultvalue, args);
}
public string gettext(string key, string defaultvalue, list<?> args, valuestack stack) {
return gettextprovider().gettext(key, defaultvalue, args, stack);
}
public string gettext(string key, string defaultvalue, string[] args, valuestack stack) {
return gettextprovider().gettext(key, defaultvalue, args, stack);
}
public string getformatted(string key, string expr) {
map<string, object> conversionerrors = actioncontext.getcontext().getconversionerrors();
if (conversionerrors.containskey(expr)) {
string[] vals = (string[]) conversionerrors.get(expr);
return vals[0];
} else {
final valuestack valuestack = actioncontext.getcontext().getvaluestack();
final object val = valuestack.findvalue(expr);
return gettext(key, arrays.aslist(val));
}
}
public resourcebundle gettexts() {
return gettextprovider().gettexts();
}
public resourcebundle gettexts(string abundlename) {
return gettextprovider().gettexts(abundlename);
}
public void addactionerror(string anerrormessage) {
validationaware.addactionerror(anerrormessage);
}
public void addactionmessage(string amessage) {
validationaware.addactionmessage(amessage);
}
public void addfielderror(string fieldname, string errormessage) {
validationaware.addfielderror(fieldname, errormessage);
}
public string input() throws exception {
return input;
}
public string dodefault() throws exception {
return success;
}
public string execute() throws exception {
return success;
}
public boolean hasactionerrors() {
return validationaware.hasactionerrors();
}
public boolean hasactionmessages() {
return validationaware.hasactionmessages();
}
public boolean haserrors() {
return validationaware.haserrors();
}
public boolean hasfielderrors() {
return validationaware.hasfielderrors();
}
public void clearfielderrors() {
validationaware.clearfielderrors();
}
public void clearactionerrors() {
validationaware.clearactionerrors();
}
public void clearmessages() {
validationaware.clearmessages();
}
public void clearerrors() {
validationaware.clearerrors();
}
public void clearerrorsandmessages() {
validationaware.clearerrorsandmessages();
}
public void validate() {
}
@override
public object clone() throws clonenotsupportedexception {
return super.clone();
}
public void pause(string result) {
}
private textprovider gettextprovider() {
if (textprovider == null) {
textproviderfactory tpf = new textproviderfactory();
if (container != null) {
container.inject(tpf);
}
textprovider = tpf.createinstance(getclass(), this);
}
return textprovider;
}
@inject
public void setcontainer(container container) {
this.container = container;
}

可以看到里面有很多的方法,但我们很明显看到有一个我们很了解的,validate(),数据校验的方法。通过这个方法,我们可以登录时,用户名和密码为空的提示,或其他··

现在举一个简单的例子:当用户名和密码为空,给客户一个友好提示。

下面通过两种方式来阐述struts 2的数据校验功能。

1. 编码方式校验

1) action一定要继承自actionsupport

2) 针对某个要进行校验的请求处理方法编写一个 public void validatexxx()方法,在方法内部进行表单数据校验.

3) 也可针对所有的请求处理方法编写public void validate()方法。

4) 在校验方法中,可以通过addfielderror()方法来添加字段校验错误消息。

5) 当校验失败时,struts框架会自动跳转到name为input的result页面。在校验失败页面中,可以使用<s:fielderror/>来显示错误消息
6) 简单,灵活。但重用性不高

重写validate方法

1.我们编写的action一般继承与actionsupport,而actionsupport不仅实现了action接口,还实现了validatable接口,提供了数据校验功能。在validatable接口中定义一个validate方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到actionsupport类的fielderror域中,然后通过ognl表达式输出。

下面是用户登录校验界面:

<body>
<%--输出校验信息--%>
<%--想要单个提示 <s:fielderror fieldname="uname"/>--%>
<%--<s:property value=""/>
--%><div style="color:red"><s:fielderror/></div> 
<s:form name="form1" namespace="/" method="post" action="loginvalidateaction">
<s:div>请输入用户名:<s:textfield name="user.uname" ></s:textfield></s:div>
<s:div>请输入密码:<s:password name="user.upwd" ></s:password></s:div>
<s:submit value="登录"></s:submit>
</s:form>
<%--debug --%>
<s:debug></s:debug>
</body>

用户输入数据后,提交到loginvalidateaction 中:

public class loginvalidateaction extends actionsupport implements action {
public user user;
public map<string, object> map;
//验证的方法,会对所有的action起作用
@override 
public void validate() {
if(user.getuname().length()==0){
addfielderror("uname", "用户名不能为空!");

}
if(user.getupwd().length()==0){
addfielderror("upwd", "密码不能为空!");
} 

} 
//处理业务的方法
public string execute() throws exception {
system.out.println(user.getuname());
if(user.getuname().equals("admin")&&user.getupwd().equals("admin")){
//让struts2注入 map集合
map.put("uname", user.getuname());
//如果登录成功,返回“ success”
return success;
}
else{
//登录失败,返回 error
return input; //此处一定是 input
}
}
/**
* @return the user
*/
public user getuser() {
return user;
}
/**
* @param user the user to set
*/
public void setuser(user user) {
this.user = user;
}

上面的loginvalidateaction类重写了validate方法,该方法会在执行excute方法之前执行,如果执行该方法之后,action类的filederror中包含了数据校验错误,请求将被转发到input逻辑视图。

struts.xml配置如下:

<!-- 数据校验 -->
<action name="loginvalidateaction" class="cn.struts2.action.loginvalidateaction">
<!-- 结果为“success”时,跳转至success.jsp页面 -->
<result name="success">success.jsp</result>
<!-- 结果为"error"时,跳转至fail.jsp页面 或 还在登录界面 login.jsp-->
<result name="input">loginvalidateaction.jsp</result>
<result name="login">fail.jsp</result> 
<result name="error">fail.jsp</result> 
</action>

在客户端的效果:

Struts 2 数据校验功能及校验问题的解决方案

但是大家注意没有呢,当提示错误的时候不太是我们想要的的效果显示。

Struts 2 数据校验功能及校验问题的解决方案

这个不是我们所想要的,那么我们怎么改呢?其实这主要显示的struts2主题样式导致的,

再来看看:

Struts 2 数据校验功能及校验问题的解决方案

它自动给我们添加了样式。struts2提供了三种主题,ajax, simple, xhtml,它默认的是xhtml主题,当然你可以写任意个你自己的主题,我们称之为自定义主题。可以通过设置解决以上问题

有两种方法可以解决:

1.简单的方法(也很实用,针对所有struts2标签),在struts.xml中,加上下一行代码就可以了。

<constant name="struts.ui.theme" value="simple" />

代表所有的页面采用的都是 simple主题了,这时它输出的页面,不回添加任何多余的代码,比如 table tr td 等,我们就可以像其他编辑页面的方式编辑页面的风格。

现在再来看看,错误的提示格式

Struts 2 数据校验功能及校验问题的解决方案

我们可以通过设置这样一个标签:

<s:property value="errors.uname[0]"/>

把这个标签注释掉:

<div style="color:red"><s:fielderror/></div> 

但我们设置成 这样时,会出现这样的效果。

Struts 2 数据校验功能及校验问题的解决方案

这种效果就有点想我们平常输入错误时的那个提示了,还有其他属性值,这里就不用一一列举了。

使用struts2的校验框架

xml配置方式校验。

在编码方式之前被执行。

1) 针对要校验的action类,在同包下编写一个名为:action类名-validation.xml校验规则文件。

2) 在校验规则文件中添加校验规则:具体的校验器名,参数可参看struts2的reference或struts2的api。

a) field校验:针对action类中每个非自定义类型的field进行校验的规则。

<field name="要校验的field名">
<field-validator type="校验规则器名" short-circuit="是否要短路径校验(默认是false)">
<param name="校验器要使用的参数名">值</param>
<message>校验失败时的提示消息</message>
</field-validator>
<!-- 还可添加其它的校验规则 -->
</field>

b) 非field校验:针对action类的某些field使用ognl表达进行组合校验。

<validator type="fieldexpression">
<param name="fieldname">pwd</param>
<param name="fieldname">pwd2</param>
<param name="expression"><![cdata[pwd==pwd2]]></param><!-- ognl表达式 -->
<message>确认密码和密码输入不一致</message>
</validator>

c) visitor校验:主要是用来校验action类中的自定义类型field。(针对使用模型驱动方式时)

i) 在action类的的校验规则文件中针对自定义类型field使用visitor校验规则。

<!-- 针对自定义field使用visitor校验 -->
<field name="user">
<field-validator type="required" short-circuit="true">
<message>用户的信息必填</message><!-- 消息前缀 -->
</field-validator>
<field-validator type="visitor"><!-- 指定为visitor校验规则 -->
<param name="context">usercontext</param><!-- 指定本visitor校验的上下文名 -->
<param name="appendprefix">true</param><!-- 是否要添加校验失败消息的前缀 -->
<message>用户的</message><!-- 消息前缀 -->
</field-validator>
</field>

ii) 针对visitor的field编写一个校验规则文件.文件名为: visitor字段类型名[-visitor校验的上下文名]-validation.xml. 例如: 本例中的文件名为user-usercontext-validation.xml

注意: 此文件要存放到visitor字段类型所在的包下.

iii) 在visitor的field校验规则文件中针对要校验的field添加校验规则.

  我们还可以不重写validate方法,而通过增加校验配置文件来进行数据校验。这个校验配置文件通过使用struts2已有的校验器来完成对表单域的校验,下面以requiredstring校验器为例,这个校验器是一个必填校验器,指定某个表单域必须输入。

下面是这个校验配置文件loginvalidateaction-validation.xml的写法:

<?xml version="1.0" encoding="utf-8"?>
<!doctype validators public "-//apache struts//xwork validator 1.0.2//en" 
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
<field name="uname">
<field-validator type="requiredstring">
<message>用户名不能为空</message>
</field-validator>
</field>
<field name="upwd">
<field-validator type="requiredstring">
<message>密码不能为空</message>
</field-validator>
<field-validator type="stringlength">
<param name="maxlength">18</param>
<param name="minlength">6</param>
<message>密码长度应该在${minlength}--${maxlength}位之间</message>
</field-validator>
</field>
</validators>

注意:这个校验配置文件必须遵守下面两个规则:

  1、该文件命运格式必须是action类名-validation.xml,例如本例中该文件名为:loginvalidateaction-validation.xml

  2、该文件必须与action类的class文件位于同一路径下,本例中文件位于

Struts 2 数据校验功能及校验问题的解决方案

loginvalidateaction类的代码还是一样:

public class loginvalidateaction extends actionsupport implements action {
public user user;
public map<string, object> map;
//验证的方法,会对所有的action起作用
@override 
public void validate() {
if(user.getuname().length()==0){
addfielderror("uname", "用户名不能为空!");
}
if(user.getupwd().length()==0){
addfielderror("upwd", "密码不能为空!");
} 
} 
//处理业务的方法
public string execute() throws exception {
system.out.println(user.getuname());
if(user.getuname().equals("admin")&&user.getupwd().equals("admin")){
//让struts2注入 map集合
map.put("uname", user.getuname());
//如果登录成功,返回“ success”
return success;
}
else{
//登录失败,返回 error
return input; //此处一定是 input
}
}
/**
* @return the user
*/
public user getuser() {
return user;
}
/**
* @param user the user to set
*/
public void setuser(user user) {
this.user = user;
}

以上所述是小编给大家介绍的struts 2 数据校验功能及校验问题的解决方案,希望对大家有所帮助