25. Portlet MVC Framework
Portlet MVC框架
25.1 Introduction
引入
JSR-286 The Java Portlet Specification
For more general information about portlet development, please review the JSR-286 Specification itself.
关于prolet开发的更多信息,请参考JSR-286规范本身的内容。
In addition to supporting conventional (servlet-based) Web development, Spring also supports JSR-286 Portlet development. As much as possible, the Portlet MVC framework is a mirror image of the Web MVC framework, and also uses the same underlying view abstractions and integration technology. So, be sure to review the chapters entitled Chapter 22, Web MVC framework and Chapter 23, View technologies before continuing with this chapter.
此外方便支持(基于servlet)web开发,spring也支持JSR-286 Prolet开发。并且,Prolet的mvc框架是最小的web的mvc框架,并且使用了相同的视图抽象和集成技术。因此,为了回顾整个22章节,web的mvc框架和23章节,视图技术在这个章节开始之前。
[Note]
注意
Bear in mind that while the concepts of Spring MVC are the same in Spring Portlet MVC, there are some notable differences created by the unique workflow of JSR-286 portlets.
记住当spring的mvc的内容是和spring的prolet的mvc内容相同,有一些区别对于不同的JSR-286的prolet中的工作流。
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 is executed only once and is where any 'backend' changes or actions occur, such as making changes in a database. The render phase then 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. This provides (and requires) a clean separation between the activities that modify the persistent state of your system and the activities that generate what is displayed to the user.
主要的方式在prolet工作流中区别于Servlet的工作流是请求对于prolet可以有两个不同的阶段:行为阶段和解析阶段。行为阶段执行一旦任何后端的改变或行为发生例如改变了数据库。解析阶段每次展示给用户。这里的临界点是单个请求,行为阶段执行一次,但是解析阶段可以被执行多次。这提供了(并请求)一个区分和激活修改你系统目前的状态并且激活产生展示给用户。
Spring Web Flow
spring的web流
Spring Web Flow (SWF) aims to be the best solution for the management of web application page flow.
spring的web流目的是一个较好的解决方案用于管理web应用页面流。
SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and Portlet environments. If you have a business process (or processes) that would benefit from a conversational model as opposed to a purely request model, then SWF may be the solution.
SWF集成已有的框架例如spring的mvc和jsf,在Servlet和Porlet环境中。如果你有一个业务处理从方便的模型中收益相对于传统的请求模型,SWF可以是一种解决方案。
SWF allows you to capture logical page flows as self-contained modules that are reusable in different situations, and as such is ideal for building web application modules that guide the user through controlled navigations that drive business processes.
SWF允许你获得逻辑页面流作为容器模块本身可以在不同的环境中进行重用,并且这样对于构建web应用模块可以指导用户童虎控制导航来驱动业务处理。
For more information about SWF, consult the Spring Web Flow website.
关于更多有关SWF的信息,参考spring的web流网站。
The dual phases of portlet requests are one of the real strengths of the JSR-286 specification. For example, dynamic search results can be updated routinely on the display without the user explicitly rerunning the search. Most other portlet MVC frameworks attempt to completely hide the two phases from the developer and make it look as much like traditional servlet development as possible - we think this approach removes one of the main benefits of using portlets. So, the separation of the two phases is preserved throughout the Spring Portlet MVC framework. The primary manifestation of this approach is that where the servlet version of the MVC classes will have one method that deals with the request, the portlet version of the MVC classes will have two methods that deal with the request: one for the action phase and one for the render phase. For example, where the servlet version of AbstractController has the handleRequestInternal(..) method, the portlet version of AbstractController has handleActionRequestInternal(..) and handleRenderRequestInternal(..) methods.
prolet请求的两个阶段是JSR286规范中真实的之一。例如,动态的查找结果可以更新在显示中而不需要用户明确的返回查询。其他的porlet的mvc框架尝试完成隐藏两个阶段对于开发者并且使他看起来更像传统的Servlet开发————我们思考这种方式益处使用porlet的重要有时,两个阶段的分开是展现通过spring的porlet的mvc框架的。主要的表现关于这个方式是mvc类中Servlet的版本将有一个方法来处理请求,mvc类的porlet版本将有两个方法来处理请求,一个用于行为阶段并且另一个用于解析阶段。例如,AbstractController的Servlet版本有handleRequestInternal方法,AbstractController的porlet版本有handleActionRequestInternal和handleRenderRequestInternal方法。
The framework is designed around a DispatcherPortlet that dispatches requests to handlers, with configurable handler mappings and view resolution, just as the DispatcherServlet in the web framework does. File upload is also supported in the same way.
框架被设计围绕DispatcherPortlet并且分发请求给处理器,配置处理器匹配和视图解析,就像web框架中的DispatcherPortlet所作的。文件上传也支持以相同的方式。
Locale resolution and theme resolution are not supported in Portlet MVC - these areas are in the purview of the portal/portlet container and are not appropriate at the Spring level. However, all mechanisms in Spring that depend on the locale (such as internationalization of messages) will still function properly because DispatcherPortlet exposes the current locale in the same way as DispatcherServlet.
本地解析和这些解析不支持在Porlet的mvc中————这些区域是在portal或porlet容器的环境中是不适合在spring的级别的。然而,所有的spring的策略依赖于本地(例如消息的国际化)将依然有作用来暴露当前的位置以相同的方式作为DispatcherPortlet。
25.1.1 Controllers - The C in MVC
The default handler is still a very simple Controller interface, offering just two methods:
默认的处理器依然是一种简单的控制器接口,提供了两个方法:
void handleActionRequest(request,response)
ModelAndView handleRenderRequest(request,response)
The framework also includes most of the same controller implementation hierarchy, such as AbstractController, SimpleFormController, and so on. Data binding, command object usage, model handling, and view resolution are all the same as in the servlet framework.
框架包含大部分相同的控制器实现结构例如AbstractController、SimpleFormController等等。数据绑定,命令object的使用、模型处理和视图解析在Servlet框架中都是相同的。
25.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.
所有的视图解析能力对于Servlet框架被直接使用通过一个特定的桥Servlet名字为ViewRendererServlet。通过使用这个Servlet,porlet请求时方便转换为Servlet请求并且视图可以被解析使用整个普通的Servlet内容。这意味着所有的已有解析器,例如JSP、Velocity等等可以依然使用在porlet中。
25.1.3 Web-scoped beans
web范围的bean
Spring Portlet MVC supports beans whose lifecycle is scoped to the current HTTP request or HTTP Session (both normal and global). This is not a specific feature of Spring Portlet MVC itself, but rather of the WebApplicationContext container(s) that Spring Portlet MVC uses. These bean scopes are described in detail in Section 7.5.4, “Request, session, global session, application, and WebSocket scopes”
spring的porlet的mvc支持bean当生命周期的范围是当前的http请求或http会话(包括普通和全局)。这不是一个特性对于spring的porlet的mvc本事,而是WebApplicationContext容器使用通过spring的porlet的mvc。这些bean的范围被描述在章节7.5.4中,“请求、会话、全局会话、应用和websocket范围”
25.2 The DispatcherPortlet
Portlet MVC is a request-driven web MVC framework, designed around a portlet that dispatches requests to controllers and offers other functionality facilitating the development of portlet applications. Spring’s DispatcherPortlet however, does more than just that. It is completely integrated with the Spring ApplicationContext and allows you to use every other feature Spring has.
porlet的mvc是一个基于请求的web的mvc框架,设计围绕porlet分发请求给控制器并且提供其他的功能面向porlet应用的开发。spring的DispatcherPortlet。他集成的spring的应用上下文并且允许你使用任何spring的特性。
Like ordinary portlets, the DispatcherPortlet is declared in the portlet.xml file of your web application:
类似于普通porlet,DispatcherPortlet被定义在porlet.xml中对于你的web应用:
The DispatcherPortlet now needs to be configured.
DispatcherPortlet现在需要被配置。
In the Portlet MVC framework, each DispatcherPortlet has its own WebApplicationContext, which inherits all the beans already defined in the Root WebApplicationContext. These inherited beans can be overridden in the portlet-specific scope, and new scope-specific beans can be defined local to a given portlet instance.
在porlet的mvc框架中,每个DispatcherPortlet有自己的web应用上下文,继承了所有的bean定义在根的web应用上下文中。这些继承的bean可以被覆盖在特定的porlet范围并ie新的指定访问的bean可以被定义对于给定的porlet实例。
The framework will, on initialization of a DispatcherPortlet, look for a file named [portlet-name]-portlet.xml in the WEB-INF directory of your web application and create the beans defined there (overriding the definitions of any beans defined with the same name in the global scope).
框架将初始化DispatcherPortlet来查找文件名字为[portlet-name]-portlet.xml在web-inf目录中对于你的web应用并且创建bean定义这些(覆盖任何已经定义在全局范围的同名的bean)。
The config location used by the DispatcherPortlet can be modified through a portlet initialization parameter (see below for details).
这个配置使用通过DispatcherPortlet可以被修改通过porlet初始化参数(参照下面的细节)。
The Spring DispatcherPortlet has a few special beans it uses, in order to be able to process requests and render the appropriate views. These beans are included in the Spring framework and can be configured in the WebApplicationContext, just as any other bean would be configured. Each of those beans is described in more detail below. Right now, we’ll just mention them, just to let you know they exist and to enable us to go on talking about the DispatcherPortlet. For most of the beans, defaults are provided so you don’t have to worry about configuring them.
spring的DispatcherPortlet有一些特定的bean来使用,用于处理I给你求和解析适当的视图。这些bean是包含在spring的框架并且可以被配置在web应用上下文中,就像其他的bean的配置一样。每个这样的bean被描述在下面。我们将提到他们,让你知道他们的存在并且允许你来讨论DispatcherPortlet。对于大部分的bean是默认提供的因此你不需要考虑如何配置他们。
Table 25.1. Special beans in the WebApplicationContext
在WebApplicationContext中特殊的bean
Expression 表达式 |
Explanation 解释 |
handler mapping(s) |
(Section 25.5,“Handler mappings”) a list of pre- and post-processors and controllers that will be executed if they match certaincriteria(for instance a matching portlet mode specified with the controller) 前置和后置处理器和控制器将执行如果他匹配相应的条件(对于匹配porlet模式指定容器) |
controller(s) |
(Section 25.4,“Controllers”) the beans providing the actual functionality (or at least, access to the functionality) as part of the MVC triad 提供实际功能的beans(至少访问功能)作为MVC的一部分 |
view resolver |
(Section 25.6,“Views and resolving them”) capable of resolving view names to view definitions 对于视图定义解析视图名 |
multipart resolver |
(Section 25.7,“Multipart (file upload) support”) offers functionality to process file uploads from HTML forms 提供处理来自HTML表单的文件上传 |
handler exception resolver |
(Section 25.8,“Handling exceptions”) offers functionality to map exceptions to views or implement other more complex exception handling code 提供匹配异常对于视图或实现其他复杂的异常处理代码 |
When a DispatcherPortlet is setup for use and a request comes in for that specific DispatcherPortlet, it starts processing the request. The list below describes the complete process a request goes through if handled by a DispatcherPortlet:
当一个DispatcherPortlet被设置用于请求来自指定的DispatcherPortlet,他开始处理请求。下面的列表描述了全部的处理过程如果他们是通过DispatcherPortlet来处理的。
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.).
PortletRequest.getLocale()本地返回绑定到请求使得在处理中解析使用的位置信息当处理请求时(解析视图、预处理数据等等)。
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. (See Section 25.7,“Multipart (file upload) support”for further information about multipart handling).
如果一个multipart解析被定义并且是一个ActionRequest,请求会查找multiparts如果他们被找到,通过MultipartActionRequest来包裹对于后续的处理在过程的其他部分。(见章节25.7,“Multipart文件上传支持”来了解Multipart的处理部分)。
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.
一个适当的处理是查找。如果一个处理器被找到,执行链绑定处理器(前置处理、后置处理、控制器)将执行用于准备一个model。
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.
如果model被返回,视图被解析,使用视图解析器配置在WebApplicationContext中。如果没有model被返回(由于前置或后置处理器拦截了请求,例如处于安全的原因)没有视图被匹配,请求已经被受理了。
Exceptions that are thrown during processing of the request get picked up by any of the handler exception resolvers that are declared in the WebApplicationContext. Using these exception resolvers you can define custom behavior in case such exceptions get thrown.
异常被抛出在执行请求的过程中被定义在web上下文的异常处理器捕获解析。使用这些异常解析器你可以定义自定义行为当应用抛出异常之后。
You can customize Spring’s DispatcherPortlet by adding context parameters in the portlet.xml file or portlet init-parameters. The possibilities are listed below.
你可以自定义spring的DispatcherPortlet通过添加上下文参数在porlet.xml文件中或porlet的初始化参数中。可选的参数列表如下。
Table 25.2. DispatcherPortlet initialization parameters
DispatcherPortlet的初始化参数
Parameter 参数 |
Explanation 解释 |
contextClass |
Class that implements WebApplicationContext, which will be used to instantiate the context used by this portlet. If this parameter isn’t specified, the XmlPortletApplicationContext will be used. 类实现了WebApplicationContext将被使用用于实例化porlet使用的上下文。如果这个参数没有被指定,则将使用XmlPortletApplicationContext。 |
contextConfigLocation |
String which is passed to the context instance (specified by contextClass) to indicate where context(s) can be found. The String is potentially split up into multiple Strings (using a comma as a delimiter) to support multiple contexts (in case of multiple context locations, for beans that are defined twice, the latest takes precedence). 字符串传递给上下文实例(定义在上下文类中)来指定可以找到的上下文。字符串被分割成多个子串(使用逗号作为分隔)来支持多个上下文(用于多个上下文的位置,对于bean定义两次的以最后一次为准)。 |
namespace |
The namespace of the WebApplicationContext. Defaults to [portlet-name]-portlet. WebApplicationContext的命名空间。默认是[portlet-name]-portlet |
viewRendererUrl |
The URL at which DispatcherPortlet can access an instance of ViewRendererServlet (see Section 25.3,“The ViewRendererServlet”). DispatcherPortlet可以访问ViewRendererServlet实例的URL。(见章节25.3,“The ViewRendererServlet”) |
25.3 The ViewRendererServlet
The rendering process in Portlet MVC is a bit more complex than in Web MVC. In order to reuse all the view technologies from Spring Web MVC, we must convert the PortletRequest / PortletResponse to HttpServletRequest / HttpServletResponse and then call the render method of the View. To do this, DispatcherPortlet uses a special servlet that exists for just this purpose: the ViewRendererServlet.
解析程序在PorletMVC中是一个比web的mvc更复杂的。用于重用所有的视图技术来自spring的web的mvc,我们必须转换PortletRequest / PortletResponse为HttpServletRequest / HttpServletResponse并且调用解析视图的方法。为了这么做,DispatcherPortlet使用了一个特定的servlet来实现这个目的,就是ViewRendererServlet。
In order for DispatcherPortlet rendering to work, you must declare an instance of the ViewRendererServlet in the web.xml file for your web application as follows:
为了保证DispatcherPortlet解析可以工作,你必须定义一个ViewRendererServlet的实例在web.xml文件中用于你的web应用如下:
To perform the actual rendering, DispatcherPortlet does the following:
为了执行实际的解析,DispatcherPortlet是这么做的:
Binds the WebApplicationContext to the request as an attribute under the same WEB_APPLICATION_CONTEXT_ATTRIBUTE key that DispatcherServlet uses.
绑定WebApplicationContext对于请求作为一个属性定义在WEB_APPLICATION_CONTEXT_ATTRIBUTE为key中用于DispatcherServlet。
Binds the Model and View objects to the request to make them available to the ViewRendererServlet.
绑定model和view对于请求使得对于ViewRendererServlet可用。
Constructs a PortletRequestDispatcher and performs an include using the /WEB- INF/servlet/view URL that is mapped to the ViewRendererServlet.
构建一个PortletRequestDispatcher并且执行包含使用/WEB- INF/servlet/view的url来匹配ViewRendererServlet。
The ViewRendererServlet is then able to call the render method on the View with the appropriate arguments.
ViewRendererServlet可以调用系诶下方法对于视图配合适当的参数。
The actual URL for the ViewRendererServlet can be changed using DispatcherPortlet’s `viewRendererUrl configuration parameter.
实际的URL对于ViewRendererServlet可以被改变使用DispatcherPortlet’s `viewRendererUrl的配置参数。
25.4 Controllers
控制器
The controllers in Portlet MVC are very similar to the Web MVC Controllers, and porting code from one to the other should be simple.
porlet的mvc中的控制器是十分相似于web的mvc的控制器,并且移植了相应的代码使得简单。
The basis for the Portlet MVC controller architecture is the org.springframework.web.portlet.mvc.Controller interface, which is listed below.
对于porlet的mvc控制器是基础的使用org.springframework.web.portlet.mvc.Controller接口,列在下面。
public interface Controller {
/**
* Process the render request and return a ModelAndView object which the
* DispatcherPortlet will render.
*/
ModelAndView handleRenderRequest(RenderRequest request,
RenderResponse response) throws Exception;
/**
* Process the action request. There is nothing to return.
*/
void handleActionRequest(ActionRequest request,
ActionResponse response) throws Exception;
}
As you can see, the Portlet Controller interface requires two methods that handle the two phases of a portlet request: the action request and the render request. The action phase should be capable of handling an action request, and the render phase should be capable of handling a render request and returning an appropriate model and view. While the Controller interface is quite abstract, Spring Portlet MVC offers several controllers that already contain a lot of the functionality you might need; most of these are very similar to controllers from Spring Web MVC. The Controller interface just defines the most common functionality required of every controller: handling an action request, handling a render request, and returning a model and a view.
就如你看到的,porlet的控制器接口请求两个方法处理porlet请求的两个部分:行为请求和解析请求。行为部分应当处理行为请求并且解析部分应当处理解析请求并且返回适当的model和view。当控制器接口是抽象的,spring的porlet的mvc提供了多个控制器包含许多功能你可能会需要;大部分的功能和来自spring的web的mvc中的相似。控制器接口只是定义了相同的功能请求每个控制器,处理行为阶段请求,处理解析阶段请求和返回model和view。
25.4.1 AbstractController and PortletContentGenerator
Of course, just a Controller interface isn’t enough. To provide a basic infrastructure, all of Spring Portlet MVC’s Controllers inherit from AbstractController, a class offering access to Spring’s ApplicationContext and control over caching.
当然,只是一个控制器接口是不够的。为了提供基本的结构,所有的spring的porlet的mvc控制器继承了AbstractController,一类提供了访问对于spring的应用上下文和控制缓存。
Table 25.3. Features offered by the AbstractController
AbstractController提供的特性
Parameter 参数 |
Explanation 解释 |
requireSession |
Indicates whether or not this Controller requires a session to do its work. This feature is offered to all controllers. If a session is not present when such a controller receives a request, the user is informed using a SessionRequiredException. 指定控制器请求需要session来工作。这个特性被提供对于所有的控制器。如果一个session没有被表现当这样的控制器收到一个请求,用户会收到一个SessionRequiredException的异常。 |
synchronizeSession |
Use this if you want handling by this controller to be synchronized on the user’s session. To be more specific, the extending controller will override the handleRenderRequestInternal(..) and handleActionRequestInternal(..) methods, which will be synchronized on the user’s session if you specify this variable. 使用如果你需要处理这个控制器对于同步用户的session。更加具体一点,扩展的控制器将覆盖handleRenderRequestInternal和handleActionRequestInternal方法,将会同步用户的session如果你指定了这个变量。 |
renderWhenMinimized |
If you want your controller to actually render the view when the portlet is in a minimized state, set this to true. By default, this is set to false so that portlets that are in a minimized state don’t display any content. 如果你希望你的控制器对于实际的解析视图当porlet以最小的状态运行时,设置其为true。默认是false因此porlet最小状态运行时不会展示任何内容。 |
cacheSeconds |
When you want a controller to override the default cache expiration defined for the portlet, specify a positive integer here. By default it is set to -1, which does not change the default caching. Setting it to 0 will ensure the result is never cached. 当你希望控制器覆盖默认的缓存耗尽定义在porlet中,指定一个正数值。默认设置为负一,没有改变缓存。设置为零将保证结果不会被缓存。 |
The requireSession and cacheSeconds properties are declared on the PortletContentGenerator class, which is the superclass of AbstractController) but are included here for completeness.
requireSession和cacheSeconds属性别定义在PortletContentGenerator类中,是AbstractController的超类但是包含在这里是为了完整。
When using the AbstractController as a base class 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).
当使用AbstractController作为你的控制器的基类(不建议你使用许多的其他的控制器来为你工作)你只需要覆盖handleActionRequestInternal或handleRenderRequestInternal方法或者都覆盖来实现你的逻辑并且返回ModelAndView的object。
The default implementations of both handleActionRequestInternal(..) and handleRenderRequestInternal(..) throw a PortletException. This is consistent with the behavior of GenericPortlet from the JSR- 168 Specification API. So you only need to override the method that your controller is intended to handle.
handleActionRequestInternal和handleRenderRequestInternal的默认实现会抛出一个PortletException异常。这是一致的对于JSR168规范指定的API。因此你只需要覆盖定义在控制器中的方法来处理。
Here is short example consisting of a class and a declaration in the web application context.
这里是一个简短的例子包含一个类和定义在web的应用上下文中。
package samples;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.mvc.AbstractController;
import org.springframework.web.portlet.ModelAndView;
public class SampleController extends AbstractController {
public ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) {
ModelAndView mav = new ModelAndView("foo");
mav.addObject("message", "Hello World!");
return mav;
}
}
The class above and the declaration in the web application context is all you need besides setting up a handler mapping (see Section 25.5,“Handler mappings”) to get this very simple controller working.
上面的类和定义在web的应用上下文是你需要的设置处理器匹配(见章节25.5,“处理器匹配”)来获得十分简单的控制器。
25.4.2 Other simple controllers
其他简单的控制器
Although you can extend AbstractController, Spring Portlet MVC provides a number of concrete implementations which offer functionality that is commonly used in simple MVC applications.
尽管你可以继承AbstractController,spring的porlet的mvc提供了一系列专有的实现用于提供功能可以使用于简单的mvc应用中。
The ParameterizableViewController is basically the same as the example above, except for the fact that you can specify the view name that it will return in the web application context (no need to hard-code the view name).
ParameterizableViewController是基本的和上面的例子类似,除了实际你可以指定视图的名字将返回在web应用上下文呢(不需要硬编码视图名)。
The PortletModeNameViewController uses the current mode of the portlet as the view name. So, if your portlet is in View mode (i.e. PortletMode.VIEW) then it uses "view" as the view name.
PortletModeNameViewController使用当前的mode对于porlet作为视图名。因此,如果你的porlet是在View模型中(例如PortletMode.VIEW)使用了“view”作为视图名。
25.4.3 Command Controllers
命令控制器
Spring Portlet MVC has the exact same hierarchy of command controllers as Spring Web MVC. They provide a way to interact with data objects and dynamically bind parameters from the PortletRequest to the data object specified. Your data objects don’t have to implement a framework-specific interface, so you can directly manipulate your persistent objects if you desire. Let’s examine what command controllers are available, to get an overview of what you can do with them:
spring的porlet的mvc有相同的继承结构对于命令控制器用于spring的web的mvc中。他们提供了一个方式来作用于数据object并且动态的绑定参数来自PortletRequest对于数据object指定。你的数据object不需要实现框架指定的接口,因此你可以直接保持你的持久化object根据你的需要。让我们检查命令控制器根据需要,来了解你可以对他们做什么:
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.
AbstractCommandController————一个命令控制器你可以使用来创建你自己的命令控制器,可以绑定请求参数对于你指定的数据object。这个类不需要提供表单功能,他提哦给你了验证特性并且允许你指定在控制器本身关于如何处理命令object对于来自请求中的参数。
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.
AbstractFormController————一个抽象的控制器提供了提交的支持。使用这个控制器你可以模型化表单并且使用来自控制器的命令object。在用户填写表单,AbstractFormController绑定域、验证器和处理object对于控制器来采取适当的行动。支持特性是:验证提交、验证和正常的表单工作流。你实现方法来决定展现和成功时的视图。使用这个控制器如果你需要表单但是不希望指定你希望展示的视图在应用的上下文中。
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.
SimpleFormController————一个混合AbstractFormController提哦给你了支持当创建表单使用相应的命令object时。SimpleFormController允许你定义一个命令object,一个视图名对于表单、一个视图名对于你希望提交成功后展示的页面等等。
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.
AbstractWizardFormController————一个混合AbstractFormController提供了导航风格的接口用于编辑命令object的内容来访问多个展示页面。支持多个用户行为:完成、取消或页面转换,所有的都被简单定义在请求参数中用于视图。
These command controllers are quite powerful, but they do require a detailed understanding of how they operate in order to use them efficiently. Carefully review the javadocs for this entire hierarchy and then look at some sample implementations before you start using them.
这些命令控制器是很有用的,但是他们需要深层次的理解对于如何操作用于使得他们更加有效。检查javadocs对于整个结构并且进行简单的实现在你使用他们之前是有好处的。
25.4.4 PortletWrappingController
Instead of developing new controllers, it is possible to use existing portlets and map requests to them from a DispatcherPortlet. Using the PortletWrappingController, you can instantiate an existing Portlet as a Controller as follows:
为了开发新的控制器,可以使用已有的porlet和匹配请求对于他们来自DispatcherPortlet。使用PortletWrappingController,你可以使用一个已有的porlet控制器如下:
This can be very valuable since you can then use interceptors to pre-process and post-process requests going to these portlets. Since JSR-286 does not support any kind of filter mechanism, this is quite handy. For example, this can be used to wrap the Hibernate OpenSessionInViewInterceptor around a MyFaces JSF Portlet.
这可以十分有效当你可以使用拦截器对于前置处理和后置处理请求对于porlet。自从JSR286不支持任何种类的过滤器,这是十分便利的。例如,可以使用用于处理Hibernate的OpenSessionInViewInterceptor通过MyFaces的JSF的Porlet。
25.5 Handler mappings
处理器匹配
Using a handler mapping you can map incoming portlet requests to appropriate handlers. There are some handler mappings you can use out of the box, for example, the PortletModeHandlerMapping, but let’s first examine the general concept of a HandlerMapping.
使用一个处理器匹配你可以匹配输入porlet请求对于适当的处理器。有一些处理器匹配你可以使用,例如,PortletModeHandlerMapping,但是让我们首先检查HandlerMapping中通用的内容。
Note: We are intentionally using the term "Handler" here instead of "Controller". DispatcherPortlet is designed to be used with other ways to process requests than just Spring Portlet MVC’s own Controllers. A Handler is any Object that can handle portlet requests. Controllers are an example of Handlers, and they are of course the default. To use some other framework with DispatcherPortlet, a corresponding implementation of HandlerAdapter is all that is needed.
注意:我们使用Handler代替Controller。DispatcherPortlet被设计用于使用另一种方式来处理请求对于spring的mvc的控制器。一个Handler可以处理porlet请求。Controller是Handler的一个例子并且是默认的。为了使用其他的框架配合DispatcherPortlet,响应实现HandlerAdapter是有必要的。
The functionality a basic HandlerMapping provides is the delivering of a HandlerExecutionChain, which must contain the handler that matches the incoming request, and may also contain a list of handler interceptors that are applied to the request. When a request comes in, the DispatcherPortlet will hand it over to the handler mapping to let it inspect the request and come up with an appropriate HandlerExecutionChain. Then the DispatcherPortlet will execute the handler and interceptors in the chain (if any). These concepts are all exactly the same as in Spring Web MVC.
这是一个基本的处理器匹配对于HandlerExecutionChain的处理链,包含处理器匹配收到的请求并且可以包含一个拦截器的列表应用于请求。当收到一个请求,DispatcherPortlet将处理对应处理器匹配对于请求和适当的HandlerExecutionChain。然后DispatcherPortlet将执行handler在处理器链中。这些内容是和spring的mvc中是相同的。
The concept of configurable handler mappings that can optionally contain interceptors (executed before or after the actual handler was executed, or both) is extremely powerful. A lot of supporting functionality can be built into a custom HandlerMapping. Think of a custom handler mapping that chooses a handler not only based on the portlet mode of the request coming in, but also on a specific state of the session associated with the request.
可配置处理器匹配的内容是可选的包含拦截器(执行在实际的处理器执行的前后)是非常有用的。许多支持的功能可以构建进入自定义的处理匹配。考虑自定义处理器匹配选择处理器不是因为porlet的mode对于收到的请求,而是基于特定的状态对于请求中session的绑定。
In Spring Web MVC, handler mappings are commonly based on URLs. Since there is really no such thing as a URL within a Portlet, we must use other mechanisms to control mappings. The two most common are the portlet mode and a request parameter, but anything available to the portlet request can be used in a custom handler mapping.
在spring的web的mvc中,处理器匹配是基于URL的。真的没有这样使用URL配合porlet,我们必须使用其他的策略对于控制匹配。这两个和porlet模式是相同的和请求参数,但是任何适应于porlet请求可以使用以自定义的处理器匹配方式。
The rest of this section describes three of Spring Portlet MVC’s most commonly used handler mappings. They all extend AbstractHandlerMapping and share the following properties:
这个章节剩余的内容关于spring的porlet的mvc使用处理器匹配。他们都继承了AbstractHandlerMapping并且共享下面的属性:
interceptors: The list of interceptors to use. HandlerInterceptors are discussed in Section 25.5.4,“Adding HandlerInterceptors”.
interceptors:使用的拦截器列表。HandlerInterceptors将在章节25.5.4中讨论。“添加HandlerInterceptors”
defaultHandler: The default handler to use, when this handler mapping does not result in a matching handler.
defaultHandler:默认使用的处理器,这个处理器不匹配任何匹配的handler。
order: Based on the value of the order property (see the org.springframework.core.Ordered interface), Spring will sort all handler mappings available in the context and apply the first matching handler.
order:基于order属性的值(见org.springframework.core.Ordered接口),spring将排序所有上下文中可用的处理器匹配并且将其应用于第一个匹配的handler。
lazyInitHandlers: Allows for lazy initialization of singleton handlers (prototype handlers are always lazily initialized). Default value is false. This property is directly implemented in the three concrete Handlers.
lazyInitHandlers:允许单例handler的延迟加载(原型的handler是延迟加载的)。默认值是false。这个属性直接应用于混合的Handler。
25.5.1 PortletModeHandlerMapping
This is a simple handler mapping that maps incoming requests based on the current mode of the portlet (e.g. 'view', 'edit', 'help'). An example:
这是一个简单的处理器匹配用于匹配输入请求给予当前porlet的模式(例如view、edit、help)。一个案例:
25.5.2 ParameterHandlerMapping
If we need to navigate around to multiple controllers without changing portlet mode, the simplest way to do this is with a request parameter that is used as the key to control the mapping.
如果我们不需要多个处理器来改变porlet的mode,这最简单的方式对于请求参数使用key来控制匹配。
ParameterHandlerMapping uses the value of a specific request parameter to control the mapping. The default name of the parameter is 'action', but can be changed using the 'parameterName' property.
ParameterHandlerMapping使用特定的请求参数来控制匹配。默认的参数名是action,但是可以改变通过使用parameterName属性。
The bean configuration for this mapping will look something like this:
这个bean配置对于匹配可以是这样的:
25.5.3 PortletModeParameterHandlerMapping
The most powerful built-in handler mapping, PortletModeParameterHandlerMapping combines the capabilities of the two previous ones to allow different navigation within each portlet mode.
大部分有用的内置处理器匹配,PortletModeParameterHandlerMapping合并了两个之前的功能允许不同的导航对于每个porlet的web。
Again the default name of the parameter is "action", but can be changed using the parameterName property.
对于默认的参数名action,可以改变通过parameterName属性。
By default, the same parameter value may not be used in two different portlet modes. This is so that if the portal itself changes the portlet mode, the request will no longer be valid in the mapping. This behavior can be changed by setting the allowDupParameters property to true. However, this is not recommended.
默认的,简单参数值不能使用在两个不同的porlet模式。如果portal本身改变porlet的mode,请求将不会被验证在匹配中。这个行为可以被改变通过设置allowDupParameters属性为true。然而,这是不推荐的。
The bean configuration for this mapping will look something like this:
这个bean配置对于这个匹配看起来是这样的:
This mapping can be chained ahead of a PortletModeHandlerMapping, which can then provide defaults for each mode and an overall default as well.
这个匹配可以被放在PortletModeHandlerMapping之前,可以提供默认的对于每个模式并且覆盖默认的配置。
25.5.4 Adding HandlerInterceptors
添加HandlerInterceptors
Spring’s handler mapping mechanism has a notion of handler interceptors, which can be extremely useful when you want to apply specific functionality to certain requests, for example, checking for a principal. Again Spring Portlet MVC implements these concepts in the same way as Web MVC.
spring的处理器匹配策略有处理拦截器的概念,可以很有用当你希望应用特定的功能对于特定的请求,例如,检查原则。spring的porlet的mvc实现这些概念以相同的方式在web的mvc中。
Interceptors located in the handler mapping must implement HandlerInterceptor from the org.springframework.web.portlet package. Just like the servlet version, this interface defines three methods: one that will be called before the actual handler will be executed ( preHandle), one that will be called after the handler is executed ( postHandle), and one that is called after the complete request has finished ( afterCompletion). These three methods should provide enough flexibility to do all kinds of pre- and post- processing.
拦截器位于处理器匹配中必须实现HandlerInterceptor接口来自org.springframework.web.portlet包。就像servlet版本,这个接口定义三个方法:一个将调用在实际的处理器之前将执行,一个将被调用在handler执行之后,另一个整个请求完成之后执行。这三个方法听了足够的方便对于所有前置和后置的处理。
The preHandle method returns a boolean value. You can use this method to break or continue the processing of the execution chain. When this method returns true, the handler execution chain will continue. When it returns false, the DispatcherPortlet assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain.
preHandle方法返回一个boolean值。你可以使用这个方法来打断或继续执行链的处理。当这个方法返回true是,处理器执行将会继续。当他返回false时,DispatcherPortlet假定拦截器自身处理了请求(例如,解析了适当的视图)并且不需要继续执行其他的拦截和执行链中的实际的处理器。
The postHandle method is only called on a RenderRequest. The preHandle and afterCompletion methods are called on both an ActionRequest and a RenderRequest. If you need to execute logic in these methods for just one type of request, be sure to check what kind of request it is before processing it.
postHandle方法只能调用对于RenderRequest。preHandle和afterCompletion方法可以被调用对于ActionRequest和RenderRequest。如果你需要执行逻辑在这三个方法中用于某一种请求,保证检查相同种类的请求在执行之前。
25.5.5 HandlerInterceptorAdapter
As with the servlet package, the portlet package has a concrete implementation of HandlerInterceptor called HandlerInterceptorAdapter. This class has empty versions of all the methods so that you can inherit from this class and implement just one or two methods when that is all you need.
对于servlet包,porlet包有具体的实现对于HandlerInterceptor名字为HandlerInterceptorAdapter。这个类有一个空的版本号对于所有的方法你可以继承来自这个类并且实现了一个或两个你需要的方法。
25.5.6 ParameterMappingInterceptor
The portlet package also has a concrete interceptor named ParameterMappingInterceptor that is meant to be used directly with ParameterHandlerMapping and PortletModeParameterHandlerMapping. This interceptor will cause the parameter that is being used to control the mapping to be forwarded from an ActionRequest to the subsequent RenderRequest. This will help ensure that the RenderRequest is mapped to the same Handler as the ActionRequest. This is done in the preHandle method of the interceptor, so you can still modify the parameter value in your handler to change where the RenderRequest will be mapped.
porlet包有一个拦截器名字为ParameterMappingInterceptor可直接适用于ParameterHandlerMapping和PortletModeParameterHandlerMapping。这个拦截器将导致参数被使用来控制匹配对于ActionRequest的转发和RenderRequest的处理。这将用于保证RenderRequest匹配相同的Handler作为ActionRequest。实现在拦截器的preHandle方法中,因此你依然可以修改参数值在你的处理器中来改变将被匹配的RenderRequest。
Be aware that this interceptor is calling setRenderParameter on the ActionResponse, which means that you cannot call sendRedirect in your handler when using this interceptor. If you need to do external redirects then you will either need to forward the mapping parameter manually or write a different interceptor to handle this for you.
注意拦截器调用ActionResponse中的setRenderParameter,意味着你不能调用sendRedirect在你的handler中当你使用拦截器的时候。如果你需要执行额外的转发你需要转发手动匹配参数或写一个不同的拦截器来帮你处理。
25.6 Views and resolving them
视图和处理他们
As mentioned previously, Spring Portlet MVC directly reuses all the view technologies from Spring Web MVC. This includes not only the various View implementations themselves, but also the ViewResolver implementations. For more information, refer to Chapter 23, View technologies and Section 22.5, “Resolving views”respectively.
在之前提到过,spring的porlet的mvc直接使用所有来自spring的web的mvc的视图技术。这个包括不同的视图实现本身,以及ViewResolver实现。关于更多的信息,参考章节23视图技术和章节22.5处理视图。
A few items on using the existing View and ViewResolver implementations are worth mentioning:
一些项目使用已有的视图和ViewResolver实现:
Most portals expect the result of rendering a portlet to be an HTML fragment. So, things like JSP/JSTL, Velocity, FreeMarker, and XSLT all make sense. But it is unlikely that views that return other document types will make any sense in a portlet context.
大部分porlet期望解析porlet为html为结果。因此类似于JSP/JSTL、Velocity、FreeMarker和XSLT都可以。但是不像视图返回其他的文档类型将使用于porlet上下文中。
There is no such thing as an HTTP redirect from within a portlet (the sendRedirect(..) method of ActionResponse cannot be used to stay within the portal). So, RedirectView and use of the 'redirect:' prefix will not work correctly from within Portlet MVC.
作为http转发来自porlet是不存在的(sendRedirect方法来自ActionResponse不能用于配合portal)。因此,RedirectView和redirect:前缀的使用将不能直接用于porlet的mvc中。
It may be possible to use the 'forward:' prefix from within Portlet MVC. However, remember that since you are in a portlet, you have no idea what the current URL looks like. This means you cannot use a relative URL to access other resources in your web application and that you will have to use an absolute URL.
可以使用forward:前缀对于porlet的mvc。然而,记住你在porlet中,你没有其他的方案对于当前的URL中。这意味着你不能使用相对的URL来访问其他的资源在你的应用中并且你将使用绝对的URL。
Also, for JSP development, the new Spring Taglib and the new Spring Form Taglib both work in portlet views in exactly the same way that they work in servlet views.
并且,对于JSP开发,新的spring的标签库和新的spring表单标签库都可以用于porlet视图中以相同的方式工作与Servlet视图中。
25.7 Multipart (file upload) support
多部分(文件上传)的支持
Spring Portlet MVC has built-in multipart support to handle file uploads in portlet applications, just like Web MVC does. The design for the multipart support is done with pluggable PortletMultipartResolver objects, defined in the org.springframework.web.portlet.multipart package. Spring provides a PortletMultipartResolver for use with Commons FileUpload. How uploading files is supported will be described in the rest of this section.
spring的porlet的mvc有内置的多部分支持用于处理文件上传在porlet应用中,类似于web的mvc所做的。这个设计对于多部分支持是通过PortletMultipartResolver的object插件完成的,定义在org.springframework.web.portlet.multipart包中。spring提供了PortletMultipartResolver用于普通的文件上传。然而上传文件的支持将在这个章节后续的部分中描述。
By default, no multipart handling will be done by Spring Portlet MVC, as some developers will want to handle multiparts themselves. You will have to enable it yourself by adding a multipart resolver to the web application’s context. After you have done that, DispatcherPortlet will inspect each request to see if it contains a multipart. If no multipart is found, the request will continue as expected. However, if a multipart is found in the request, the PortletMultipartResolver that has been declared in your context will be used. After that, the multipart attribute in your request will be treated like any other attribute.
默认的,没有多部分处理通过spring的porlet的mvc,作为一些开发者将希望有处理多部分本身。你将被允许如果你添加了多部分处理对于web应用的上下文中。在你完成这些以后,DispatcherPortlet将处理每个请求如果每个请求中包含多部分。如果没有多部分被找到,请求将包含其他需要的内容。然而如果一个多不部分被找到在请求中,PortletMultipartResolver定义在你的上下文中用于使用。之后,多部分属性在你的请求中将被处理类似于其他的属性。
[Note]
注意
Any configured PortletMultipartResolver bean must have the following id (or name): " portletMultipartResolver`". If you have defined your `PortletMultipartResolver with any other name, then the DispatcherPortlet will not find your PortletMultipartResolver, and consequently no multipart support will be in effect.
任何配置PortletMultipartResolver的bean有下面的id或name:portletMultipartResolver。如果你定义你的PortletMultipartResolver使用了其他的名字,DispatcherPortlet将不会找到你的PortletMultipartResolver并且因此没有多部分实际被支持。
25.7.1 Using the PortletMultipartResolver
使用PortletMultipartResolver
The following example shows how to use the CommonsPortletMultipartResolver:
下面的例子展示了如何使用CommonsPortletMultipartResolver:
class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver">
Of course you also need to put the appropriate jars in your classpath for the multipart resolver to work. In the case of the CommonsMultipartResolver, you need to use commons-fileupload.jar. Be sure to use at least version 1.1 of Commons FileUpload as previous versions do not support JSR-286 Portlet applications.
当然你需要放入适当的jar在你的classpath中对于多部分解析来使得其工作。对于CommonsMultipartResolver的例子,你需要使用commons-fileupload.jar文件。保证使用不低于1.1的版本对于通用的文件上传对于之前的版本不支持JSR286的porlet应用。
Now that you have seen how to set Portlet MVC up to handle multipart requests, let’s talk about how to actually use it. When DispatcherPortlet detects a multipart request, it activates the resolver that has been declared in your context and hands over the request. What the resolver then does is wrap the current ActionRequest in a MultipartActionRequest that has support for multipart file uploads. Using the MultipartActionRequest you can get information about the multiparts contained by this request and actually get access to the multipart files themselves in your controllers.
你如何设置porlet的mvc来处理多部分请求,让我们讨论一下如何使用它。当DispatcherPortlet发现一个多部分的请求,他激活解析器定义在你的上下文中并且处理请求。之前是怎么做的,包括在MultipartActionRequest中当前的ActionRequest来支持文件上传。使用MultipartActionRequest你可以获得信息来自多部分包含请求并且实际获得访问对于多部分文件本身在你们的控制器中。
Note that you can only receive multipart file uploads as part of an ActionRequest, not as part of a RenderRequest.
注意你只是收到的多部分文件上传作为ActionRequest的一部分,而是RenderRequest的一部分。
25.7.2 Handling a file upload in a form
处理表单中的文件上传
After the PortletMultipartResolver has finished doing its job, the request will be processed like any other. To use the PortletMultipartResolver, create a form with an upload field (see example below), then let Spring bind the file onto your form (backing object). To actually let the user upload a file, we have to create a (JSP/HTML) form:
在PortletMultipartResolver完成他的工作之后,请求将被处理和其他的请求一样。为了使用PortletMultipartResolver,创建一个表单包含一个上传域(见下面的例子),让spring绑定文件对于你的表单(包括object)。用户上传一个文件,我们创建一个JSP/HTML表单。
As you can see, we’ve created a field named "file" that matches the property of the bean that holds the byte[] array. Furthermore we’ve added the encoding attribute ( enctype="multipart/form-data"), which is necessary to let the browser know how to encode the multipart fields (do not forget this!).
由于你看淡的,我们将创建一个域名字为file用于匹配bean的属性包含byte数组。此外我们添加编码属性( enctype="multipart/form-data"),是必要的对于浏览器知道如何编码多部分于(不要忘记)。
Just as with any other property that’s not automagically convertible to a string or primitive type, to be able to put binary data in your objects you have to register a custom editor with the PortletRequestDataBinder. There are a couple of editors available for handling files and setting the results on an object. There’s a StringMultipartFileEditor capable of converting files to Strings (using a user-defined character set), and there is a ByteArrayMultipartFileEditor which converts files to byte arrays. They function analogous to the CustomDateEditor.
就像其他的属性没有自动转换为字符串或基本类型,可以放入二进制数在你的object中注册自定义编辑器使用PortletRequestDataBinder。这是一些可用的编辑器对于处理文件和设置object的结果。这是StringMultipartFileEditor可以转换文件为字符串(使用一个用户自定义的字符集)并且ByteArrayMultipartFileEditor转换文件为字节数组。这些方法类似于CustomDateEditor。
So, to be able to upload files using a form, declare the resolver, a mapping to a controller that will process the bean, and the controller itself.
因此,为了可以上传文件使用表单,定义解析器,匹配容器将处理bean和控制器本身。
class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver"/>
After that, create the controller and the actual class to hold the file property.
在此之后,创建控制器和实际的类来处理文件属性。
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
byte[] file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
protected void initBinder(PortletRequest request,
PortletRequestDataBinder binder) throws Exception {
// to actually be able to convert Multipart instance to byte[]
// we have to register a custom editor
binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
// now Spring knows how to handle multipart object and convert
}
}
public class FileUploadBean {
private byte[] file;
public void setFile(byte[] file) {
this.file = file;
}
public byte[] getFile() {
return file;
}
}
As you can see, the FileUploadBean has a property of type byte[] that holds the file. The controller registers a custom editor to let Spring know how to actually convert the multipart objects the resolver has found to properties specified by the bean. In this example, nothing is done with the byte[] property of the bean itself, but in practice you can do whatever you want (save it in a database, mail it to somebody, etc).
可见,FileUploadBean有一个byte数组类型的属性来保存文件。控制器注册自定义编辑器使得spring知道如何实际转换多部分的object解析对于定义在bean中的属性。在这个例子中,bean本身的字节数组你可以获取(保存到数据库、邮件给其他人等等)。
An equivalent example in which a file is bound straight to a String-typed property on a form backing object might look like this:
一个类似的例子对于斍是直接绑定到字符串类型的属性中对于表单对应的object看起来是这样的:
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
String file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
protected void initBinder(PortletRequest request,
PortletRequestDataBinder binder) throws Exception {
// to actually be able to convert Multipart instance to a String
// we have to register a custom editor
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
// now Spring knows how to handle multipart objects and convert
}
}
public class FileUploadBean {
private String file;
public void setFile(String file) {
this.file = file;
}
public String getFile() {
return file;
}
}
Of course, this last example only makes (logical) sense in the context of uploading a plain text file (it wouldn’t work so well in the case of uploading an image file).
当然,最后的例子只是关注于上传的上下文对于普通的文本文件(他不支持图片文件的上传)。
The third (and final) option is where one binds directly to a MultipartFile property declared on the (form backing) object’s class. In this case one does not need to register any custom property editor because there is no type conversion to be performed.
第三个(或最终的)选择是直接绑定MultipartFile属性定义域object的类中。在这个例子中可以不需要注册任何自定义属性编辑器因为没有类型转换被执行。
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
MultipartFile file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
}
public class FileUploadBean {
private MultipartFile file;
public void setFile(MultipartFile file) {
this.file = file;
}
public MultipartFile getFile() {
return file;
}
}
25.8 Handling exceptions
异常处理
Just like Servlet MVC, Portlet MVC provides HandlerExceptionResolvers to ease the pain of unexpected exceptions that occur while your request is being processed by a handler that matched the request. Portlet MVC also provides a portlet-specific, concrete SimpleMappingExceptionResolver that enables you to take the class name of any exception that might be thrown and map it to a view name.
类似于Servlet的mvc,porlet的mvc提供了HandlerExceptionResolvers用于减少异常发生在你请求被处理通过一个处理器来匹配一个请求。porlet的mvc也提供了特定的porlet关注于SimpleMappingExceptionResolver允许你使用任何异常类的名字可以被抛出匹配一个视图名。
25.9 Annotation-based controller configuration
基于注解的配置
Spring 2.5 introduced an annotation-based programming model for MVC controllers, using annotations such as @RequestMapping, @RequestParam, @ModelAttribute, etc. This annotation support is available for both Servlet MVC and Portlet MVC. Controllers implemented in this style do not have to extend specific base classes or implement specific interfaces. Furthermore, they do not usually have direct dependencies on Servlet or Portlet API’s, although they can easily get access to Servlet or Portlet facilities if desired.
spring2.5引入了基于注解的编程模型用于mvc的控制器,使用了注解类似于@RequestMapping、@RequestParam、@ModelAttribute等等。这些注解也支持Servlet的mvc和porlet的mvc。控制器实现不需要继承特定的基类或实现特定的接口。此外,不需要直接依赖于Servlet或porlet的API,尽管他们可以简单的访问Servlet或porlet根据需要。
The following sections document these annotations and how they are most commonly used in a Portlet environment.
下面章节的文档描述了这些注解以及通常的用法在porlet的环境中。
25.9.1 Setting up the dispatcher for annotation support
设置分发器用于注解支持
`@RequestMapping` will only be processed if a corresponding HandlerMapping (for type level annotations) and/or HandlerAdapter (for method level annotations) is present in the dispatcher. This is the case by default in both DispatcherServlet and DispatcherPortlet.
@RequestMapping只能被处理如果相应的HandlerMapping和HandlerAdapter出现在dispatcher中。这是默认的在DispatcherServlet和DispatcherPortlet中。
However, if you are defining custom HandlerMappings or HandlerAdapters, then you need to make sure that a corresponding custom DefaultAnnotationHandlerMapping and/or AnnotationMethodHandlerAdapter is defined as well - provided that you intend to use @RequestMapping.
然而,如果你定义了自定义的HandlerMappings或HandlerAdapters,你需要保证相应的自定义DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter也被定义了————提供给你用于使用@RequestMapping。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> // ... (controller bean definitions) ...
Defining a DefaultAnnotationHandlerMapping and/or AnnotationMethodHandlerAdapter explicitly also makes sense if you would like to customize the mapping strategy, e.g. specifying a custom WebBindingInitializer (see below).
明确定义DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter是有用的如果你希望自定义匹配策略,例如,指定一个自定义的WebBindingInitializer(如下)。
25.9.2 Defining a controller with @Controller
使用@Controller定义一个控制器
The @Controller annotation indicates that a particular class serves the role of a controller. There is no need to extend any controller base class or reference the Portlet API. You are of course still able to reference Portlet-specific features if you need to.
@Controller注解指定了特定的类用于控制器的角色。不需要继承任何控制器基类或应用porlet的api。你可以使用引用指定的porlet特性如果你需要的话。
The basic purpose of the @Controller annotation is to act as a stereotype for the annotated class, indicating its role. The dispatcher will scan such annotated classes for mapped methods, detecting @RequestMapping annotations (see the next section).
@Controller注解的基本目的是扮演一个注解类的角色,指定他的位置。dispatcher将扫描这样的注解类对于匹配方法,找到@RequestMapping注解(见后面的章节)。
Annotated controller beans may be defined explicitly, using a standard Spring bean definition in the dispatcher’s context. However, the @Controller stereotype also allows for autodetection, aligned with Spring 2.5’s general support for detecting component classes in the classpath and auto-registering bean definitions for them.
注解控制器的bean可以明确指定,使用一个标准的spring的bean定义在dispatcher的上下文中。然而,@Controller策略也允许自动探测,配合spring2.5的通用支持用于探测组件类在classpath中并且自动注册bean定义。
To enable autodetection of such annotated controllers, you have to add component scanning to your configuration. This is easily achieved by using the spring-context schema as shown in the following XML snippet:
为了启用这样注解控制器的自动探测,你需要添加组件扫描在你的控制器中。这可以简单的通过spring-context来实现展示在下面的xml片段中:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> // ...
25.9.3 Mapping requests with @RequestMapping
使用@RenderMapping匹配请求
The @RequestMapping annotation is used to map portlet modes like 'VIEW'/'EDIT' onto an entire class or a particular handler method. Typically the type-level annotation maps a specific mode (or mode plus parameter condition) onto a form controller, with additional method-level annotations 'narrowing' the primary mapping for specific portlet request parameters.
@RenderMapping注解被使用用于匹配porlet模式例如'VIEW'/'EDIT'对于整个类或一个特定的处理器方法。通常类型级别的注解匹配特定的模型(或模式加参数条件)对于表单控制器,使用额外的方法级别的注解来缩小主匹配对于特定的porlet请求参数。
[Tip]
提示
@RequestMapping at the type level may be used for plain implementations of the Controller interface as well. In this case, the request processing code would follow the traditional handle(Action|Render)Request signature, while the controller’s mapping would be expressed through an @RequestMapping annotation. This works for pre-built Controller base classes, such as SimpleFormController, too.
@RenderMapping在类型级别可以使用普通的实现对于控制器实例。在这个例子中,请求处理代码可以符合传统的处理请求方法,控制器的匹配将通过@RenderMapping来表现。这适用于之前构建的控制器基类,例如SimpleFormController。
In the following discussion, we’ll focus on controllers that are based on annotated handler methods.
在下面的讨论中,我们关注控制器给予注解处理方法。
The following is an example of a form controller from the PetPortal sample application using this annotation:
下面是一个例子关于表单控制器来自PetPortal的样例应用使用注解:
@Controller
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
private Properties petSites;
public void setPetSites(Properties petSites) {
this.petSites = petSites;
}
@ModelAttribute("petSites")
public Properties getPetSites() {
return this.petSites;
}
@RequestMapping // default (action=list)
public String showPetSites() {
return "petSitesEdit";
}
@RequestMapping(params = "action=add") // render phase
public String showSiteForm(Model model) {
// Used for the initial form as well as for redisplaying with errors.
if (!model.containsAttribute("site")) {
model.addAttribute("site", new PetSite());
}
return "petSitesAdd";
}
@RequestMapping(params = "action=add") // action phase
public void populateSite(@ModelAttribute("site") PetSite petSite,
BindingResult result, SessionStatus status, ActionResponse response) {
new PetSiteValidator().validate(petSite, result);
if (!result.hasErrors()) {
this.petSites.put(petSite.getName(), petSite.getUrl());
status.setComplete();
response.setRenderParameter("action", "list");
}
}
@RequestMapping(params = "action=delete")
public void removeSite(@RequestParam("site") String site, ActionResponse response) {
this.petSites.remove(site);
response.setRenderParameter("action", "list");
}
}
As of Spring 3.0, there are dedicated @ActionMapping and @RenderMapping (as well as @ResourceMapping and @EventMapping) annotations which can be used instead:
由于spring的3.0,引入了@ActionMapping和@RenderMapping(类似于@ResourceMapping和@EventMapping)注解可以作为代替使用如下:
@Controller
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
private Properties petSites;
public void setPetSites(Properties petSites) {
this.petSites = petSites;
}
@ModelAttribute("petSites")
public Properties getPetSites() {
return this.petSites;
}
@RenderMapping // default (action=list)
public String showPetSites() {
return "petSitesEdit";
}
@RenderMapping(params = "action=add")
public String showSiteForm(Model model) {
// Used for the initial form as well as for redisplaying with errors.
if (!model.containsAttribute("site")) {
model.addAttribute("site", new PetSite());
}
return "petSitesAdd";
}
@ActionMapping(params = "action=add")
public void populateSite(@ModelAttribute("site") PetSite petSite,
BindingResult result, SessionStatus status, ActionResponse response) {
new PetSiteValidator().validate(petSite, result);
if (!result.hasErrors()) {
this.petSites.put(petSite.getName(), petSite.getUrl());
status.setComplete();
response.setRenderParameter("action", "list");
}
}
@ActionMapping(params = "action=delete")
public void removeSite(@RequestParam("site") String site, ActionResponse response) {
this.petSites.remove(site);
response.setRenderParameter("action", "list");
}
}
25.9.4 Supported handler method arguments
支持处理方法参数
Handler methods which are annotated with @RequestMapping are allowed to have very flexible signatures. They may have arguments of the following types, in arbitrary order (except for validation results, which need to follow right after the corresponding command object, if desired):
处理方法被注解使用@RequestMapping允许有方便的签名。他们可以实现下面类型的参数,以任意的属性(尤其是验证结果,需要下面匹配相应的命令object根据需要):
Request and/or response objects (Portlet API). You may choose any specific request/response type, e.g. PortletRequest / ActionRequest / RenderRequest. An explicitly declared action/render argument is also used for mapping specific request types onto a handler method (in case of no other information given that differentiates between action and render requests).
请求或响应object。你可以选择任何指定的请求或响应类型例如PortletRequest / ActionRequest / RenderRequest。一个明确的行为和处理参数也可以使用用于匹配特定的请求类型对于处理器方法(不需要其他的信息给定不同的行为和处理请求)。
Session object (Portlet API): of type PortletSession. An argument of this type will enforce the presence of a corresponding session. As a consequence, such an argument will never be null.
会话object:类型是PortletSession。这个类型的参数将强制表现相应的会话。因此,这样的参数应该为null。
org.springframework.web.context.request.WebRequest or org.springframework.web.context.request.NativeWebRequest. Allows for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API.
允许通用的请求参数访问请求或会话属性,而不需要绑定到本地的Servlet或porlet的API中。
java.util.Locale for the current request locale (the portal locale in a Portlet environment).
java.util.Locale用于当前请求的位置
java.util.TimeZone / java.time.ZoneId for the current request time zone.
java.util.TimeZone / java.time.ZoneId用于当前请求的时区。
java.io.InputStream / java.io.Reader for access to the request’s content. This will be the raw InputStream/Reader as exposed by the Portlet API.
java.io.InputStream / java.io.Reader用于访问请求上下文。这是一个普通的InputStream/Reader用于porlet的api中。
java.io.OutputStream / java.io.Writer for generating the response’s content. This will be the raw OutputStream/Writer as exposed by the Portlet API.
java.io.OutputStream / java.io.Writer用于生成响应内容。将是一个普通的OutputStream/Writer用于porlet的api中。
@RequestParam annotated parameters for access to specific Portlet request parameters. Parameter values will be converted to the declared method argument type.
@RequestParam注解参数用于访问指定的porlet的请求参数。参数值将被转换为定义方法参数类型。
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap for enriching the implicit model that will be exposed to the web view.
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap用于整个模型暴露给web视图。
Command/form objects to bind parameters to: as bean properties or fields, with customizable type conversion, depending on @InitBinder methods and/or the HandlerAdapter configuration - see the " webBindingInitializer`" property on `AnnotationMethodHandlerAdapter. Such command objects along with their validation results will be exposed as model attributes, by default using the non-qualified command class name in property notation (e.g. "orderAddress" for type "mypackage.OrderAddress"). Specify a parameter-level ModelAttribute annotation for declaring a specific model attribute name.
命令或表单object绑定参数:作为bean属性或域,自定义类型转换,依赖@InitBinder方法或HandlerAdapter的配置————见webBindingInitializer属性对于AnnotationMethodHandlerAdapter。这样的方法object允许验证结果暴露于模型属性,通过默认使用不合格的命令类名在属性中。(例如,orderAddress用于mypackage.OrderAddress类型)。指定一个参数级别的ModelAttribute注解用于定义指定的模型属性名。
org.springframework.validation.Errors / org.springframework.validation.BindingResult validation results for a preceding command/form object (the immediate preceding argument).
org.springframework.validation.Errors / org.springframework.validation.BindingResult验证结果用于处理命令或表单object。
org.springframework.web.bind.support.SessionStatus status handle for marking form processing as complete (triggering the cleanup of session attributes that have been indicated by the @SessionAttributes annotation at the handler type level).
org.springframework.web.bind.support.SessionStatus状态用于标记完整处理(清理会话属性指定通过@SessionAttributes注解在处理类型级别)。
The following return types are supported for handler methods:
下面返回类型是支持处理方法:
A ModelAndView object, with the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
ModelAndView,包含明确的model对于命令object和@ModelAttribute注解应用数据访问方法。
A Model object, with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
Model的object,视图名明确决定通过RequestToViewNameTranslator并且model明确指定了命令object和@ModelAttribute注解引用数据访问方法的结果。
A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
Map的object用于暴露一个model,包含视图名明确定义通过RequestToViewNameTranslator和模型明确包含命令object和@ModelAttribute的引用数据访问方法的结果。
A View object, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
视图object,model明确指定通过命令object和@ModelAttribute注解引用数据访问方法。处理器方法可以编程整个模型定义一个Model参数。
A String value which is interpreted as view name, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
字符串来作为一个视图名,model明确决定通过命令object并且@ModelAttribute注解引用数据访问方法。处理器方法可以编程整个模型定义一个Model参数。
void if the method handles the response itself (e.g. by writing the response content directly).
void如果方法处理响应本身(例如直接输出响应内容流)
Any other return type will be considered a single model attribute to be exposed to the view, using the attribute name specified through @ModelAttribute at the method level (or the default attribute name based on the return type’s class name otherwise). The model will be implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
任何其他类型将被任何是一个单一的model属性需要展示给视图,使用属性名指定通过@ModelAttribute在方法级别(或默认的属性名基于返回类类名)。model将明确指定命令object和@ModelAttribute注解引用数据访问方法的结果。
25.9.5 Binding request parameters to method parameters with @RequestParam
绑定请求参数对于方法参数通过@RequestParam
The @RequestParam annotation is used to bind request parameters to a method parameter in your controller.
@RequestParam注解被使用用于绑定请求参数对于方法参数在你的控制器中。
The following code snippet from the PetPortal sample application shows the usage:
下面的代码片段来自PetPortal简单的应用展示了使用的方法。
@Controller
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
// ...
public void removeSite(@RequestParam("site") String site, ActionResponse response) {
this.petSites.remove(site);
response.setRenderParameter("action", "list");
}
// ...
}
Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting @RequestParam’s `required attribute to false (e.g., @RequestParam(name="id", required=false)).
参数使用这个注解要求是默认的,但是你可以指定参数是可选的通过设置@RequestParam的required属性为false。(例如,@RequestParam(name="id", required=false))。
25.9.6 Providing a link to data from the model with @ModelAttribute
提供一个连接来自model使用@ModelAttribute注解
@ModelAttribute has two usage scenarios in controllers. When placed on a method parameter, @ModelAttribute is used to map a model attribute to the specific, annotated method parameter (see the populateSite() method below). This is how the controller gets a reference to the object holding the data entered in the form. In addition, the parameter can be declared as the specific type of the form backing object rather than as a generic java.lang.Object, thus increasing type safety.
@ModelAttribute有两种用法在控制器中。当处理方法参数,@ModelAttribute被使用用于指定匹配一个model属性,注解方法参数(见下面的populateSite方法)。这是如何使用控制器获得一个引用对于object保存在数据对于表单中。此外,蚕食可以被定义作为制定的表单object类型而不是通用的java.lang.Object,是类型安全的。
@ModelAttribute is also used at the method level to provide reference data for the model (see the getPetSites() method below). For this usage the method signature can contain the same types as documented above for the @RequestMapping annotation.
@ModelAttribute也可以用于方法级别来提供引用数据对于model(见下面的getPetSites方法)。对于这种使用于方法签名可以包含相同的类型对于@RequestMapping注解。
[Note]
注意
@ModelAttribute annotated methods will be executed before the chosen @RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through @ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.
@ModelAttribute注解方法将被指定在@RequestMapping注解处理器方法之前。他可以有效的处理model对于特定的属性,提供加载数据库。这样的属性可以直接访问通过@ModelAttribute注解处理器方法参数在选择处理器方法中,绑定验证。
The following code snippet shows these two usages of this annotation:
下面的代码片段展示了这两种注解的使用:
@Controller
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
// ...
@ModelAttribute("petSites")
public Properties getPetSites() {
return this.petSites;
}
@RequestMapping(params = "action=add") // action phase
public void populateSite( @ModelAttribute("site") PetSite petSite, BindingResult result, SessionStatus status, ActionResponse response) {
new PetSiteValidator().validate(petSite, result);
if (!result.hasErrors()) {
this.petSites.put(petSite.getName(), petSite.getUrl());
status.setComplete();
response.setRenderParameter("action", "list");
}
}
}
25.9.7 Specifying attributes to store in a Session with @SessionAttributes
指定属性用于存储在会话中通过@SessionAttributes
The type-level @SessionAttributes annotation declares session attributes used by a specific handler. This will typically list the names of model attributes or types of model attributes which should be transparently stored in the session or some conversational storage, serving as form-backing beans between subsequent requests.
类型级别的@SessionAttributes注解定义了会话属性使用特定的处理器。这通常列出了model属性的名字或model属性的类型应当被显示存储在会话或一些方便的存储,作为表单bean在请求中。
The following code snippet shows the usage of this annotation:
下面的代码片段展示了这个注解的使用方法:
@Controller
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
// ...
}
25.9.8 Customizing WebDataBinder initialization
自定义WebDataBinder初始化
To customize request parameter binding with PropertyEditors, etc. via Spring’s WebDataBinder, you can either use @InitBinder-annotated methods within your controller or externalize your configuration by providing a custom WebBindingInitializer.
为了自定义请求参数绑定对于PropertyEditors等等通过spring的WebDataBinder,你可以使用@InitBinder-annotated方法在你的控制器中或具体化你的配置通过提供自定义的WebBindingInitializer。
Customizing data binding with @InitBinder
使用@InitBinder自定义数据绑定
Annotating controller methods with @InitBinder allows you to configure web data binding directly within your controller class. @InitBinder identifies methods which initialize the WebDataBinder which will be used for populating command and form object arguments of annotated handler methods.
注解控制器使用@InitBinder允许你配置web数据绑定直接应用于你的控制器类。@InitBinder定义方法初始化WebDataBinder将使用于暴露命令和表单object参数对于注解处理器方法。
Such init-binder methods support all arguments that @RequestMapping supports, except for command/form objects and corresponding validation result objects. Init-binder methods must not have a return value. Thus, they are usually declared as void. Typical arguments include WebDataBinder in combination with WebRequest or java.util.Locale, allowing code to register context-specific editors.
这样的init-binder方法支持所有的参数相同于@RequestMapping支持的,处理命令和表单object和相应的验证结果object。Init-binder方法不能有返回值。因此,他们通常定义为void。通常参数包括WebDataBinder用于WebRequest或java.util.Locale,允许代码来注册指定的上下文编辑器。
The following example demonstrates the use of @InitBinder for configuring a CustomDateEditor for all java.util.Date form properties.
下面的例子展示了@InitBinder的使用用于配置CustomDateEditor对于java.util.Data的表单属性。
@Controller
public class MyFormController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
// ...
}
Configuring a custom WebBindingInitializer
配置一个自定义的WebBindingInitializer
To externalize data binding initialization, you can provide a custom implementation of the WebBindingInitializer interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter, thus overriding the default configuration.
为了处理数据绑定初始化,你可以提供一个自定义的实现对于WebBindingInitializer接口,允许你支持自定义的bean配置用于AnnotationMethodHandlerAdapter,覆盖默认的配置。
25.10 Portlet application deployment
Poelet的应用部署
The process of deploying a Spring Portlet MVC application is no different than deploying any JSR-286 Portlet application. However, this area is confusing enough in general that it is worth talking about here briefly.
部署spring的porlet的mvc应用的过程和部署JSR286的porlet的应用没有什么不同。然而,这个部分通常是复杂的值得简要讨论一下的。
Generally, the portal/portlet container runs in one webapp in your servlet container and your portlets run in another webapp in your servlet container. In order for the portlet container webapp to make calls into your portlet webapp it must make cross-context calls to a well-known servlet that provides access to the portlet services defined in your portlet.xml file.
通常,portal或porlet容器运行在一个webapp在你的Servlet容器中并且你的porlet运行于另一个webapp在你的Servlet容器中。为了porlet的webapp调用你的porlet的webapp必须跨上下文调用对于Servlet提供了访问支持对于porlet的服务定义在你的porlet.xml文件中,
The JSR-286 specification does not specify exactly how this should happen, so each portlet container has its own mechanism for this, which usually involves some kind of "deployment process" that makes changes to the portlet webapp itself and then registers the portlets within the portlet container.
JSR286规范没有明确指定应该发生什么,因此每个porlet容器有自己的策略,使用调用一些开发程序使得改变porlet的webapp本身注册porlet对于porlet容器。
At a minimum, the web.xml file in your portlet webapp is modified to inject the well-known servlet that the portlet container will call. In some cases a single servlet will service all portlets in the webapp, in other cases there will be an instance of the servlet for each portlet.
最小的情况下,web.xml文件在你的porlet的webapp中被修改用于注入Servlet使得porlet容器可以调用。在一些情况下,一个单一的Servlet将服务于所有的porlet在webapp中,此外特闷将是一个Servlet的实例对于每个porlet。
Some portlet containers will also inject libraries and/or configuration files into the webapp as well. The portlet container must also make its implementation of the Portlet JSP Tag Library available to your webapp.
一些porlet容器将注入库配置文件在webapp中。porlet容器也可以实现porlet的JSP标签库用于你的webapp中。
The bottom line is that it is important to understand the deployment needs of your target portal and make sure they are met (usually by following the automated deployment process it provides). Be sure to carefully review the documentation from your portal for this process.
下面一行是重要的关于理解部署需要你目标的porlet并且保证他们是可见的(通常符合自动化部署程序)。保证检查文档来自你的portal对于这个过程。
Once you have deployed your portlet, review the resulting web.xml file for sanity. Some older portals have been known to corrupt the definition of the ViewRendererServlet, thus breaking the rendering of your portlets.
一旦你部署了你的porlet,同时检查结果的web.xml文件。一些以前的portal可能错误定义了ViewRendererServlet,打破了解析你的porlet。