WebWork教程-ServletDispatcher
ServletDispatcher
是默認(rèn)的處理
Web Http
請求的調(diào)度器,它是一個(gè)
JavaServlet
,是
WebWork
框架的控制器。所有對
Action
調(diào)用的請求都將通過這個(gè)
ServletDispatcher
調(diào)度。它將在
web.xml
里配置
ServletDispatcher
時(shí)指定,讓所有對
WebWork
的
Action(
默認(rèn)的是
.action
的后綴
)
的請求都對應(yīng)到該調(diào)度的
JavaServlet
中,具體配置在前面的
WebWork-helloWorld
中有介紹。
?
ServletDispatcher
接受客戶端的
HTTP
請求,將
JavaServlet
的很多相關(guān)對象進(jìn)行包裝,再傳給我們的
XWork
框架,由我們的
XWork
框架去解析我們的
xwork.xml
配置文件,根據(jù)配置文件的信息,創(chuàng)建對應(yīng)的
Action
,組裝并調(diào)用相應(yīng)的攔截器,執(zhí)行
Action
,返回執(zhí)行結(jié)果。
WebWork
使用
XWork
的核心,主要是由這個(gè)
ServletDispatcher
去實(shí)現(xiàn)的
?
具體調(diào)用流程:
(Servlet
調(diào)用流程
)
?
一、?
init
()方法在
web
服務(wù)器啟動時(shí)調(diào)用。
1
、初始化
Velocity
引擎
?
2
、檢查是否支持配置文件重新載入功能。如果
webwork.configuration.xml.reload
(見
webwork.properties
文件)設(shè)置為
true,
每個(gè)
request
請求都將重新裝載
xwork.xml
配置文件。在開發(fā)環(huán)境使用將會非常方便,但在生產(chǎn)環(huán)境必需設(shè)置為
false
代碼如下:
if ("true".equalsIgnoreCase(Configuration.getString("webwork.configuration.xml.reload"))) {FileManager.setReloadingConfigs(true);}
?
3
、設(shè)置一些文件上傳的信息,比如:上傳臨時(shí)目錄,上傳的最大字節(jié)等。都設(shè)置在
webwork.properties
文件里,如果在
classpath
中找不到這個(gè)屬性文件,它會去讀取默認(rèn)的
default.properties
?
二、??
service
()方法,每次客戶端的請求都將調(diào)用此方法
1、???????????
通過
request
請求取得
action
的命名空間(
namespace
,與
xwork.xml
配置文件里
package
標(biāo)簽的
name
對應(yīng))
例如:
/foo/bar/MyAction.action
,取得的命名空間為
/foo/bar
在
xwork.xml
配置文件里應(yīng)該有這一段:
<package name="foo.bar" …….
?
2、???????????
根據(jù)
servlet
請求的
Path,
解析出要調(diào)用該請求的
Action
的名字(
actionName
),例如:(
../foo/bar/MyAction.action -> MyAction
)
在
xwork.xml
配置文件里應(yīng)該有:
<package name="foo.bar" …….
<Action name=” MyAction”……]
?
3、???????????
創(chuàng)建
Action
上下文(
extraContext
)。我們前面介紹的
ActionContext
上下文的對象,就是在這里設(shè)置的。它將
JavaServlet
相關(guān)的對象進(jìn)行包裝,放入到
extraContext
這個(gè)
Map
對象里。
/**
???? *
將所有的應(yīng)用請求和
servlet
屬性保存到一個(gè)
HashMap
中,
???? * @param requestMap
存放所有
request
請求屬性的
Map
???? * @param parameterMap
存放所有
request
請求參數(shù)的
Map
???? * @param sessionMap
存放所有
session
屬性的
Map
???? * @param applicationMap
存放所有
servlet
上下文屬性的
Map
???? * @param request?HttpServletRequest
對象
???? * @param response ?HttpServletResponse
對象
.
???? * @param servletConfig ?ServletConfig
對象
.
???? * @return
代表
Action
上下文的一個(gè)
HashMap
*/
?
?
public
static HashMap createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletConfig servletConfig) {
??????? HashMap extraContext = new HashMap();
??????? extraContext.put(ActionContext.PARAMETERS, parameterMap);
??????? extraContext.put(ActionContext.SESSION, sessionMap);
??????? extraContext.put(ActionContext.APPLICATION, applicationMap);
??????? extraContext.put(ActionContext.LOCALE, request.getLocale());
?
??????? extraContext.put(HTTP_REQUEST, request);
??????? extraContext.put(HTTP_RESPONSE, response);
??????? extraContext.put(SERVLET_CONFIG, servletConfig);
??????? extraContext.put(COMPONENT_MANAGER, request.getAttribute("DefaultComponentManager"));
?
??????? // helpers to get access to request/session/application scope
??????? extraContext.put("request", requestMap);
??????? extraContext.put("session", sessionMap);
??????? extraContext.put("application", applicationMap);
??????? extraContext.put("parameters", parameterMap);
?
??????? AttributeMap attrMap = new AttributeMap(extraContext);
??????? extraContext.put("attr", attrMap);
?
??????? return extraContext;}
下面我們來看看它是如何將
request
請求的參數(shù)和
session
進(jìn)行包裝的:
Request
包裝
protected Map getParameterMap(HttpServletRequest request) throws IOException {
??????? return request.getParameterMap();
}
這個(gè)方法比較簡單,它直接調(diào)用了
HttpServletRequest
的方法
getParameterMap
(),將所有
request
請求的參數(shù)封裝到一個(gè)
Map
中
?
Session
包裝
protected Map getSessionMap(HttpServletRequest request) {
??????? return new SessionMap(request);
}
這個(gè)方法取得所有
Session
中的屬性,它調(diào)用了
com.opensymphony.webwork.dispatcher. SessionMap
類,這個(gè)類實(shí)現(xiàn)了
Map
接口,在
entrySet
()方法中列舉
Session
的所有屬性,存放在
Set
中。
?
4、???????????
根據(jù)前面獲得的
namespace
、
actionName
、
extraContext
,創(chuàng)建一個(gè)
ActonProxy
ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);
默認(rèn)的
proxy
是
com.opensymphony.xwork.DefaultActionProxy
,在它的構(gòu)造函數(shù)會進(jìn)行下面的操作:
1
)、根據(jù)
namespace
、
actionName
讀取
xwork.xml
配置文件里這個(gè)
Action
的所有配置信息
?
2
)、創(chuàng)建
ActionInvocation
invocation=ActionProxyFactory.getFactory().createActionInvocation(this, extraContext);
默認(rèn)的
invocation
是
com.opensymphony.xwork.DefaultActionInvocation
,它的構(gòu)造函數(shù)操作有
:
?
???????????????????????? i.?????????????
由
com.opensymphony.xwork.ObjectFactory
創(chuàng)建我們配置文件描述的
Action
對象。再將這個(gè)
Action
對象存放入
OgnlValueStack
中。記得我們前面用戶注冊的例子嗎?當(dāng)用戶提交表達(dá)時(shí)它會有表達(dá)式語言向
OgnlValueStack
取得
Action
對象的字段,再把輸入框的數(shù)據(jù)設(shè)置到對應(yīng)的
Action
字段中,這個(gè)
Action
對象就是在這個(gè)時(shí)候進(jìn)棧的
??????????????????????? ii.?????????????
傳入
extraContext
參數(shù),創(chuàng)建與
ActionInvocation
對應(yīng)的
Action
上下文(
ActionContext
)。記得我們在介紹
ActionContext
的最后,提出了一個(gè)需要注意的地方:不要在
Action
構(gòu)造函數(shù)中調(diào)用
ActionContext.getContext()
。現(xiàn)在應(yīng)該能明白,原來是
Action
對象實(shí)例在
ActionContext
對象實(shí)例之前創(chuàng)建的,所有這樣取得
ActionContext
容器對象就有可能會返回
null
????????????????????? iii.?????????????
取得這個(gè)
Action
對應(yīng)的所有攔截器(
Interceptor
),存放入
java.util.Iterator
對象中。
?
5、???????????
執(zhí)行
proxy
的
execute()
方法,這個(gè)方法最核心的語句是:
retCode = invocation.invoke();
,
invocation
對象的
invoke()
方法它遍歷并執(zhí)行這個(gè)
Action
對應(yīng)的所有攔截器,執(zhí)行
Action
對應(yīng)的方法(默認(rèn)的是
execute()
),根據(jù)
Action
執(zhí)行返回的值去調(diào)用執(zhí)行相應(yīng)的
Result
(返回結(jié)果處理)的方法
?
Action
的單元測試
理解了
ServletDispatcher
,我們就明白了整個(gè)框架調(diào)用執(zhí)行的順序。
Action
雖然是與
Web
無關(guān),可是它的創(chuàng)建、參數(shù)設(shè)置、執(zhí)行與我們的
WebWork
、
XWork
緊密關(guān)聯(lián)在一起,有我們的控制器
ServletDispatcher
去統(tǒng)一調(diào)度,那我們?nèi)绾稳?/span>
Action
進(jìn)行獨(dú)立的單元測試呢?
請看下面的例子:使用單元測試框架
JUnit
對
register.User. RegisterAction
做單元測試
見
example.register. RegisterActionTest
類
testExecuteWithProxyFactory()
方法
?
public
void testExecuteWithProxyFactory() throws Exception{
???????
??????? //
創(chuàng)建
action
上下文(
actionContext
)
??????? Map params = new HashMap();
??????? params.put("user.username","Moxie");
??????? params.put("user.password","mypassword");
??????? params.put("user.email","achqian@yahoo.com.cn");
??????? params.put("user.age",new Integer(23));
??????? Map extraContext = new HashMap();
??????? extraContext.put(ActionContext.PARAMETERS,params);
???????
??????? //
創(chuàng)建代理(找出所在的
action
)
??????? ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("example", "register", extraContext);
?
??????? //
不要執(zhí)行出現(xiàn)
Success
后的代碼
proxy.setExecuteResult(false);
???????
??????? //
測試代碼是否正確
??? ??? assertEquals(proxy.execute(),"success");
???????
??????? //
返回
Action
,測試
action
里面的代碼是否正確
??????? RegisterAction action = (RegisterAction) proxy.getAction();
??????? assertEquals(action.getUser().getUsername(),"Moxie");
??????? assertEquals(action.getUser().getAge(),23);
??? }
?
下面解說這個(gè)方法:
1、??
對象
params
表示請求參數(shù)的
Map,
在它里面設(shè)置了注冊用戶的信息。
extraContext
當(dāng)然就是我們
ActionContext
上下文的容器,它里面保存了放置請求參數(shù)的對象
params
2、??
創(chuàng)建我們的
ActionProxy
,它傳入的參數(shù)有:“
example
”-這個(gè)
Action
的命名空間,“
register
”-
Action
對應(yīng)的名字,
extraContext
-存放
Actin
上下文里的對象,,執(zhí)行并將它返回的值與“
success
”比較,測試
Action
是否能正確執(zhí)行完成。注意:
proxy.setExecuteResult(false);
,因?yàn)槲覀兪菃卧獪y試,所以
Action
執(zhí)行完成就可以了,不用再去調(diào)用結(jié)果響應(yīng)的操作,故將是否執(zhí)行結(jié)果設(shè)置為“
false
”。
3、??
Action
正確執(zhí)行完成之后,我們也可以測試現(xiàn)在
Action
的字段里的數(shù)據(jù)是否按照我們預(yù)期的要求正確設(shè)置。從
ActionProxy
對象里取得執(zhí)行的
Action
,即
RegisterAction
對象,再取得它的
User
模型,將其數(shù)據(jù)與前面設(shè)置參數(shù)的數(shù)據(jù)進(jìn)行比較,判斷它是否等于我們預(yù)期設(shè)置的數(shù)值。
?
Result Type
前面我們學(xué)習(xí)了
ServletDispatcher
,它是
WebWork
框架機(jī)制的核心。它和
Action
在我們
MVC
模式中,扮演著控制器的角色,
MVC
模式通過控制器實(shí)現(xiàn)了我們模型和視圖的分離。
WebWork
提供了多種活靈活視圖展現(xiàn)方式。
我們先看看前面用戶注冊例子的展現(xiàn)方式:我們使用的是
Jsp
和
WebWork
自帶的標(biāo)簽庫,
Action
對應(yīng)的視圖當(dāng)然是在
xwork.xml
配置文件里設(shè)置:
<action name="register" class="example.register.RegisterAction" >
<result name="success" type="dispatcher">
?????????? <param name="location">register-result.jsp</param>
</result>
<interceptor-ref name="params"/>
</action>
?
Result
是
Action
執(zhí)行完返回的一個(gè)字符串常量,它表示
Action
執(zhí)行完成的狀態(tài),比如:執(zhí)行成功、執(zhí)行失敗等。在我們前面
Action
的介紹中,詳細(xì)介紹了它默認(rèn)的標(biāo)準(zhǔn)
Result
,當(dāng)然
Result
我們也可以自己定義,只要是一個(gè)字符串常量就可以了。
?
Result
的值在
xwork.xml
配置文件里就是
result
標(biāo)簽里“
name
”的值,
name="success"
表示
Action
執(zhí)行成功,返回“
success
”就對應(yīng)此標(biāo)簽的配置,進(jìn)行視圖輸出:
“
type
”就是我們的
Result Type
,
Result Type
是一個(gè)類,它在
Action
執(zhí)行完成并返回
Result
之后,決定采用哪一種視圖技術(shù),將執(zhí)行結(jié)果展現(xiàn)給用戶。我們輸出的類型是
type="dispatcher"
,它對應(yīng)
com.opensymphony.webwork.dispatcher.ServletDispatcherResult
這個(gè)類,它將執(zhí)行結(jié)果通過
javax.servlet.RequestDispatcher
的
forward()
或
include()
方法調(diào)度到
Jsp
頁面展現(xiàn)。
我們可以自己開發(fā)
Result Type
,實(shí)現(xiàn)我們需要的視圖展現(xiàn)方式。
Result Type
必需要實(shí)現(xiàn)
com.opensymphony.xwork..Result
接口。在
WebWork
中,它已經(jīng)為我們提供了很多
Result Type
,實(shí)現(xiàn)了視圖部分對
JSP, Velocity, FreeMarker, JasperReports
,
XML
等的支持,具體如下表格
:
Result Type
|
Nname
|
Class
|
Dispatcher
|
dispatcher
|
com.opensymphony.webwork.dispatcher.ServletDispatcherResult
|
Redirect
|
Redirect
|
com.opensymphony.webwork.dispatcher.ServletRedirectResult
|
Action Chaining
|
Chain
|
com.opensymphony.xwork.ActionChainResult
|
Velocity
|
Velocity
|
com.opensymphony.webwork.dispatcher.VelocityResult
|
FreeMarker
|
freemarker
|
com.opensymphony.webwork.views.freemarker.FreemarkerResult
|
JasperReports
|
Jasper
|
com.opensymphony.webwork.views.jasperreports.JasperReportsResult
|
XML/XSL
|
Xslt
|
com.opensymphony.webwork.views.xslt.XSLTResult
|
HttpHeader
|
?
|
com.opensymphony.webwork.dispatcher.HttpHeaderResult
|
?
?
Dispatcher
:
通過
javax.servlet.RequestDispatcher
的
forward()
或
include()
方法調(diào)度到頁面展現(xiàn),這樣的頁面一般是
Jsp
頁面。
?
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
location
|
是
|
執(zhí)行完成之后轉(zhuǎn)向的位置
|
parse
|
否
|
默認(rèn)的是“
true
”,如果設(shè)置為“
false
”,
location
參數(shù)將不會被
OGNL
表達(dá)式語言解析
|
例子:
<result name="success" type="dispatcher">
?????????? <param name="location">register-result.jsp</param>
???????? </result>
也可以簡單寫成這樣:
?? <result name="success" type="dispatcher">register-result.jsp</result>
?
?
Action Chaining
:
一種特殊的視圖結(jié)果,將
Action
執(zhí)行完之后鏈接到另一個(gè)
Action
中繼續(xù)執(zhí)行。新的
Action
使用上一個(gè)
Action
的上下文(
ActionContext
)。
?
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
actionName
|
是
|
將要被鏈接的
Action
名字
|
namespace
|
否
|
被鏈接的
Action
的命名空間(
namespace
),如果不設(shè)置,默認(rèn)的即是當(dāng)前的命名空間
|
例子:
<result name="success" type="chain">
??? <param name="actionName">bar</param>
??? <param name="namespace">/foo</param>
</result>
?
將要調(diào)用的
Action
如下:
<action name="bar" class="myPackage.barAction">
??? ...
</action>
?
Velocity
:
它類似
Jsp
的執(zhí)行環(huán)境(使用
JavaServlet
容器),將
Velocity
模板轉(zhuǎn)化成數(shù)據(jù)流的形式,直接通過
JavaServlet
輸出。
?
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
location
|
是
|
執(zhí)行完成之后轉(zhuǎn)向的位置
(
一般是
.vm
頁面
)
|
parse
|
否
|
默認(rèn)的是“
true
”,如果設(shè)置為“
false
”,
location
參數(shù)將不會被
OGNL
表達(dá)式語言解析
|
例子:
<result name="success" type="velocity">
??? <param name="location">foo.vm</param>
</result>
?
?
FreeMarker
:
FreeMarker
是一個(gè)純
Java
模板引擎;一個(gè)普通的基于模板生成文本的工具,它只能應(yīng)用在
Web
應(yīng)用環(huán)境中。
?
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
location
|
是
|
執(zhí)行完成之后轉(zhuǎn)向的位置
|
parse
|
否
|
默認(rèn)的是“
true
”,如果設(shè)置為“
false
”,
location
參數(shù)將不會被
OGNL
表達(dá)式語言解析
|
contentType
|
否
|
如果不指定,默認(rèn)的是
"text/html"
|
例子:
<result name="success" type="freemarker">foo.ftl</result>
?
?
JasperReports
:
將
Action
執(zhí)行的結(jié)果通過
JasperReports
報(bào)表形式輸出,可以指定
JasperReports
支持的輸出格式(
PDF
、
HTML
、
XLS
、
CSV
、
XML
等),默認(rèn)是通過
PDF
格式輸出。
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
location
|
是
|
執(zhí)行完成之后轉(zhuǎn)向的位置
|
parse
|
否
|
默認(rèn)的是“
true
”,如果設(shè)置為“
false
”,
location
參數(shù)將不會被
OGNL
表達(dá)式語言解析
|
dataSource
|
是
|
它是
Action
的一個(gè)字段(通常是一個(gè)
List
),
OGNL
表達(dá)式被用來去
value stack
(
OgnlValueStack
)重新找回這個(gè)
dataSource
|
format
|
否
|
報(bào)表生成的數(shù)據(jù)格式,默認(rèn)的是
pdf
|
例子:
<result name="success" type="jasper">
??? <param name="location">foo.jasper</param>
??? <param name="dataSource">mySource</param>
??? <param name="format">CSV</param>
</result>
?
或者默認(rèn)的
pdf
格式
<result name="success" type="jasper">
??? <param name="location">foo.jasper</param>
??? <param name="dataSource">mySource</param>
</result>
????????
XML/XSL
:
將結(jié)果轉(zhuǎn)換為
xml
輸出
?
參數(shù)
(Parameters)
|
是否必需
|
描
?
述
|
location
|
是
|
執(zhí)行完成之后轉(zhuǎn)向的位置
|
parse
|
否
|
默認(rèn)的是“
true
”,如果設(shè)置為“
false
”,
location
參數(shù)將不會被
OGNL
表達(dá)式語言解析
|
例子:
<result name="success" type="xslt">foo.xslt</result>?? posted on 2006-09-01 13:41 Binary 閱讀(653) 評論(0) 編輯 收藏 所屬分類: Webwork