?
This document uses PHP Chinese website manual Release
通過處理器映射,可以把進(jìn)來的portlet請(qǐng)求對(duì)應(yīng)到合適的處理器上。已經(jīng)有一些
現(xiàn)成的處理器映射可以使用,比如PortletModeHandlerMapping
。
但還是讓我們先看一下HandlerMapping
的一般概念。
注意,我們這里有意使用“處理器”來代替“控制器”。
DispatcherPortlet
是設(shè)計(jì)用來和多種方式一起處理請(qǐng)求的,
而不僅僅是和Spring Portlet MVC自己的控制器。處理器是任意可以處理Portlet請(qǐng)求的對(duì)象。
控制器當(dāng)然缺省是一種處理器。要將DispatcherPortlet
和一些其他的框架一起使用,只需要實(shí)現(xiàn)相應(yīng)的HandlerAdapter
就可以了。
HandlerMapping
提供的基本功能是提供一個(gè)
HandlerExecutionChain
,后者必須包含匹配進(jìn)來請(qǐng)求的
的處理器,也可能包含需要應(yīng)用到請(qǐng)求的處理器攔截器的列表。當(dāng)一個(gè)請(qǐng)求進(jìn)來時(shí),
DispatcherPortlet
會(huì)把它交給處理器射映,讓它來檢查
請(qǐng)求并得到合適的HandlerExecutionChain
。然后
DispatcherPortlet
會(huì)執(zhí)行處理器以及chain里的攔截器。這些
概念和Spring Web MVC中的完全一致。
可配置的處理器映射非常強(qiáng)大,它可以包含攔截器(在實(shí)際的處理前、后進(jìn)行預(yù)處理或后處理
或兩者都執(zhí)行)??梢酝ㄟ^自定義一個(gè)HandlerMapping
來加入許多功能。
想像一下,一個(gè)自定義的處理器映射,它不僅可以根據(jù)指定的portlet模式來選擇處理器,
也可以根據(jù)請(qǐng)求相聯(lián)系的session里的指定狀態(tài)來選擇。
在Spring Web MVC里,處理器映射通常是基于URL的。因?yàn)樵赑ortlet里確實(shí)沒有URL, 必須使用其它的機(jī)制來控制映射。最常見的兩個(gè)是portlet模式和請(qǐng)求參數(shù), 但在portlet請(qǐng)求里的任何對(duì)象都可以用在自定義的處理器映射中。
余下的章節(jié)會(huì)介紹在Spring Portlet MVC里最常見的三種處理器射映,
它們都繼承AbstractHandlerMapping
并且共享以下的屬性:
interceptors
: 需要使用的攔截器列表。
HandlerInterceptor
在
第?16.5.4?節(jié) “增加 HandlerInterceptor
s”有討論。
defaultHandler
: 在找不到匹配的處理器時(shí),缺省的處理器。
order
: Spring會(huì)按照order屬性值
(見org.springframework.core.Ordered
接口)
對(duì)context里的所有處理器映射進(jìn)行排序,并且應(yīng)用第一個(gè)匹配的處理器。
lazyInitHandlers
: 用來Lazy初始化單例
處理器(prototype處理器是始終lazy初始化的)。缺省值是false。這個(gè)屬性是在這三個(gè)具體處理器里直接實(shí)現(xiàn)。
這是一個(gè)簡(jiǎn)單的處理器映射,它是基于當(dāng)前的portlet模式(比如:'view', 'edit', 'help')。如下:
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping"> <property name="portletModeMap"> <map> <entry key="view" value-ref="viewHandler"/> <entry key="edit" value-ref="editHandler"/> <entry key="help" value-ref="helpHandler"/> </map> </property> </bean>
如果需要在不改變portlet模式的情況下而在多個(gè)控制器間切換, 最簡(jiǎn)單的方法是把一個(gè)請(qǐng)求參數(shù)作為key來控制映射。
ParameterHandlerMapping
使用一個(gè)特定的請(qǐng)求參數(shù)來控制映射。
這個(gè)參數(shù)的缺省名是'action'
,可以通過'parameterName'
屬性來改變。
這個(gè)映射的bean設(shè)置會(huì)是這樣:
<bean id="parameterHandlerMapping" class="org.springframework.web.portlet.handler.ParameterHandlerMapping”> <property name="parameterMap"> <map> <entry key="add" value-ref="addItemHandler"/> <entry key="edit" value-ref="editItemHandler"/> <entry key="delete" value-ref="deleteItemHandler"/> </map> </property> </bean>
最強(qiáng)大的內(nèi)置處理映射
PortletModeParameterHandlerMapping
結(jié)合了前兩者的功能,
能夠在每種portlet模式下進(jìn)行不同的切換。
同樣,參數(shù)的缺省名是“action”,但可以通過 parameterName
來修改。
缺省情況下,同樣的參數(shù)值不能在兩個(gè)不同的portlet模式下使用,
因?yàn)槿绻鹥ortlet自己改變了portlet模式,那么請(qǐng)求在映射中將不在有效。
把 allowDupParameters
屬性設(shè)為true可以改變這種行為,但這種做法是不推薦的。
這個(gè)映射的bean設(shè)置會(huì)是這樣:
<bean id="portletModeParameterHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping"> <property name="portletModeParameterMap"> <map> <entry key="view"> <!-- 'view' portlet mode --> <map> <entry key="add" value-ref="addItemHandler"/> <entry key="edit" value-ref="editItemHandler"/> <entry key="delete" value-ref="deleteItemHandler"/> </map> </entry> <entry key="edit"> <!-- 'edit' portlet mode --> <map> <entry key="prefs" value-ref="prefsHandler"/> <entry key="resetPrefs" value-ref="resetPrefsHandler"/> </map> </entry> </map> </property> </bean>
這個(gè)映射可以在處理鏈中放在
PortletModeHandlerMapping
前面,它可以為每個(gè)模式以及全局提供缺省的映射。
Spring的處理器映射機(jī)制里有處理器攔截器的概念,在希望對(duì)于特定的請(qǐng)求 應(yīng)用不同的功能時(shí),它是非常有用。比如,檢查用戶名(principal)。同樣,Spring Portlet MVC以Web MVC相同的方式實(shí)現(xiàn)了這些概念。
在處理器映射里的攔截器必須實(shí)現(xiàn)org.springframework.web.portlet
里的HandlerInterceptor
接口。
和servlet的版本一樣,這個(gè)接口定義了三個(gè)方法:一個(gè)在實(shí)際的處理器執(zhí)行前被調(diào)用
(preHandle
),一個(gè)在執(zhí)行后被調(diào)用(postHandle
)
還有一個(gè)是在請(qǐng)求完全結(jié)束時(shí)被調(diào)用(afterCompletion
)。
這三個(gè)方法應(yīng)該可以為各種前置和后置處理提供足夠的靈活。
preHandle
返回一個(gè)布爾值??梢允褂眠@個(gè)方法來中斷或者繼續(xù)執(zhí)行鏈的處理。
當(dāng)返回true
時(shí),處理執(zhí)行鏈會(huì)繼續(xù),當(dāng)返回false
時(shí),
DispatcherPortlet
假設(shè)這個(gè)攔截器已經(jīng)處理請(qǐng)求(比如,顯示了合適的視圖)并且不需要繼續(xù)執(zhí)行其它的
攔截器和在執(zhí)行鏈中實(shí)際的處理器。
postHandle
只會(huì)在RenderRequest
中被調(diào)用。ActionRequest
和RenderRequest
都會(huì)調(diào)用preHandle
和afterCompletion
方法。
如果希望只在其中的一種請(qǐng)求中執(zhí)行你的代碼,務(wù)必在處理前檢查請(qǐng)求的類型。
和servlet包類似,portlet包里也有一個(gè) HandlerInterceptor
的具體實(shí)現(xiàn) HandlerInterceptorAdapter
。這個(gè)類所有方法都是空的,
所以可以繼承它,實(shí)現(xiàn)一個(gè)或兩個(gè)你所需要的方法。
Portlet包也帶一個(gè)名為ParameterMappingInterceptor
的具體攔截器,它可以和ParameterHandlerMapping
以及PortletModeParameterHandlerMapping
一起使用。
這個(gè)攔截器可以把用來控制映射的參數(shù)從ActionRequest
帶到隨后的RenderRequest
,這能夠確保
RenderRequest
映射到和
ActionRequest
相同的處理器。這些都是在
preHandle
方法里完成的,所以在你的處理器里仍然可以改變決定
RenderRequest
映射的參數(shù)值。
注意這個(gè)攔截器會(huì)調(diào)用ActionResponse
的setRenderParameter
方法,這意味著在使用它的時(shí)候,
不能在處理器里調(diào)用sendRedirect
。如果確實(shí)需要重定向,
可以手工地把映射參數(shù)向前傳,或者另寫一個(gè)攔截器來處理。