通过继承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();}@Deprecatedpublic Collection<String> getErrorMessages() {return getActionErrors();}@Deprecatedpublic 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() {}@Overridepublic 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;}@Injectpublic 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{//登录失败,返回 errorreturn 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>
在客户端的效果:
但是大家注意没有呢,当提示错误的时候不太是我们想要的的效果显示。
这个不是我们所想要的,那么我们怎么改呢?其实这主要显示的struts2主题样式导致的,
再来看看:
它自动给我们添加了样式。struts2提供了三种主题,ajax, simple, xhtml,它默认的是xhtml主题,当然你可以写任意个你自己的主题,我们称之为自定义主题。可以通过设置解决以上问题
有两种方法可以解决:
1.简单的方法(也很实用,针对所有struts2标签),在Struts.xml中,加上下一行代码就可以了。
<constant name="struts.ui.theme" value="simple" />
代表所有的页面采用的都是 simple主题了,这时它输出的页面,不回添加任何多余的代码,比如 table tr td 等,我们就可以像其他编辑页面的方式编辑页面的风格。
现在再来看看,错误的提示格式
我们可以通过设置这样一个标签:
<s:property value="errors.uname[0]"/>
把这个标签注释掉:
<div style="color:red"><s:fielderror/></div>
但我们设置成 这样时,会出现这样的效果。
这种效果就有点想我们平常输入错误时的那个提示了,还有其他属性值,这里就不用一一列举了。
使用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文件位于同一路径下,本例中文件位于
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{//登录失败,返回 errorreturn 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 数据校验功能及校验问题的解决方案,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!
新闻热点
疑难解答