package 节点
<package name="user" namespace="/user" extends="struts-default" abstract="false">
</package>
属性名称
|
是否必须
|
属性描述
|
name
|
是
|
指定 package 的名字,这个名字在工程内必须是唯一的
|
extends
|
是
|
指明要扩展的包的名字。如 extends="struts-default"
|
abstract
|
否
|
指明 package 是否是抽象的。默认是 false。
抽象的 package 不能拥有任何的 action,只能作为父包被继承
|
namespace
|
否
|
命名空间。默认值是 ""。
若指定了该属性的值,那么,访问该 package 下的所有 Action 都需要带上这个命名空间
|
action 节点
<action name="domain" class="fan.tutorial.action.DomainAction" method="launch">
<result>/domain.jsp</result>
</action>
属性名称
|
是否必须
|
属性描述
|
name
|
是
|
指定 Action 的名字
|
class
|
否
|
指定 Action 的完整类路径。
默认是 class = "com.opensymphony.xwork2.ActionSupport"
|
method
|
否
|
指定 Action 执行时调用的方法。默认是 method = "execute"
|
result 节点
<result name="success" type="dispatcher">/success.jsp</result>
属性名称
|
是否必须
|
属性描述
|
name
|
否
|
指定视图结果的名称,用于根据不同的逻辑名称匹配不同的视图结果页面。
默认值 name = "success"
|
type
|
否
|
指定视图结果类型,用于根据不同的类型 ( 例如转发或重定向等 ) 跳转到指定的视图页面
默认值 type = "dispatcher"
|
result 节点的结果类型
结果类型名称
|
结果类型描述
|
chain
|
用于将多个 Action 链接起来执行,来共同完成一次请求 ( 数据可以在多个 Action 中共享 )
|
dispatcher
|
转发。这是默认的结果类型。
本质是通过 Servlet API 的 RequestDispatcher.forward() 来完成
|
redirect
|
重定向。
本质是通过 Servlet API 的 HttpServletResponse.sendRedirect() 来完成。
重定向是服务器向客户端浏览器发回302状态码以及重定向地址 Location,浏览器接收后将重新发起一次新的 HTTP 请求。前一次 HTTP 请求所包含的数据是不能被后一次 HTTP 请求所共享的。
|
redirectAction
|
与 redirect 结果类型相似,只是它专门用来映射到另外的一个 Action 动作
|
stream
|
向客户端浏览器发送 InputStream 流对象,通常可以用来作为文件下载的一种手段
|
配置全局结果
<package name="basic" extends="struts-default">
<global-results>
<result name="error">/pages/global/error.jsp</result>
<result name="success">/pages/global/success.jsp</result>
</global-results>
</package>
全局结果是在 package 中定义的,全局结果定义完成后,该 package 下的所有 action 都能来使用它们。
其余 package 如果也想来使用这些结果,那么需要通过 extends 来继承该 package 才能使用。
配置默认 action
<package name="default" extends="struts-default">
<default-action-ref name="invalidAction" />
<action name="invalidAction">
<result type="redirect">/index.jsp</result>
</action>
</package>
在没有配置默认 action 之前,若访问一个不存在的 action,那么服务器端将报出错误,客户端浏览器得到的是 HTTP ERROR: 404 的错误提示页面。
在配置好默认的 action 之后,若访问一个不存在的 action,那么这个默认的 action 将被执行并将执行完成的结果视图发回给客户端。
另外,<default-action-ref> 节点需要在 <action> 节点之前声明,否则在启动时将报出错误。
package 的运用
<struts>
<package name="first" namespace="/first" extends="struts-default">
<action name="access">
<result>/pages/package/first.jsp</result>
</action>
</package>
<package name="second" extends="struts-default">
<action name="access">
<result>/pages/package/second.jsp</result>
</action>
</package>
<package name="third" extends="struts-default" abstract="true">
<global-results>
<result>/pages/package/third.jsp</result>
</global-results>
</package>
<package name="fourth" namespace="/fourth" extends="third">
<action name="access" />
</package>
</struts>
这里总共配置了4个 package,其中一个是抽象的,其余3个 package 中分别定义了一个 action,action 节点的 class 和 method 属性不指定 ( 使用默认 ),并且 action 的 name 属性都指定为 access ( 极端示例,切勿效仿 ☺ )。
访问 first package 下的 action 的方式为:/first/access.action
访问 second package 下的 action 的方式为:/access.action 或 /xxx/access.action 或 /xxx/yyy/access.action ( xxx、yyy 代表任意串 )
访问 fourth package 下的 action 的方式为:/fourth/access.action
不知道你注意了没有,这里的 second package 的命名空间是没有指定的,也就是说它能捕获所有的命名空间串。那好,现在问题来了,当访问 /first/access.action 的时候,得到的视图为什么是 first.jsp 而不是 second.jsp 呢?这是不是跟 package 节点在配置文件中出现的先后顺序有关系呢?( 有过 WEB 开发的都知道,配置文件中节点的先后顺序有时候是很重要的 )。这个很明显,当访问 /fourth/access.action 的时候,得到的是 third.jsp 而不是 second.jsp。事实上,Struts2 是首先根据 URL 中的命名空间去相对应的 package 下查找 action,如果查找不到,才到默认的命名空间的 package 中去查找 action,如果有多个 package 都使用了默认的命名空间,这个时候才是根据 package 出现的先后顺序来查找 action 的。
action 的运用
package fan.tutorial.action;
import com.opensymphony.xwork2.Action;
public class ExampleAction implements Action {
public String execute() {
System.out.println("--- ExampleAction[execute] ---");
return SUCCESS;
}
public String launch() {
System.out.println("--- ExampleAction[launch] ---");
return "launch";
}
public String load() {
System.out.println("--- ExampleAction[load] ---");
return "load";
}
}
<struts>
<package name="simple" namespace="/simple" extends="struts-default">
<action name="example" class="fan.tutorial.action.ExampleAction">
<result name="load">/pages/example/load.jsp</result>
<result name="launch">/pages/example/launch.jsp</result>
<result name="success">/pages/example/success.jsp</result>
</action>
<action name="example2" class="fan.tutorial.action.ExampleAction" method="load">
<result name="load">/pages/example/load.jsp</result>
<result name="launch">/pages/example/launch.jsp</result>
<result name="success">/pages/example/success.jsp</result>
</action>
</package>
</struts>
这里配置了2个 action,不同的是,第2个 action 使用了 method 属性,那么当访问 /simple/example2.action 的时候,由 method 指定的方法将被执行。
而第1个 action 没有指定 method 属性,那么当访问 /simple/example.action 的时候,默认执行的是 execute 方法。
action 动态方法的调用
Struts2 Action 动态方法调用非常简单,就是在 action 名称后面使用 "!" 来链接需要执行的方法的名称就可以了。以上面的配置为例,如想调用 ExampleAction 的 launch 方法,只需要访问 /simple/example!launch.action 就可以了。
使用通配符映射 action
<struts>
<package name="wildcard" namespace="/wildcard" extends="struts-default">
<action name="*_*" class="fan.tutorial.action.{1}Action" method="{2}">
<result name="{2}">/pages/example/{2}.jsp</result>
</action>
</package>
</struts>
通配符 "*" 匹配的值用符号 {n} 来访问得到。第1个 "*" 用 {1} 来访问,其余的以此类推。
使用通配符后,如果想执行 ExampleAction 的 launch 方法,访问 /wildcat/Example_launch.action 即可。
需要注意的是,这里的 Example 必须是要大写字母开头的,因为它是用来定位我们的 Action 类路径的,它必须与你的类名称保持高度一致。
dispatcher 结果类型的运用
package fan.tutorial.action;
import com.opensymphony.xwork2.Action;
public class LoginAction implements Action {
private String username;
private String password;
public String execute() {
System.out.println("**************************");
System.out.println("LoginAction: ");
System.out.println("username = " + username + ", password = " + password);
System.out.println("**************************");
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package fan.tutorial.action;
import com.opensymphony.xwork2.Action;
public class ManagerAction implements Action {
private String username;
private String password;
public String execute() {
System.out.println("**************************");
System.out.println("ManagerAction: ");
System.out.println("username = " + username + ", password = " + password);
System.out.println("**************************");
return SUCCESS;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<struts>
<package name="result" namespace="/result" extends="struts-default">
<action name="login" class="fan.tutorial.action.LoginAction">
<result type="dispatcher">/pages/result/login.jsp</result>
</action>
<action name="manager" class="fan.tutorial.action.ManagerAction">
<result type="dispatcher">/pages/result/manager.jsp</result>
</action>
</package>
</struts>
<html>
<h1>${username}, ${password}</h1>
</html>
dispatcher 是默认的结果类型,也是最常用的结果类型。
当访问 /result/login.action?username=u&password=p 的时候,在 login.jsp 中输出相应的信息,这个比较简单,就不多说了。
chain 结果类型的运用
<struts>
<package name="result" namespace="/result" extends="struts-default">
<action name="login" class="fan.tutorial.action.LoginAction">
<result type="chain">manager</result>
</action>
<action name="manager" class="fan.tutorial.action.ManagerAction">
<result type="dispatcher">/pages/result/manager.jsp</result>
</action>
</package>
</struts>
访问 /result/login.action?username=u&password=p,在控制台可以看到,LoginAction 和 ManagerAction 的 execute 方法依次被执行并打印出相应的信息,请求中携带的数据在两个 Action 中被共享,最终在 manager.jsp 中显示相应的信息。
需要注意的是,在 chain 中不能为 action 指定扩展名,如 manager.action 等是不正确的。
redirect 结果类型的运用
<struts>
<package name="result" namespace="/result" extends="struts-default">
<action name="login" class="fan.tutorial.action.LoginAction">
<result type="redirect">/pages/result/login.jsp</result>
</action>
<action name="manager" class="fan.tutorial.action.ManagerAction">
<result type="redirect">
/pages/result/manager.jsp?username=${username}&password=${password}
</result>
</action>
</package>
</struts>
当访问 /result/login.action?username=u&password=p 的时候,控制台打印出了接收到的参数的信息,但是 login.jsp 页面中不会显示参数信息,这是由于重定向引起的,上面已经有提及到,这里就不再赘述。
若想使用 redirect 又不想丢失一些你感兴趣的数据,那么,可以采用像第2个 action 的配置方式,在重定向的时候,重新把一些必要的信息传回去就可以了。
需要注意的是,若有多个参数,不能像平常那样使用 "&" 来连接,而是需要使用它的实体名称 ( & ) 来连接。否则,工程在启动的时候是会报出错误的。
redirectAction 结果类型的运用
<struts>
<package name="result" namespace="/result" extends="struts-default">
<action name="login" class="fan.tutorial.action.LoginAction">
<result type="redirectAction">manager</result>
</action>
<action name="login_alias" class="fan.tutorial.action.LoginAction">
<result type="redirectAction">
manager?username=${username}&password=${password}
</result>
</action>
<action name="manager" class="fan.tutorial.action.ManagerAction">
<result type="dispatcher">/pages/result/manager.jsp</result>
</action>
</package>
</struts>
当访问 /result/login.action?username=u&password=p 的时候,在控制台,LoginAction 的 execute 方法执行并将接收得到的参数信息打印了出来,
而 ManagerAction 的 execute 方法执行打印出来的参数信息是 null,说明执行到 ManagerAction 的时候,之前的 HTTP 请求参数已经丢失了,同样的,这是由于重定向造成的。
如果不想丢失数据,可以参考 login_alias 的配置方式。需要注意的问题和上面 redirect 提到的是一样的。实际上,这里的 redirectAction 也可以换成 redirect 的,它们达到的效果是一样的。
stream 结果类型的运用
考虑到文章篇幅过长,这个将留到下一篇文章中来专门介绍。这里暂且略过。
配置动态结果
package fan.tutorial.action;
import java.util.Random;
import com.opensymphony.xwork2.Action;
public class DynamicResultAction implements Action {
private String resultView;
public String execute() {
if(new Random().nextInt(100) % 2 == 0){
resultView = "even";
}else{
resultView = "odd";
}
return SUCCESS;
}
public String getResultView() {
return resultView;
}
}
<struts>
<package name="result" namespace="/result" extends="struts-default">
<action name="dynamic" class="fan.tutorial.action.DynamicResultAction">
<result>/pages/result/${resultView}.jsp</result>
</action>
</package>
</struts>
这里使用了 ${resultView} 表达式,这要求 Action 类中必须有一个 public String getResultView() 方法。
struts-xml.zip