Struts2 Action/动作
动作是Struts2框架的核心,因为他们的任何MVC(模型 - 视图 - 控制器)框架。每个URL将被映射到一个特定的动作,它提供了来自用户的请求提供服务所需的处理逻辑。
但动作也提供其他两个重要的能力。首先,操作从请求数据的传输中起着重要的作用,通过向视图,无论是一个JSP或其它类型的结果。二,动作必须协助的框架,在确定结果应该渲染视图,在响应该请求将被退回。
创建动作:
在Struts2的动作,唯一的要求是必须有一个无参数的方法返回String或结果的对象,必须是一个POJO。如果不带参数的方法是不指定,则默认动作是使用execute()方法。
也可以选择扩展ActionSupport类实现了6个接口,包括动作界面。动作界面如下:
1
2
3
4
5
6
7
8
|
public interface Action { public static final String SUCCESS = "success" ; public static final String NONE = "none" ; public static final String ERROR = "error" ; public static final String INPUT = "input" ; public static final String LOGIN = "login" ; public String execute() throws Exception; } |
让我们来看看Hello World示例的操作方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.yiibai.struts2; public class HelloWorldAction{ private String name; public String execute() throws Exception { return "success" ; } public String getName() { return name; } public void setName(String name) { this .name = name; } } |
为了说明这一点,操作方法控制视图,让我们做出以下更改执行方法和扩展类ActionSupport 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.yiibai.struts2; import com.opensymphony.xwork2.ActionSupport; public class HelloWorldAction extends ActionSupport{ private String name; public String execute() throws Exception { if ( "SECRET" .equals(name)) { return SUCCESS; } else { return ERROR; } } public String getName() { return name; } public void setName(String name) { this .name = name; } } |
在这个例子中,我们有一些在execute方法的逻辑来看待的name属性。如果属性等于字符串“SECRET”,我们返回SUCCESS 的结果,否则我们返回ERROR 的结果。因为我们已经扩展ActionSupport,所以我们可以使用字符串常量的成功和错误。现在,让我们修改我们的struts.xml文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? 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" /> < package name = "helloworld" extends = "struts-default" > < action name = "hello" class = "com.yiibai.struts2.HelloWorldAction" method = "execute" > < result name = "success" >/HelloWorld.jsp</ result > < result name = "error" >/AccessDenied.jsp</ result > </ action > </ package > </ struts > |
创建视图
让我们创建以下JSP文件 helloWorld.jsp 的WebContent文件夹在eclipse项目。要做到这一点,右键单击WebContent文件夹在项目资源管理器,选择New >JSP File。该文件将要求返回的结果是SUCCESS,这是一个字符串常量“success”的定义在动作界面:
1
2
3
4
5
6
7
8
9
10
|
<%@ page contentType= "text/html; charset=UTF-8" %> <%@ taglib prefix= "s" uri= "/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Hello World, <s:property value= "name" /> </body> </html> |
以下是由框架的动作的结果将被调用的文件,该文件是等于字符串常量“错误”的ERROR 。以下是AccessDenied.jsp 的内容
1
2
3
4
5
6
7
8
9
10
|
<%@ page contentType= "text/html; charset=UTF-8" %> <%@ taglib prefix= "s" uri= "/struts-tags" %> <html> <head> <title>Access Denied</title> </head> <body> You are not authorized to view this page. </body> </html> |
我们还需要在WebContent文件夹中创建index.jsp。该文件将作为初始动作URL,用户可以直接点击告诉Struts 2框架调用HelloWorldAction类的 execute方法,并呈现 helloWorld.jsp视图。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page language= "java" contentType= "text/html; charset=ISO-8859-1" pageEncoding= "ISO-8859-1" %> <%@ taglib prefix= "s" uri= "/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <title>Hello World</title> </head> <body> <h1>Hello World From Struts2</h1> <form action= "hello" > <label for = "name" >Please enter your name</label><br/> <input type= "text" name= "name" /> <input type= "submit" value= "Say Hello" /> </form> </body> </html> |
就是这样,不需要改变的web.xml文件,所以让我们用同一个web.xml,是之前我们已经创建了范例章。现在,我们已经准备好运行使用Struts 2框架的 Hello World应用程序。
执行应用程序
右键点击项目名称,并单击 Export > WAR File 创建一个WAR文件。然后在Tomcat 的webapps目录下部署这个WAR。最后,启动Tomcat服务器和尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。这会给出以下画面:
让我们为“SECRET”,并输入一个字,应该看到以下页面:
现在输入任何单词而非“SECRET”,应该看到以下页面:
建立多个动作:
经常会定义一个以上的动作,以处理不同的请求,并提供不同的用户的URL,因此可以定义不同的类定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.yiibai.struts2; import com.opensymphony.xwork2.ActionSupport; class MyAction extends ActionSupport{ public static String GOOD = SUCCESS; public static String BAD = ERROR; } public class HelloWorld extends ActionSupport{ ... public String execute() { if ( "SECRET" .equals(name)) return MyAction.GOOD; return MyAction.BAD; } ... } public class SomeOtherClass extends ActionSupport{ ... public String execute() { return MyAction.GOOD; } ... } |
在struts.xml文件中配置这些操作如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<? 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" /> < package name = "helloworld" extends = "struts-default" > < action name = "hello" class = "com.yiibai.struts2.HelloWorld" method = "execute" > < result name = "success" >/HelloWorld.jsp</ result > < result name = "error" >/AccessDenied.jsp</ result > </ action > < action name = "something" class = "com.yiibai.struts2.SomeOtherClass" method = "execute" > < result name = "success" >/Something.jsp</ result > < result name = "error" >/AccessDenied.jsp</ result > </ action > </ package > </ struts > |
正如看到在上述假设的例子,动作的结果是重复的SUCCESS和ERROR。要解决这个问题,建议创建一个类包含结果的结果。
Struts2 拦截器
拦截器的概念是Servlet过滤器或JDK代理类一样的。拦截器允许横切功能分开实现的动作,以及框架。使用拦截器,可以实现如下:
- 提供预处理行动之前被称为逻辑。
- 提供后处理逻辑动作后被调用
- 捕获异常,这样可以进行替代处理。
Struts2框架提供的许多功能都使用拦截实现的例子包括异常处理,文件上传,生命周期回调和验证等事实上作为Struts2的基础,其功能拦截,这可能有7或8拦截器分配给每个动作。
Struts2框架的拦截器:
Struts 2框架提供了良好的箱拦截列表来预先设定的,并准备使用。下面列出了几个重要的拦截:
请看Struts 2文档的完整细节上面提到的拦截。会告诉如何使用Struts应用程序在一个拦截器。
如何使用拦截器?
让我们来看看如何使用已有的拦截,我们的“Hello World”程序。我们将使用计时器来测量过了多长时间执行操作方法,其目的是拦截。同时使用params拦截器,其目的是发送请求参数的动作。您可以尝试不使用这个拦截您的示例中会发现,没有被设置name属性,因为参数是无法达到动作。
我们将继续HelloWorldAction.java,web.xml 的helloWorld.jsp 和 index.jsp 文件,因为他们已经建立了范例章节,但让我们如下修改struts.xml文件,添加一个拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<? 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" /> < package name = "helloworld" extends = "struts-default" > < action name = "hello" class = "com.yiibai.struts2.HelloWorldAction" method = "execute" > < interceptor-ref name = "params" /> < interceptor-ref name = "timer" /> < result name = "success" >/HelloWorld.jsp</ result > </ action > </ package > </ struts > |
右键点击项目名称,并单击 Export > WAR File 创建一个WAR文件。然后部署在Tomcat 的webapps目录下这个WAR。最后,启动Tomcat服务器和尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。这会给你以下画面:
现在,在给定的文本框中输入单词,并单击“Say Hello按钮执行已定义的动作。现在,如果将检查生成的日志,会发现下面的文字:
1
2
3
4
|
INFO: Server startup in 3539 ms 27/08/2011 8:40:53 PM com.opensymphony.xwork2.util.logging.commons.CommonsLogger info INFO: Executed action [//hello!execute] took 109 ms. |
这里底行,正在生成因为这告诉动作发生要执行的总共为 109ms定时器的拦截器。
创建自定义的拦截器
在应用程序中使用自定义的拦截器是一种优雅的方式提供横切的应用功能。创建一个自定义拦截器是很容易的,需要扩展的接口,下面的Interceptor接口:
1
2
3
4
5
6
|
public interface Interceptor extends Serializable{ void destroy(); void init(); String intercept(ActionInvocation invocation) throws Exception; } |
正如其名称所表明的,init()方法提供了一种方法来初始化拦截器,并destroy() 方法提供了一种工具拦截清理。不同的行动,拦截被重用跨请求和需要是线程安全的,尤其是intercept() 方法。
ActionInvocation对象可以访问运行时环境。它允许访问的动作本身和方法调用的动作,并确定动作是否已被调用。
如果不需要初始化或清除代码,可以扩展AbstractInterceptor类。这提供了一个默认的无操作实现的init()和 destroy()方法。
创建拦截器类:
让我们创建Java资源 MyInterceptor.java> src 文件夹:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.yiibai.struts2; import java.util.*; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception{ /* let us do some pre-processing */ String output = "Pre-Processing"; System.out.println(output); /* let us call action or next interceptor */ String result = invocation.invoke(); /* let us do some post-processing */ output = "Post-Processing" ; System.out.println(output); return result; } } |
就像看到的,实际行动将使用拦截器执行invocation.invoke()调用。所以,可以做一些前处理和一些处理后,根据需要。
该框架本身启动的过程中,在第一次调用ActionInvocation对象的invoke()。每次 invoke()被调用,ActionInvocation的咨询的状态和执行为准拦截接下来。通过请求流以下数据图显示了相同的概念:
创建动作类:
让我们创建一个Java文件HelloWorldAction.java的Java下Java Resources > src下面给出的内容包名为 com.yiibai.struts2。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package com.yiibai.struts2; import com.opensymphony.xwork2.ActionSupport; public class HelloWorldAction extends ActionSupport{ private String name; public String execute() throws Exception { System.out.println( "Inside action...." ); return "success" ; } public String getName() { return name; } public void setName(String name) { this .name = name; } } |
在前面的例子中,我们已经看到,这是一个相同的类。我们有标准的“名称”属性的getter和setter方法,并返回字符串“success”的执行方法。
创建视图
让我们创建以下JSP文件helloWorld.jsp,在eclipse项目在WebContent文件夹。
1
2
3
4
5
6
7
8
9
10
|
<%@ page contentType= "text/html; charset=UTF-8" %> <%@ taglib prefix= "s" uri= "/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Hello World, <s:property value= "name" /> </body> </html> |
创建页面:
我们还需要在WebContent文件夹中创建 index.jsp。该文件将作为初始动作URL,用户可以在其中点击告诉Struts 2框架调用 HelloWorldAction类定义的方法呈现 helloWorld.jsp视图。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page language= "java" contentType= "text/html; charset=ISO-8859-1" pageEncoding= "ISO-8859-1" %> <%@ taglib prefix= "s" uri= "/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <title>Hello World</title> </head> <body> <h1>Hello World From Struts2</h1> <form action= "hello" > <label for = "name" >Please enter your name</label><br/> <input type= "text" name= "name" /> <input type= "submit" value= "Say Hello" /> </form> </body> </html> |
Hello 动作定义在上面的视图文件将被映射到HelloWorldAction类和其执行方法使用struts.xml文件。
配置文件
现在,我们需要注册我们的拦截器,然后调用它默认的拦截器在前面的例子中调用。要注册一个新定义的拦截,直接放在的<interceptors>...</interceptors>标签下<package>的标签插件struts.xml文件。您可以跳过这一步为默认的拦截器,就像我们在我们前面的例子。但在这里,让我们注册和使用它,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?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" /> < package name= "helloworld" extends = "struts-default" > <interceptors> <interceptor name= "myinterceptor" class = "com.yiibai.struts2.MyInterceptor" /> </interceptors> <action name= "hello" class = "com.yiibai.struts2.HelloWorldAction" method= "execute" > <interceptor-ref name= "params" /> <interceptor-ref name= "myinterceptor" /> <result name= "success" >/HelloWorld.jsp</result> </action> </ package > </struts> |
应该指出的是,可以注册多个拦截器<package>标签内,同一时间,可以调用多个拦截里面的<action>标签。可以调用相同的拦截器与不同的动作。
web.xml文件需要在 WEB-INF文件夹下创建 WebContent 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<? xml version = "1.0" encoding = "UTF-8" ?> < web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id = "WebApp_ID" version = "3.0" > < display-name >Struts 2</ display-name > < welcome-file-list > < welcome-file >index.jsp</ welcome-file > </ welcome-file-list > < filter > < filter-name >struts2</ filter-name > < filter-class > org.apache.struts2.dispatcher.FilterDispatcher </ filter-class > </ filter > < filter-mapping > < filter-name >struts2</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > </ web-app > |
右键点击项目名称,并单击 Export > WAR File 文件创建一个WAR文件。然后部署在Tomcat 的webapps目录下这个WAR。最后,启动Tomcat 服务器和尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。这会给你以下画面:
现在,在给定的文本框中输入任何单词,并单击“Say Hello“ 按钮执行已定义的动作。现在,如果检查生成的日志,会发现下面的文本下方:
1
2
3
|
Pre-Processing Inside action.... Post-Processing |
堆叠多个拦截器:
可以想像,配置多个拦截器每个动作很快就会变得非常难以控制。出于这个原因,拦截器与拦截器栈管理。下面是一个例子,直接从在struts-default.xml文件:
1
2
3
4
5
6
7
8
|
< interceptor-stack name = "basicStack" > < interceptor-ref name = "exception" /> < interceptor-ref name = "servlet-config" /> < interceptor-ref name = "prepare" /> < interceptor-ref name = "checkbox" /> < interceptor-ref name = "params" /> < interceptor-ref name = "conversionError" /> </ interceptor-stack > |
上面的栈被调用basicStack,可用于在配置中,如下所示。此配置节点放置在<package.../>节点下。每个<interceptor-ref.../>标记引用一个拦截器或拦截器栈已配置在当前的拦截器栈。因此,这是非常重要的,以确保该名称是唯一的所有拦截器和拦截器栈配置配置初始的拦截器和拦截器栈时。
我们已经看到了如何应用拦截的动作,将拦截器栈是没有什么不同。事实上,我们完全使用相同的标签:
1
2
3
4
|
<action name= "hello" class = "com.yiibai.struts2.MyAction" > <interceptor-ref name= "basicStack" /> <result>view.jsp</result> </action |
上述注册的“basicStack”所有6个拦截器完成注册的栈 Hello 动作。应该指出的是,拦截器执行的顺序在配置中。例如,在上述情况下,异常将被执行,servlet 配置等。