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

struts2之action生命周期,通配符,ActionSupport

程序员文章站 2022-05-28 16:52:23
...

1 action生命周期

Struts2Action的生命周期是:Struts2为每个请求都重新初始化一个Action的实例。可以稍微改造一下代码来验证一下。
HelloWorldAction加上一个public无参的构造方法,在里面输出一句话。
大家都知道,一个Java类如果没有写构造方法,那么会有一个默认的public无参的构造方法,这里只是把它明确的写出来了,因此这么做,并没有改变Action的任何功能,只是想看一下到底什么时候,Action会被初始化。示例代码如下:

public HelloWorldAction(){  
    System.out.println("HelloWorldAction被初始化");  
} 

然后在execute方法上也加入一个打印Action自己这个对象实例的语句,示例代码如下:

public String execute() throws Exception {  
    System.out.println(this);  
    this.businessExecute();  
    return "toWelcome";  
}  

注意:大家都知道在Java基础知识里面,System.out.println(this);这句话,在打印一个对象实例的时候,实际上是调用的这个类的toString方法,但是HelloWorldAction类没有实现toString方法,所以,会调用到ObjecttoString方法。ObjecttoString方法会打印出自己的全类名和Objecthashcode方法的返回值,这个hashcode方法返回一个数字,只要这个数字不同,则被打印的对象就绝不是同一个对象。
修改做完之后,重新启动Tomcat,仔细察看后台的输出信息,你会发现启动的时候,并没有打印出来那句HelloWorldAction被初始化,这说明了Action的初始化并不是在Tomcat启动的时候进行的。
接下来按照如下顺序操作:

  • 访问http://localhost:8080/helloworld/s2impl/login.jsp,在页面上填写账号和密码,然后点击提交按钮,会跳转到欢迎页面。这个时候去察看后台的输出信息,如下:
HelloWorldAction被初始化  
cn.javass.action.action.HelloWorldAction@922804  
用户输入的参数为===account=test,password=111111,submitFlag=login  
  • 接下来,按F5来刷新这个欢迎页面,点击重试按钮,这样就相当于再次访问HelloWorldAction,再察看后台的输出信息,如下:
HelloWorldAction被初始化  
cn.javass.action.action.HelloWorldAction@922804  
用户输入的参数为===account=test,password=111111,submitFlag=login  
HelloWorldAction被初始化  
cn.javass.action.action.HelloWorldAction@18e8541  
用户输入的参数为===account=test,password=111111,submitFlag=login 

HelloWorldAction被初始化这句话被打印了两次,说明HelloWorldAction对象的构造方法被调用了两次。而且两次打印的toString分别是[email protected][email protected],这说明了为两次web请求服务的HelloWorldAction对象不是同一个。

因此,Struts2中的Action在每一次web请求的时候都要新建一个实例。

2 action中使用通配符

在以前的学习中,<action>元素的配置,都是用明确的配置,其nameclass等属性都是一个明确的值。其实Struts2还支持class属性和method属性使用来自name属性的通配符。

2.1 通配符示例

2.1.1 action使用通配符

接下来看看使用通配符的示例,如果我们使用以下<action>配置:

<action name="*_*" class="cn.javass.action.action.{1}Action" method="{2}">  
     <result name="toWelcome">/s2impl/welcome.jsp</result>  
</action> 

在上面的配置中:
name属性的值中*代表长度不为0的任意字符串,因此,它可以响应的action只需要名称中间有一个下划线即可。比如页面可访问的action名称为:HelloWorld_create.actionHelloWorld _update.action等等。
name属性定义了通配符之后,class属性使用第一个通配符(使用{1}作为占位),method属性使用第二个通配符。如果使用HelloWorld_create.action作为访问的action名称的话,struts.xmlaction名称为HelloWorld_create,第一个通配符匹配HelloWorld,第二个通配符匹配create。因此,由cn.javass.action.action.HelloWorldActioncreate方法来响应。

2.1.2 result使用通配符

那么,对于<result>元素,能不能也使用<action>元素的name属性定义的通配符呢?答案是可以的,假如有如下的配置:

<action name="*_*_*_*" class="cn.javass.action.action.{1}Action" method="{2}">  
     <result name="{3}">/${folder}/{4}.jsp</result>  
</action>  

2.1.3 通配符匹配原则

在使用通配符的时候,也有可能不止一个使用通配符的<action>元素可能匹配这次URL的访问,看以下的配置文件:

<action name="HelloWorld_create" class="cn.javass.action.action.HelloWorldAction" method="create2">  
      <result name="toWelcome">/s2impl/welcome.jsp</result>  
</action>  
<action name="*_*" class="cn.javass.action.action.{1}Action" method="{2}">  
      <result name="toWelcome">/s2impl/welcome.jsp</result>  
</action>  

这时候,如果访问/helloworld/HelloWorld_create.actionStruts2首先会查找是否有精确匹配的<action>元素,这时候无论以上<action>元素以什么顺序出现,Struts2会先找到并使用精确匹配的<action>元素。但是,如果没有精确匹配的<action>元素,则Struts2会找到第一个匹配的使用通配符的<action>元素来使用。
通配符对于那些简单的CRUD的工程或软件原型来说,只要Action的包名、Action的类名、对应的方法名写的有规律的应用,能大大简化配置的工作。

3 继承ActionSupport类

Struts2中,Action可以不实现任何特殊的接口或者继承特殊的类,仅仅是一个POJOPlain Old Java Object,简单的Java对象)就可以;也可以实现Xwork2中的Action接口;但是由于XworkAction接口非常简单,为程序员提供的帮助有限,因此,在实际开发中,会更多的使用继承ActionSupport类来实现Action的方式,如下所示:

import com.opensymphony.xwork2.ActionSupport;  
public class HelloWorldAction extends ActionSupport {  
    //省略了  
}  

ActionSupport类本身实现了Action接口,所以继承ActionSupport类就相当于实现了Action接口。除此之外,ActionSupport类还实现了其它几个接口,来为程序员提供更多使用的功能,这些接口和Struts2的一些其他特性相结合,可以实现基本的数据验证功能和国际化。接口如下所示:

  • com.opensymphony.xwork2.Validateable; 提供validate()方法来为Action增加验证的功能
  • com.opensymphony.xwork2.Validateaware; 提供方法来保存和恢复action或field级的错误信息
  • com.opensymphony.xwork2.TextProvider; 提供获取本地信息文本的功能
  • com.opensymphony.xwork2.LocaleProvider;提供getLocale()方法来获取本地消息

3.1 基本的数据验证

要实现数据验证的功能,只需要在Action类中覆盖实现validate方法即可;在validate方法内部,对请求传递过来的数据进行校验,如果不满足要求,那么添加例外信息到父类用于存放例外的集合中。示例代码如下:

package cn.javass.hello.struts2impl.action;  

import com.opensymphony.xwork2.ActionSupport;
  
public class HelloWorldAction extends ActionSupport {  
    private String account;  
    private String password;  
    private String submitFlag;  
    public String execute() throws Exception {  
        this.businessExecute();  
        return "toWelcome";  
    }  
    public void validate(){  
        if(account==null || account.trim().length()==0){  
            this.addFieldError("account", "账号不可以为空");  
        }  
        if(password==null || password.trim().length()==0){  
            this.addFieldError("password", "密码不可以为空");  
        }
        if(password!=null && !"".equals(password.trim()) && password.trim().length()<6){  
            this.addFieldError("password", "密码长度至少为6位");  
        }  
    }  
    /** 
     * 示例方法,表示可以执行业务逻辑处理的方法, 
     */  
    public void businessExecute(){  
        System.out.println("用户输入的参数为==="+"account="+account+",password="+password+",submitFlag="+submitFlag);  
    }
    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getSubmitFlag() {
        return submitFlag;
    }
    public void setSubmitFlag(String submitFlag) {
        this.submitFlag = submitFlag;
    }  
    
}  

从上面的示例可以看出,在validate方法中,可以对用户请求中传递过来的数据进行验证,同一个数据可以进行多方面的验证。
如果验证结果是数据不正确,那么就使用父类提供的addFieldError方法来添加验证的错误消息。addFieldError方法有两个参数,前面的是消息的key值,后面是具体的消息。
细心的你肯定发现了,validate方法是没有返回值的,那么当验证后,如果有数据没有通过验证,该返回到什么页面呢?这就需要在struts.xml中的Action配置里面,添加一个名称为input的result配置,也就是说,如果validate方法中,有数据没有通过验证,那么会自动跳转回到该action中名称为inputresult所配置的页面。示例如下:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE struts PUBLIC  
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  
    "http://struts.apache.org/dtds/struts-2.0.dtd">  
<struts>  
    <constant name="struts.devMode" value="true" />        <!-- 设置了程序的运行模式 -->
    <constant name="struts.locale" value="zh_CN"/>         <!-- 设置程序运行所使用的locale -->
    <constant name="struts.i18n.encoding" value="utf-8"/>  <!-- 设置程序运行时用的编码方式 -->
    <!-- 正确设置后面两个参数,就可以解决Struts2的中文问题了。 -->
    
  
    <package name="helloworld"  extends="struts-default">  
        <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction">  
            <result name="toWelcome">/s2impl/welcome.jsp</result> 
             <result name="input">/s2impl/login.jsp</result>   
        </action>  
    </package>  
    
</struts> 

当输入信息不满足条件的时候,将错误信息显示在前台页面上,代码如下:

<%@ page language="java" contentType="text/html; charset=utf-8"  
    pageEncoding="utf-8"%> 
<%@ taglib prefix="s" uri="/struts-tags"%> 
<html>  
<head>  
<meta http-equiv="Content-Type" content="text/html; utf-8">  
<title>Insert title here</title>  
<style type="text/css">
ul,li {
    list-style-type:none;
    margin:0px;
    float:left;
}
</style>
</head>  
<body>  
   
<form action="/struts2Deepen2/helloworldAction.action" method="post"> 
    <input type="hidden" name="submitFlag" value="login"/>  
    <div> 
        <font color=red><s:fielderror fieldName="account"/></font>
        <br/>
          账号:<input type="text" name="account">
    </div>
    <div>
        <font color=red><s:fielderror fieldName="password"/></font>
        <br/>
            密码:<input type="password" name="password">
    </div>
    <input type="submit" value="提交">  
</form>  
  
</body>  
</html>  

JSP页面中利用<s:fielderror/>标签在相应的字段处输出错误信息。但是,在实际开发中,<s:fielderror/>它会输出全部的错误信息内容。而如果想选择性地输出指定错误信息。我们可以使用如下代码解决:

<!-- 方法一 -->
<s:fielderror>  
  <s:param>username</s:param> <!--显示指定的 username字段的 错误消息-->  
<s:fielderror/>

<!-- 方法二 -->
<s:fielderror fieldName="username"/> 
<!--显示指定的 username字段的 错误消息-->  

通过这个示例,你会发现,validate方法会先于execute方法被执行,只有validate方法执行后,又没有发现验证错误的时候,才会运行execute方法,否则会自动跳转到你所配置的input所对应的页面。

3.2 访问本地信息

在上面的示例中,你会发现在validate方法中,添加验证错误消息的时候,是采用的硬编码方式,也就是直接写死的字符串,这是很不好的:

  • 不容易修改,比如要改变消息的内容,还得重新修改和编译类;
  • 不利于国际化,如果要把中文的信息变换成英文的呢,同样要重新修改和编译类。

可以通过访问本地信息的方式,把这些错误消息放置到Action类外部的配置文件中,在Action类内部只需要按照这些消息的key值去获取消息即可。这样一来,当消息发生变化的时候,只需要修改这个消息的配置文件即可。
先来建立消息的配置文件,在Action类的路径下建立一个同名的properties文件,也就是文件名为HelloWorldAction.properties,然后在里面按照key=value的格式,添加要使用的错误消息。示例如下:

k1=\u5E10\u53F7\u4E0D\u5141\u8BB8\u4E3A\u7A7A
k2=\u5BC6\u7801\u4E0D\u5141\u8BB8\u4E3A\u7A7A
k3=\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u57286\u4F4D\u4EE5\u4E0A

可能你会觉得很奇怪,这都是些什么呀?其实是把中文的消息转换成了相应的unicode编码,比如k1后面的value值,其实就是帐号不允许为空unicode编码。只有这样,在程序里面读取到这些值的时候才会正确显示中文。有很多工具可以把中文转换成unicode编码,比如,native2ascii工具就可以实现。
Action里面,就修改validate方法,原来是直接写的中文字符串,现在应该修改成从配置文件中获取信息了,示例如下:

 public void validate(){  
        if(account==null || account.trim().length()==0){  
            this.addFieldError("account", this.getText("k1"));  
        }  
        if(password==null || password.trim().length()==0){  
            this.addFieldError("password", this.getText("k2"));  
        }
        if(password!=null && !"".equals(password.trim()) && password.trim().length()<6){  
            this.addFieldError("password", this.getText("k3"));  
        }  
    }  
相关标签: struts2 struts