前言
在struts 2中,action是其核心功能,使用struts 2框架,主要的开发都是围绕action进行的,我们编写的action通常需要实现com.opensymphony.xwork2.Action接口,需要实现的方法是execute方法,但是在实际的开发中,编写的action也可以不必实现action接口,而是直接创建一个普通Java类,并添加execute方法就可以public String execute(){return "success";}
。还有一种方式是集成ActionSupport类,该类位于com.opensymphony.xwork2下,其实现了Action接口的execute方法。以上方式后面两种方式是最常用的。
围绕action,分为以下内容:
action属性
动态方法调用
默认action配置
通配符映射
action属性
action中有一个映射框架,主要是讲url映射到对应的action类,action的配置主要在struts.xml文件中编写,所有action的属性如下:
属性 | 是否必需 | 说明 |
---|---|---|
name | 是 | action的名字,用于匹配请求的url |
class | 否 | Action实现类的完整类名 |
method | 否 | 调用Action实现类中指定的方法 |
converter | 否 | 应用于action类型转换器的完整类名 |
需要注意的是,action的name属性一般不允许出现.
或者/
或者-
的。但是下划线是可以的。另外,如果在配置文件中没有为action配置class完整类名,那么框架会调用ActionSupport类中execute方法,该方法的实现仅仅是返回一个SUCCESS
,相当于是转发了,所以这点实际上与struts 1中的ActionForward的作用是一致的。所以我们可以这个特性,实现仅仅需要完成转发功能的action,这点比使用ActionForward方便多了。
下面重点对method属性进行说明
通常action的作用是完成一个功能点,但是例如CRUD这样的操作使用四个action类显然不划算,在struts 2中可以将这四个功能映射到一个action中进行处理,这里就需要使用method属性了。具体的做法是:在struts.xml配置文件中为一个action使用method属性和name属性指定不同别名,就可以实现CRUD映射到同一个action了。
比如有一个用户管理模块,需要对用户进行增加、修改、删除和查询,我们首先创建UserAction类,如下:
package action;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport{
private static final long serialVersionUID = 1L;
//查询所有用户
public String list() throws Exception {
return SUCCESS;
}
//修改用户信息
public String update(){
return SUCCESS;
}
//删除用户信息
public String delete(){
return SUCCESS;
}
//添加用户
public String add(){
return SUCCESS;
}
}
要注意的是,在action中并非一定需要execute方法,也可以指定自己需要的方法,action编写完毕后,就需要在struts.xml文件中编写配置文件了,如下:
<package name="user" namespace="/user" extends="struts-default">
<action name="list" class="action.UserAction" method="list">
<result>/list.jsp</result>
</action>
<action name="add" class="action.UserAction" method="add">
<result>/add.jsp</result>
</action>
<action name="delete" class="action.UserAction" method="delete">
<result>/delete.jsp</result>
</action>
<action name="update" class="action.UserAction" method="update">
<result>/update.jsp</result>
</action>
</package>
这里,通过使用别名的方式把多个业务功能映射到一个action中的不同方法,这是方式虽然有点笨拙,但是逻辑清晰,一目了然,但是在框架中国还提供了不同编写配置文件也能映射到action中的不同方法,这就是下面要讲的动态方法调用(Dynamic Method Invocation ,简称DMI)。
动态方法调用
所谓动态方法调用是指在action的名字中使用感叹号!
标识需要调用的方法名,调用格式是actionName!actionMethod.action
,通过这种方式就可以实方法的动态调用了,下面对这一结论做一个测试,首先把配置文件做一点小的修改:
<package name="user" namespace="/user" extends="struts-default">
<action name="userAction" class="action.UserAction">
<result name="success">/list.jsp</result>
<result name="update">/update.jsp</result>
<result name="add">/add.jsp</result>
</action>
<!-- <action name="add" class="action.UserAction" method="add">
<result>/add.jsp</result>
</action>
<action name="delete" class="action.UserAction" method="delete">
<result>/delete.jsp</result>
</action>
<action name="update" class="action.UserAction" method="update">
<result>/update.jsp</result>
</action> -->
</package>
然后对UserAction修改如下:
//查询所有用户
public String list() throws Exception {
return SUCCESS;
}
//修改用户信息
public String update(){
return "update";
}
//删除用户信息
public String delete(){
return null;
}
//添加用户
public String add(){
return "add";
}
下面是测试结果:
需要注意的是,尽管DMI给开发带来了诸多遍历,但是存在安全隐患,由于可以通过url直接放完action中任意方法,所以很容易受到恶意攻击。在这种情况下需要使用安全控制机制。
关于method属性与DMI应该使用哪种方式的问题,可以简要总结如下:如果一个action中的不同方法使用相同的配置(相同的result和拦截器配置),那么可以使用DMI;否则使用method属性在struts.xml文件中进行配置。
默认的action
默认的action是在访问一个不存在的action的时候访问的action,配置默认action,只需要在package中添加如下配置:
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="hello"/>
<!-- HelloWorld演示程序 -->
<action name="hello" class="example.HelloWorld">
<result>/index.jsp</result>
</action>
</package>
这里的action配置在package下面,需要注意的是:每个package可以一个默认的action,但是每个namespace应该只有一个默认的action,因为使用多个的话,框架不知道访问默认的action。
通配符映射
使用通配符映射的方式可以大大减少action的数量,所谓通配符就是使用*,用于匹配0个或多个字符。在action的配置中,可以为name属性使用*来匹配任意的字符。比如下面的配置:
<action name="edit*" class="action.Edit{1}Action">
<result>/{1}.jsp</result>
</action>
{1}会被name属性中的*的内容填充,比如在浏览器中访问/editUser,会映射到action.EditUserAction类,返回到User.jsp页面中。其中的{1}实际上就是作为占位符的,大括号的值可以是0-9,其中{0}代表整个请求URL。比如下面的配置:
<action name="*_*" class="action.{1}Action" method="{2}">
<result>/{1}_{2}.jsp</result>
</action>
当访问User_list的时候,会映射到UserAction类,访问UserAction中的list方法,返回的结果页面是User_list.jsp。