Struts 2基礎
第2章 Struts 2
此內容是《Java Web開發教程——入門與提高篇(JSP+Servlet)》一書附贈資料的一部分。
2.1概述
Struts現在分兩個版本:Struts 1.X和Struts 2.X。Struts 1.X已經有很多年了,可以說非常流行,但是因為其他框架的快速發展以及自身存在的問題,Struts 2誕生了,Struts 2與Struts 1的區別非常大,實際上Struts 2的核心思想是基於另外一個非常成功的Web框架WebWork。兩者的區別如表20.1所示。下麵主要針對Struts 2進行介紹。
表2.1 Struts1和Struts2的比較
Feature |
Struts 1 |
Struts 2 |
Action類 |
在Struts 1中要求Action類繼承抽象的基類。在Struts 1中一個普遍存在的問題就是麵向抽象類編程,而不是麵向接口編程。 |
Struts 2中的Action可以實現一個Action接口,同時可以實現其他的接口,這樣可以使用戶有選擇性地使用其它自定義的服務。Struts 2提供了基礎類ActionSupport,該類實現了一些通用的接口。Action接口不是必須的。任何具有execute方法的POJO對象都可以用作Struts 2的Action對象。 |
線程模型 |
Struts 1的Actions是單例的,因為隻有一個類的實例來處理所有對這個Action的請求,所以必須是線程安全的。單例策略對Struts 1的Action的能夠完成的功能有很大限製,有些功能需要額外的努力才能完成。Action資源必須是線程安全的或者synchronized |
Struts 2的Action對象是為每個請求實例化的,因此沒有線程安全的問題。(在實踐中,Servlet容器會為每個請求生成多個throw-away對象,增加的對象不會對性能產生太大影響或者對垃圾回收產生影響) |
Servlet依賴 |
Struts 1的Action依賴Servlet API,因為當調用Action的execute方法時需要傳參數HttpServletRequest和HttpServletResponse。 |
Struts 2的Action與容器不是緊密結合在一起的。多數情況下,servlet上下文被表示為Map對象,允許對Action進行獨立的測試。如果需要,Struts 2的Action仍然可以訪問原始的request和response對象。 然而,其它框架元素可以減少或者消除對HttpServetRequest和HttpServletResponse對象進行直接訪問的必要。 |
可測試性 |
測試Struts 1 Action的一個主要障礙就是execute方法使用了Servlet API。1個第三方擴展Struts TestCase,為Struts 1提供了一組模擬(mock)對象。 |
Struts 2的Action可以通過實例化、設置屬性和調用方法進行測試。依賴注入支持使測試更簡單。 |
獲取輸入 |
Struts 1使用ActionForm對象來獲取輸入。像Action一樣,所有的ActionForm必須繼承一個基類。因為其它的JavaBean不能用作ActionForm,開發人員經常需要創建多餘的類來獲取輸入。可以使用動態Form來替換傳統的ActionForm類,但是開發人員同樣可能需要重新描述已有的JavaBean。 |
Struts 2使用Action的屬性作為輸入屬性,不用創建第二個輸入對象。輸入屬性可以是複雜的對象類型,還可以有自己的屬性。可以在頁麵中通過taglib訪問Action屬性。Struts 2也支持ActionForm模式,以及POJO表單對象和POJO Action。複雜對象類型,包括業務或者域對象,都可以作為輸入/輸出對象。模型驅動的特性簡化了標簽庫對POJO輸入對象的引用。 |
表達式語言 |
Struts 1集成了JSTL,所以可以使用JSTL的EL語言,EL提供了基本的對象結構遍曆(object graph traversal),但是集合以及索引屬性支持比較弱。 |
Struts 2可以使用JSTL,同時Struts還支持另外一種功能更強大、使用更靈活的表達式語言,這種語言是Object Graph Notation Language,簡稱OGNL。 |
值與視圖的綁定 |
Struts 1使用了標準的JSP機製把對象與要訪問的頁麵上下文綁定。 |
Struts 2使用了一種ValueStack技術,這樣標簽庫不用把視圖與要呈現的對象類型關聯就可以訪問值。ValueStack策略允許重用涉及多個類型的視圖,這些類型可能有相同的屬性名,但是屬性類型不同。 |
類型轉換 |
Struts 1的ActionForm屬性通常都是字符串類型。Struts 1 使用Commons-Beanutils進行類型轉換。轉換器是針對每個類的,而不能為每個實例配置。 |
Struts 2使用OGNL進行類型轉換,框架包含了常用對象類型和基本數據類型的轉換器。 |
驗證 |
Struts 1支持手動驗證,通過ActionForm的validate方法或者通過繼承通用的驗證器來完成。對於同一個類可以有不同的驗證上下文環境,但是不能鏈接到對子類型的驗證。 |
Struts 2支持通過驗證方法進行手工驗證和XWork驗證框架。Xwork驗證框架支持對子屬性的鏈接驗證,使用為屬性類型定義的驗證規則和上下文。 |
Action執行的控製 |
Struts 1支持為每個模塊提供獨立的請求處理器(生命周期),但是同一個模塊中的所有Action具有相同的生命周期。 |
Struts 2通過攔截器棧支持為每個Action創建不同的生命周期。必要的時候,可以使用不同的Actio創建和使用自定義棧。 |
注:來自Struts的官方網站:https://struts.apache.org/2.0.11.2/docs/comparing-struts-1-and-2.html
Strust 2結構圖如圖2.1(原圖來自Strust 2文檔)所示:
圖2.1 Struts2結構圖
在處理一個請求的時候,主要使用3個類:Action、Interceptor和Result
處理流程:
u 請求到達服務器之後,首先經過一係列過濾器,有的是可選的,最主要的過濾器是FilterDispatcher。所有的請求都會提交給它處理,該過濾器是在web.xml中配置的。配置代碼如下:
<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>
u FilterDispatcher過濾器接收到請求之後調用ActionMapper查看是否需要調用Action。ActionMapper提供了HttpRequest與Action調用請求之間的映射關係,可以決定當前請求是否需要調用Action。如果ActionMapper返回的信息表明需要調用Action。FilterDispatcher過濾器把控製前交給ActionProxy;
u ActionProxy調用配置文件管理器ConfigurationManager,該管理器從struts.xml配置文件中獲取配置信息,獲取的信息主要包括當前請求對應哪個Action(對用戶的請求進行處理),對應哪些Result(決定了如何對用戶響應),有時候還涉及攔截器。然後根據這些信息創建ActionInvocation對象,該對象負責具體的調用過程。struts.xml是用戶需要提供的最主要的配置文件。下麵是一個struts.xml配置文件的部分內容。
<struts>
<package name="default" extends="struts-default">
<action name="Logon" >
<result name="input">/pages/Logon.jsp</result>
<result name="cancel" type="redirectAction">Welcome</result>
<result type="redirectAction">MainMenu</result>
<result name="expired" type="chain">ChangePassword</result>
</action>
<action name="Logoff" >
<result type="redirectAction">Welcome</result>
</action>
</package>
</struts>
u ActionInvocation對象按照順序執行當前請求所對應的攔截器,攔截器能夠對請求進行預處理,例如驗證、文件上傳等,並能夠對響應內容進行再處理。通常攔截器是由係統提供的,如果需要,編程人員隻需要進行配置即可。在調用Action的方法之前,會調用攔截器的預處理方法;
u ActionInvocation對象調用攔截器的預處理方法之後會調用Action的execute方法,Action中的代碼主要由編程人員根據功能進行編寫的,通常從數據庫檢索信息或者向數據庫存儲信息。Action的方法返回一個字符串。下麵是一個簡單的Action例子。
package simple;
import java.util.Map;
import javax.servlet.http.HttpSession;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionSupport;
public class LogoutAction extends ActionSupport {
public String execute() throws Exception {
Map session = ActionContext.getContext().getSession();
session.remove("logined");
session.remove("context");
return SUCCESS;
}
}
u ActionInvocation對象根據Action方法的返回結果以及struts配置文件生成Result對象。Result對象選擇一個模板文件來響應用戶,模板文件可以是JSP、FreeMarker和Velocity。
u 容器加載並執行模板文件,使用在Action中獲取的信息對模版中的變量進行賦值,也可能從資源文件或者其他內部對象中獲取信息。最終向瀏覽器呈現的是HTML、PDF或者其他內容。
u 模板文件執行的結果會經過攔截器進行再處理,最後通過過濾器返回給客戶端。
在該結構圖中,既包含了Struts框架提供的基礎接口,也包括了用戶要編寫的文件。其中,ActionMapper、ActionProxy、ConfigurationManager、ActionInvocation和Result是框架提供的核心類。過濾器和攔截器是框架提供的,用戶可以根據需要進行配置,當然也可以編寫自己的過濾器和攔截器。用戶需要編寫的文件是struts.xml、Action和模板文件,這些也是用戶在使用Struts 2框架時需要做的工作。
2.2 開發人員的主要任務
框架為開發人員提供了大量的輔助類,用戶在使用框架開發的時候隻需要編寫很少文件。在使用Struts 2開發的時候,首先應該把環境搭建起來,然後使用Struts 2提供的標簽開發界麵,然後編寫Action類,最後進行配置。
環境搭建
在進行具體的開發之前,需要先搭建環境。包括如下過程:
u 創建Web工程;
u 加載Struts 2的核心類庫,核心類庫包括commons-logging-1.0.4.jar、freemarker-2.3.8.jar、ognl-2.6.11.jar、struts2-core-2.0.11.2.jar和xwork-2.0.5.jar,把這些類庫放到Web工程的WEB-INF/lib下麵;
u 配置web.xml,主要配置Struts中心控製器FilterDispatcher,下麵是1個例子。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="https://java.sun.com/xml/ns/j2ee" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/j2ee https://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts Blank</display-name>
<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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
u 創建struts.xml配置文件,與類文件放在一起,空白的struts文件如下所示。在使用Struts 2進行開發所有的配置基本上都在這個文件中完成。也可以根據需要創建多個配置文件,然後在這個配置文件中使用<include />進行包含。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"https://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />
<include />
<!-- Add packages here -->
</struts>
環境搭建完之後,在具體開發過程中主要完成3個方麵的工作:
u 製作模板文件,可以使用JSP、FreeMarker或者Velocity等;
u 編寫Action,基本上每個動作對應1個Action;
u 配置,主要在struts.xml中進行配置。
下麵分別介紹。
製作模板文件
模版文件的主要作用是接收用戶輸入的信息,並向用戶展示信息。Struts提供了多個標簽庫來簡化頁麵的代碼量,使用標簽之後頁麵也更容易維護。下麵是一段標簽:
<s:actionerror/>
<s:form action="Profile_update" validate="true">
<s:textfield label="Username" name="username"/>
<s:password label="Password" name="password"/>
<s:password label="(Repeat) Password" name="password2"/>
<s:textfield label="Full Name" name="fullName"/>
<s:textfield label="From Address" name="fromAddress"/>
<s:textfield label="Reply To Address" name="replyToAddress"/>
<s:submit value="Save" name="Save"/>
<s:submit action="Register_cancel" value="Cancel" name="Cancel"
/>
</s:form>
Struts 2中提供了兩類通用標簽和3類界麵標簽:
u 控製標簽
u 數據標簽
u Form標簽
u Non-Form用戶接口標簽
u Ajax標簽
下麵對這些類型的標簽進行介紹。
控製標簽及其用法如表2.2所示。
表2.2 控製標簽
標簽名 |
描述 |
例子 |
if |
與Java中的if基本相同 |
<s:if test="%{false}"> <div>Will Not Be Executed</div> </s:if> <s:elseif test="%{true}"> <div>Will Be Executed</div> </s:elseif> <s:else> <div>Will Not Be Executed</div> </s:else> |
else if |
與Java中的else if基本相同 |
|
else |
與Java中的else基本相同 |
|
append |
按照順序把多個迭代器的元素組合到一個迭代器中,保持原來的順序不變。 |
<s:append var="myAppendIterator"> <s:param value="%{myList1}" /> <s:param value="%{myList2}" /> <s:param value="%{myList3}" /> </s:append> <s:iterator value="%{#myAppendIterator}"> <s:property /> </s:iterator> |
generator |
根據val屬性的給定的值生成迭代器對象。 |
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator> <s:property /><br/> </s:iterator> </s:generator> |
iterator |
對迭代器或者集合進行遍曆,類似於Java中的for-each循環。 |
<s:iterator value="#it.days" status="rowstatus"> <tr> <s:if test="#rowstatus.odd == true"> <td ><s:property/></td> </s:if> <s:else> <td><s:property/></td> </s:else> </tr> </s:iterator> |
merge |
把多個迭代器的元素合並到一個迭代器中,合並後的順序為1.1,2.1,3.1,1.2,1.3…,1.1表示第1個迭代器的第1個元素。 |
<s:merge var="myMergedIterator1"> <s:param value="%{myList1}" /> <s:param value="%{myList2}" /> <s:param value="%{myList3}" /> </s:merge> <s:iterator value="%{#myMergedIterator1}"> <s:property /> </s:iterator> |
sort |
對List進行排序。 |
<s:sort var="mySortedList" comparator="myComparator" source="myList" /> |
subset |
獲取集合的子集。 |
<s:subset var="mySubset" source="myList" count="13" start="3" /> |
數據標簽及其用法如表2.3所示。
表2.3 數據標簽
標簽名 |
描述 |
例子 |
a |
生成HTML的<a> |
<s:a href="%{testUrlId}"><img src="<s:url value="/images/delete.gif"/>" border="none"/></s:a> |
action |
在JSP頁麵中直接調用Action |
<s:action name="actionTagAction" executeResult="true" /> |
bean |
實例化JavaBean對象 |
<s:bean name="org.apache.struts2.example.counter.SimpleCounter" var="counter"> <s:param name="foo" value="BAR" /> The value of foot is : <s:property value="foo"/> <br /> </s:bean> |
date |
創建Date對象 |
<s:date name="person.birthday" format="dd/MM/yyyy" /> |
debug |
|
|
i18n |
得到ResourceBundle對象。 |
<s:i18n name="myCustomBundle"> </s:i18n> |
include |
包含1個JSP或者Servlet的輸出。 |
<s:include value="myJsp.jsp"> <s:param name="param1" value="value2" /> </s:include> |
param |
為其他標簽提供參數 |
參考上麵的例子 |
property |
獲取屬性值 |
參考bean標簽的例子 |
push |
把值保存起來使用 |
<s:push value="user"> <s:propery value="firstName" /> <s:propery value="lastName" /> </s:push> |
set |
把某個值保存到某個作用範圍的變量中。 |
<s:set name="personName" value="person.name"/> Hello, <s:property value="#personName"/>. How are you? |
text |
呈現i18n的文本消息 |
<s:i18n name="struts.action.test.i18n.Shop"> <s:text name="main.title"/> </s:i18n> |
url |
用於生成URL |
<s:url value="editGadget.action"> <s:param name="id" value="%{selected}" /> </s:url> |
Form標簽及其用法如表2.4所示。
表2.4 Form標簽
標簽名 |
描述 |
例子 |
checkbox |
生成複選框 |
<s:checkbox label="checkbox test" name="checkboxField1" value="aBoolean" fieldValue="true"/> |
checkboxlist |
生成多個複選框 |
<s:checkboxlist name="foo" list="bar"/> |
combobox |
輸入框與下拉框的組合。 |
<s:combobox label="My Favourite Fruit" name="myFavouriteFruit" list="{'apple','banana','grape','pear'}" headerKey="-1" headerValue="--- Please Select ---" emptyOption="true" value="banana" /> |
doubleselect |
生成聯動菜單 |
<s:doubleselect label="doubleselect test1" name="menu" list="{'fruit','other'}" doubleName="dishes" doubleList="top == 'fruit' ? {'apple', 'orange'} : {'monkey', 'chicken'}" /> |
head |
生成HTML的head部分。 |
<head> <title>My page</title> <s:head/> </head> |
file |
生成文件輸入框 |
<s:file name="anUploadFile" accept="text/*" />
|
form |
生成form表單 |
<p/> <s:form ... /> <p/> |
hidden |
生成隱藏域 |
<s:hidden name="foo" value="bar" /> |
label |
生成標簽 |
<s:label key="userName" /> |
optiontrans -ferselect |
生成兩個列表框,可以通過中間的按鈕把左邊的選項移動到右邊,也可以把右邊的選項移動到左邊。 |
<s:optiontransferselect label="Favourite Cartoons Characters" name="leftSideCartoonCharacters" list="{'Popeye', 'He-Man', 'Spiderman'}" doubleName="rightSideCartoonCharacters" doubleList="{'Superman', 'Mickey Mouse', 'Donald Duck'}" /> |
optgroup |
在select中提供選項 |
<s:select label="My Selection" name="mySelection" value="%{'POPEYE'}" list="%{#{'SUPERMAN':'Superman', 'SPIDERMAN':'spiderman'}}"> <s:optgroup label="Adult" list="%{#{'SOUTH_PARK':'South Park'}}" /> <s:optgroup label="Japanese" list="%{#{'POKEMON':'pokemon','DIGIMON':'digimon', 'SAILORMOON':'Sailormoon'}}" /> </s:select> |
select |
生成下拉框 |
|
password |
密碼輸入框 |
<s:password label="%{text('password')}" name="password" size="10" maxlength="15" /> |
radio |
單選按鈕 |
<s:radio label="Gender" name="male" list="#genders.genders"/> |
reset |
重值按鈕 |
<s:reset value="Reset" /> |
submit |
提交按鈕 |
<s:submit value="OK" /> |
textarea |
生成文本域 |
<s:textarea label="Comments" name="comments" cols="30" rows="8"/> |
textfield |
生成輸入框 |
<s:textfield key="user" />
|
token |
阻止表單重複提交 |
<s:textfield key="user" />
|
updownselect |
創建元素能夠上下移動的列表框 |
<s:updownselect list="#{'england':'England', 'america':'America', 'germany':'Germany'}" name="prioritisedFavouriteCountries" headerKey="-1" headerValue="--- Please Order Them Accordingly ---" emptyOption="true" /> |
non-form UI標簽及其用法如表2.5所示。
表2.5 non-form標簽
標簽名 |
描述 |
例子 |
actionerror |
呈現錯誤信息 |
<s:actionerror /> |
actionmessage |
呈現提示信息 |
<s:actionmessage /> |
component |
創建自定義組件 |
<s:component template="/my/custom/component.vm"/> |
div |
生成HTML <div> |
|
fielderror |
輸出關於輸入元素的錯誤信息 |
<s:fielderror> <s:param>field1</s:param> <s:param>field2</s:param> </s:fielderror> <s:form .... > .... </s:form> |
Ajax標簽包括a、autocompleter、bind、datetimepicker、div、head、submit、tabbedpanel、textarea、tree、treenode等。具體用法參考Struts 2幫助文檔。
編寫Action
針對每個功能可以編寫1個Action,也可以多個功能共享1個Action。Action完成的主要功能包括:
u 獲取用戶的輸入信息,這個獲取的過程是由框架完成的,但是用戶需要在Action中定義與用戶輸入表單元素名字相同的成員變量,關鍵是要提供對成員變量賦值的set方法,這樣框架在獲取用戶輸入信息之後會調用set方法把值賦給Action的成員變量。
u 根據用戶的請求信息,調用完成業務邏輯的JavaBean。如果希望要把某些執行結果傳遞給模板文件(JSP、FreeMarker和Velocity等),需要在Action中定義成員變量來表示這些結果,最關鍵的是要定義get方法,這樣在執行模版文件的時候會通過get方法來獲取這些信息。
u 根據執行的結果,返回1個字符串,這個字符串決定了使用什麼模板對用戶進行響應。
下麵是1個簡單的例子。
public class LoginAction extends ActionSupport {
private String userId;
private String passwd;
// 對userId和passwd操作的setter和getter方法
public String execute() throws Exception {
if ("admin".equals(userId) && "password".equals(passwd)) {
Map session = ActionContext.getContext().getSession();
session.put("logined","true");
session.put("context", new Date());
return SUCCESS;
}
return ERROR;
}
}
注意:並不是必須繼承ActionSupport,主要提供execute方法即可。
配置
通過配置文件Struts.xml對Web應用的流程進行管理,包括Action映射和Result處理,前者把請求與Action關聯起來,後者把Action執行的結果與響應界麵關聯起來。下麵是一段配置。下麵是一個簡單的例子。
<struts>
<package name="default" extends="struts-default">
<action name="Logon" >
<result name="input">/pages/Logon.jsp</result>
<result name="cancel" type="redirectAction">Welcome</result>
<result type="redirectAction">MainMenu</result>
<result name="expired" type="chain">ChangePassword</result>
</action>
<action name="Logoff" >
<result type="redirectAction">Welcome</result>
</action>
</package>
</struts>
Struts 2中完成的主要配置如表2.6所示。
表2.6 Struts 2的主要配置信息
配置元素 |
例子 |
JavaBean |
<bean type="com.opensymphony.xwork2.ObjectFactory" name="myfactory" /> |
常量 |
<constant name="struts.devMode" value="true" /> |
包 |
<package name="employee" extends="struts-default" namespace="/employee"> ... </package> |
命名空間 |
|
包含 |
<include /> |
攔截器 |
<interceptors> <interceptor name="security" /> <interceptor-stack name="secureStack"> <interceptor-ref name="security"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> |
引用攔截器 |
<action name="VelocityCounter" > <result name="success">...</result> <interceptor-ref name="defaultComponentStack"/> </action> 全局Result: <global-results> <result name="error">/Error.jsp</result> <result name="invalid.token">/Error.jsp</result> </global-results> |
Action |
|
Result |
|
異常配置 |
在Action中使用: <exception-mapping exception="com.company.SecurityException" result="login"/> 全局: <global-exception-mappings> <exception-mapping exception="java.sql.SQLException" result="SQLException"/> <exception-mapping exception="java.lang.Exception" result="Exception"/> </global-exception-mappings> |
Struts 2提供了大量的攔截器,用戶可以根據需要調用。
Struts 2的配置文件struts.xml的DTD定義如下。
<!--
Struts configuration DTD.
Use the following DOCTYPE
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"https://struts.apache.org/dtds/struts-2.0.dtd">
-->
<!ELEMENT struts (package|include|bean|constant)*>
<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-exception-mappings?, action*)>
<!ATTLIST package
name CDATA #REQUIRED
extends CDATA #IMPLIED
namespace CDATA #IMPLIED
abstract CDATA #IMPLIED
externalReferenceResolver NMTOKEN #IMPLIED
>
<!ELEMENT result-types (result-type+)>
<!ELEMENT result-type (param*)>
<!ATTLIST result-type
name CDATA #REQUIRED
class CDATA #REQUIRED
default (true|false) "false"
>
<!ELEMENT interceptors (interceptor|interceptor-stack)+>
<!ELEMENT interceptor (param*)>
<!ATTLIST interceptor
name CDATA #REQUIRED
class CDATA #REQUIRED
>
<!ELEMENT interceptor-stack (interceptor-ref*)>
<!ATTLIST interceptor-stack
name CDATA #REQUIRED
>
<!ELEMENT interceptor-ref (param*)>
<!ATTLIST interceptor-ref
name CDATA #REQUIRED
>
<!ELEMENT default-interceptor-ref (param*)>
<!ATTLIST default-interceptor-ref
name CDATA #REQUIRED
>
<!ELEMENT default-action-ref (param*)>
<!ATTLIST default-action-ref
name CDATA #REQUIRED
>
<!ELEMENT default-class-ref (param*)>
<!ATTLIST default-class-ref
class CDATA #REQUIRED
>
<!ELEMENT global-results (result+)>
<!ELEMENT global-exception-mappings (exception-mapping+)>
<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>
<!ATTLIST action
name CDATA #REQUIRED
class CDATA #IMPLIED
method CDATA #IMPLIED
converter CDATA #IMPLIED
>
<!ELEMENT param (#PCDATA)>
<!ATTLIST param
name CDATA #REQUIRED
>
<!ELEMENT result (#PCDATA|param)*>
<!ATTLIST result
name CDATA #IMPLIED
type CDATA #IMPLIED
>
<!ELEMENT exception-mapping (#PCDATA|param)*>
<!ATTLIST exception-mapping
name CDATA #IMPLIED
exception CDATA #REQUIRED
result CDATA #REQUIRED
>
<!ELEMENT include (#PCDATA)>
<!ATTLIST include
file CDATA #REQUIRED
>
<!ELEMENT bean (#PCDATA)>
<!ATTLIST bean
type CDATA #IMPLIED
name CDATA #IMPLIED
class CDATA #REQUIRED
scope CDATA #IMPLIED
static CDATA #IMPLIED
optional CDATA #IMPLIED
>
<!ELEMENT constant (#PCDATA)>
<!ATTLIST constant
name CDATA #REQUIRED
value CDATA #REQUIRED
>
2.3實例
功能:登錄。
涉及的文件有:
l Login.jsp,用於輸入登錄信息;
l welcome.jsp,登錄之後的歡迎界麵;
l loginCheck.jsp,判斷用戶是否登錄;
l LoginAction.java,完成登錄業務處理,正常情況下會調用其他業務邏輯JavaBean來完成;
l LogoutAction.java,完成退出業務處理;
l struts.xml,應用的配置文件。
下麵分別介紹。
Login.jsp
源文件:Login.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head><body>
<form action="login.action" method="post">
User id<input type="text" name="userId" /> <br/>
Password <input type="password" name="passwd" /> <br />
<input type="submit" value="Login"/>
</form>
</body>
</html>
/pages/welcome.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="ww" uri="/webwork" %>
<jsp:include page="WEB-INF/inc/loginCheck.jsp" />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Welcome</title>
</head>
<body>Welcome, you have logined. <br />
The attribute of 'context' in session is
<ww:property value="#session.context" />
<br /><br /><br />
<a xhref="<%= request.getContextPath() %>/logout.action">Logout</a>
<br />
<a xhref="<%= request.getContextPath() %>/logout2.action">Logout2</a>
</body>
</html>
/WEB-INF/inc/loginCheck.jsp
<%@ taglib="/webwork" prefix="ww" %>
<ww:if test="#session.login != 'true'">
<jsp:forward page="<%= request.getContextPath() %>/login.jsp" />
</ww:if>
simple.LoginAction.java
package simple;
import java.util.Date;import java.util.Map;
import javax.servlet.http.HttpSession;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionSupport;
public class LoginAction extends ActionSupport {
private String userId;
private String passwd;
public String execute() throws Exception {
if ("admin".equals(userId) && "password".equals(passwd)) {
// HttpSession session = ServletActionContext.getRequest().getSession();
// session.setAttribute("logined","true");
// session.setAttribute("context", new Date());
// Better is using ActionContext
Map session = ActionContext.getContext().getSession();
session.put("logined","true");
session.put("context", new Date());
return SUCCESS;
}
return ERROR;
}
public String logout() throws Exception {
// HttpSession session = ServletActionContext.getRequest().getSession();
// session.removeAttribute("logined");
// session.removeAttribute("context");
Map session = ActionContext.getContext().getSession();
session.remove("logined");
session.remove("context");
return SUCCESS;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
simple.LogoutAction.java
package simple;
import java.util.Map;
import javax.servlet.http.HttpSession;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionSupport;
public class LogoutAction extends ActionSupport {
public String execute() throws Exception {
Map session = ActionContext.getContext().getSession();
session.remove("logined");
session.remove("context");
return SUCCESS;
}
}
/WEB-INF/classes/xwork.xml
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "https://www.opensymphony.com/xwork/xwork-1.1.1.dtd">
<xwork>
<include />
<package name="default" extends="webwork-default">
<!-- Add your actions here -->
<action name="login" >
<result name="success" type="dispatcher">/pages/welcome.jsp</result>
<result name="error" type="redirect">/login.jsp</result>
</action>
<action name="logout2" method="logout" >
<result name="success" type="redirect">/login.jsp</result>
</action>
<action name="logout" >
<result name="success" type="redirect">/login.jsp</result>
</action>
</package>
</xwork>
最後更新:2017-04-03 22:15:32