18.1 Introduction
The main way in which portlet workflow differs from servlet workflow is that the request to the portlet can have two distinct phases: the action phase and the render phase
The action phase:
executed only once and is where any 'backend' changes or actions occur
The render phase:
produces what is displayed to the user each time the display is refreshed
● The critical point here is that for a single overall request, the action phase is executed only once, but the render phase may be executed multiple times
So, the separation of the two phases is preserved throughout the Spring Portlet MVC framework
Locale resolution and theme resolution are not supported in Portlet MVC
18.1.1 Controllers - The C in MVC
· void handleActionRequest(request,response)
·
ModelAndView handleRenderRequest(request,response)
18.1.2 Views - The V in MVC
All the view rendering capabilities of the servlet framework are used directly via a special bridge servlet named ViewRendererServlet
. By using this servlet, the portlet request is converted into a servlet request and the view can be rendered using the entire normal servlet infrastructure. This means all the existing renderers, such as JSP, Velocity, etc., can still be used within the portlet.
18.2 The DispatcherPortlet
1. dispatches requests to controllers
2. offers other functionality facilitating the development of portlet applications
3. integrated with the Spring ApplicationContext
and allows you to use every other feature Spring has
4.usage:
In portlet.xml:
<portlet>
<portlet-name>sample</portlet-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Sample Portlet</title>
</portlet-info>
</portlet>
each DispatcherPortlet
has its own WebApplicationContext.
which inherits all the beans already defined in the Root WebApplicationContext
.
问:启动DispatcherServlet时,到底背后做了些什么?
答:
框架会去look for a file named [portlet-name]-portlet.xml
in the WEB-INF
directory of your web application and create the beans defined there
但是,可以改变加载的位置.
问:在WebApplicaitonContext中有哪些特殊的bean?
答: hander mapping(s)
Controller(s)
ViewResolver
Multipart Resolver
Handle Exception
问:How complete process a request goes through if handled by a DispatcherPortlet?
答:
1. The locale returned by PortletRequest.getLocale()
is bound to the request to let elements in the process resolve the locale to use when processing the request (rendering the view, preparing data, etc.).
2. If a multipart resolver is specified and this is an ActionRequest
, the request is inspected for multiparts and if they are found, it is wrapped in a MultipartActionRequest
for further processing by other elements in the process.
3. An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (pre-processors, post-processors, controllers) will be executed in order to prepare a model.
4. If a model is returned, the view is rendered, using the view resolver that has been configured with the WebApplicationContext
. If no model is returned (which could be due to a pre- or post-processor intercepting the request, for example, for security reasons), no view is rendered, since the request could already have been fulfilled.
ViewRenderServlet到底干了些什么事?
因为在Portlet MVC 中,render的过程处理起来比Spring Web MVC 复杂 ,所以必须把
PortletReqeust/PortletResponse 转换成HttpServletRequest/HttpServletResponse,然后调用View接口的render方法。要做到这样,光一个DispatcherServlet是行不通的,它要驰骋武林,必须借助ViewRenderServlet的功力!
光说不行,怎么将ViewRenderServlet的功力传给DispatcherServlet呢。Spring 的 Portlet MVC 告诉你只要在web.xml 中做如下配置即可:
<servlet>
<servlet-name>ViewRenderServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRenderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRenderServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
就这样一配,DispatcherServlet就能完成render工作,是不是有点骗人,它到底是怎么做的啊?
我们大致看看一下人家的本事吧:
1. 把WebApplicationContext绑定到request的属性中,key的值为
WEB_APPLICAITON_CONTEXT_ATTRIBUTE
2. 把Model 对象和View对象绑定到request的属性中,以方便ViewRenderServlet能从request中得到装载了数据的Model和携带了视图渲染信息的View对象.
3. 创建一个PortletRequestDispatcher对象,并且调用该对象上的include方法用这个url----/WEB-INF/servlet/view.这样一来,请求就到了ViewRenderServlet了.
4. ViewRenderServlet然后调用render方法即可完成视图的渲染工作。
整个过程,DispatcherServlet确实帮了不少忙,但这些忙都似乎是关于数据绑定的。真正做事的还是人家ViewRenderServlet.这就叫做“拿来主义”。呵呵,实际上可以看成是委托模式的应用。
在DiapatcherServlet中可以配置触发ViewRenderServlet的URL,怎么配呢:
在DiapatcherServlet配置的地方,添加一个参数即可:
<viewRenderUrl>/viewRender</viewRenderUrl>
Spring 的高明之处的体现之一就是这个家伙的高度可配置功能,实属历史罕见!
18.2 The Controller
(Portlet MVC中的)
下面来看看Spring 的核心大脑Controller。这个家伙有得看,相当精致又相当复杂!
org.springframework.web.portlet.mvc.Controller
void handleActionRequest(javax.portlet.ActionRequest request,
javax.portlet.ActionResponse response)
throws Exception
ModelAndView handleRenderRequest(javax.portlet.RenderRequest request,
javax.portlet.RenderResponse response)
throws Exception
这两个方法分别处理actionRequest 和renderReqeust.
有的人喜欢创建自己的Controller时实现上面这个超级抽象的Controller,这样行是行,但是Spring提供了一些具有某些功能的特殊Controller,继承这些有一定功能的控制器类,能避免你重复造车啊。
When using the AbstractController
as a baseclass for your controllers (which is not recommended since there are a lot of other controllers that might already do the job for you) you only have to override either the handleActionRequestInternal(ActionRequest, ActionResponse)
method or the handleRenderRequestInternal(RenderRequest, RenderResponse)
method (or both), implement your logic, and return a ModelAndView
object (in the case of handleRenderRequestInternal
).
ParameterizableViewController
的功能:
1. Render request is received by the controller
2. call to handleRenderRequestInternal which just returns the view, named by the configuration property viewName. Nothing more, nothing less
This controller does not handle action requests
PortletModeNameViewController
介绍:
Example: PortletMode.VIEW -> "view"
This controller does not handle action requests.
上面这些Controller都是微不足道的(trivial)的Controller.
18.4.3 Command Controllers
· AbstractCommandController
- a command controller you can use to create your own command controller, capable of binding request parameters to a data object you specify. This class does not offer form functionality, it does however offer validation features and lets you specify in the controller itself what to do with the command object that has been filled with the parameters from the request.
· AbstractFormController
- an abstract controller offering form submission support. Using this controller you can model forms and populate them using a command object you retrieve in the controller. After a user has filled the form, AbstractFormController
binds the fields, validates, and hands the object back to the controller to take appropriate action. Supported features are: invalid form submission (resubmission), validation, and normal form workflow. You implement methods to determine which views are used for form presentation and success. Use this controller if you need forms, but don't want to specify what views you're going to show the user in the application context.
· SimpleFormController
- a concrete AbstractFormController
that provides even more support when creating a form with a corresponding command object. The SimpleFormController
lets you specify a command object, a viewname for the form, a viewname for the page you want to show the user when form submission has succeeded, and more.
· AbstractWizardFormController
– a concrete AbstractFormController
that provides a wizard-style interface for editing the contents of a command object across multiple display pages. Supports multiple user actions: finish, cancel, or page change, all of which are easily specified in request parameters from the view.