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 配置等。