Struts 2基础
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的官方網站:http://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" class="mailreader2.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" class="mailreader2.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 id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://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 file="example.xml"/>進行包含。
<?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.enable.DynamicMethodInvocation" value="false" />
????<constant name="struts.devMode" value="false" />
?
????<include file="example.xml"/>
?
????<!-- 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"
????????????οnclick="form.οnsubmit=null"/>
</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 style="background: grey"><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" class="mailreader2.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" class="mailreader2.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" class="com.company.myapp.MyObjectFactory" /> |
| 常量 | <constant name="struts.devMode" value="true" /> |
| 包 | <package name="employee" extends="struts-default" namespace="/employee"> ???... </package> |
| 命名空間 | |
| 包含 | <include file="Home.xml"/> |
| 攔截器 | <interceptors> ??<interceptor name="security" ?class="com.company.security.SecurityInterceptor"/> ??<interceptor-stack name="secureStack"> ????<interceptor-ref name="security"/> ????<interceptor-ref name="defaultStack"/> ??</interceptor-stack> </interceptors> |
| 引用攔截器 | <action name="VelocityCounter" class="org.apache.struts2.example.counter.SimpleCounter"> ????<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"
??????????"http://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" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">
?
<xwork>
????<include file="webwork-default.xml"/>
?
????<package name="default" extends="webwork-default">
????????<!-- Add your actions here -->
????????<action name="login" class="simple.LoginAction" >
????????????<result name="success" type="dispatcher">/pages/welcome.jsp</result>
????????????<result name="error" type="redirect">/login.jsp</result>
????????</action>
?
????????<action name="logout2" class="simple.LoginAction" method="logout" >
????????????<result name="success" type="redirect">/login.jsp</result>
????????</action>
?
????????<action name="logout" class="simple.LogoutAction" >
????????????<result name="success" type="redirect">/login.jsp</result>
????????</action>
????</package>
</xwork>
總結
以上是生活随笔為你收集整理的Struts 2基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程能力强化(4)——模拟SQL语句解析
- 下一篇: 虚拟机系统与宿主机共享上网设置