| | + title | Ref. /chapter[1]/title[1] |
| Original | Traduction | Web framework |
| sect1
| | + title | Ref. /chapter[1]/sect1[1]/title[1] |
| Original | Traduction | Introduction to the web framework |
|
| + para | Ref. /chapter[1]/sect1[1]/para[1] |
| Original | Traduction | Spring's web framework is designed around a DispatcherServlet that
dispatches requests to handlers, with configurable handler mappings, view
resolution, locale and theme resolution as well support for upload files.
The default handler is a very simple Controller interface, just offering a
ModelAndView handleRequest(request,response) method.
This can already be used for application controllers, but you will prefer
the included implementation hierarchy, consisting of for example
AbstractController,
AbstractCommandController and
SimpleFormController. Application controllers will
typically be subclasses of those. Note that you can choose an appropriate
base class: If you don't have a form, you don't need a FormController.
This is a major difference to Struts. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[2] |
| Original | Traduction | You can take any object as command or form object: There's no need
to implement an interface or derive from a base class. Spring's data
binding is highly flexible, e.g. it treats type mismatches as validation
errors that can be evaluated by the application, not as system errors. So
you don't need to duplicate your business objects' properties as Strings
in your form objects, just to be able to handle invalid submissions, or to
convert the Strings properly. Instead, it's often preferable to bind
directly to your business objects. This is another major difference to
Struts which is built around required base classes like
Action and ActionForm - for every
type of action. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[3] |
| Original | Traduction | Compared to WebWork, Spring has more differentiated object roles: It
supports the notion of a Controller, an optional command or form object,
and a model that gets passed to the view. The model will normally include
the command or form object but also arbitrary reference data. Instead, a
WebWork Action combines all those roles into one single object. WebWork
does allow you to use existing business objects as part of your form, but
just by making them bean properties of the respective Action class.
Finally, the same Action instance that handles the request gets used for
evaluation and form population in the view. Thus, reference data needs to
be modeled as bean properties of the Action too. These are arguably too
many roles in one object. |
|
| + para | Ref. /chapter[1]/sect1[1]/para[4] |
| Original | Traduction | Regarding views: Spring's view resolution is extremely flexible. A
Controller implementation can even write a view directly to the response,
returning null as ModelAndView. In the normal case, a ModelAndView
instance consists of a view name and a model Map, containing bean names
and corresponding objects (like a command or form, reference data, etc).
View name resolution is highly configurable, either via bean names, via a
properties file, or via your own ViewResolver implementation. The abstract
model Map allows for complete abstraction of the view technology, without
any hassle: Be it JSP, Velocity, or anything else - every renderer can be
integrated directly. The model Map simply gets transformed into an
appropriate format, like JSP request attributes or a Velocity template
model. |
| sect2
| | + title | Ref. /chapter[1]/sect1[1]/sect2[1]/title[1] |
| Original | Traduction | Pluggability of MVC implementation |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[1]/para[1] |
| Original | Traduction | Many teams will try to leverage their investments in terms of
know-how and tools, both for existing projects and for new ones.
Concretely, there are not only a large number of books and tools for
Struts but also a lot of developers that have experience with it. Thus,
if you can live with Struts's architectural flaws, it can still be a
viable choice for the web layer. The same applies to WebWork and other
web frameworks. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[1]/para[2] |
| Original | Traduction | If you don't want to use Spring's web MVC but intend to leverage
other solutions that Spring offers, you can integrate the web framework
of your choice with Spring easily. Simply start up a Spring root
application context via its ContextLoaderListener, and access it via its
ServletContext attribute (or Spring's respective helper method) from
within a Struts or WebWork action. Note that there aren't any "plugins"
involved, therefore no dedicated integration: From the view of the web
layer, you'll simply use Spring as a library, with the root application
context instance as entry point. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[1]/para[3] |
| Original | Traduction | All your registered beans and all of Spring's services can be at
your fingertips even without Spring's web MVC. Spring doesn't compete
with Struts or WebWork in this usage, it just addresses the many areas
that the pure web frameworks don't, from bean configuration to data
access and transaction handling. So you are able to enrich your
application with a Spring middle tier and/or data access tier, even if
you just want to use e.g. the transaction abstraction with JDBC or
Hibernate. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[1]/sect2[2]/title[1] |
| Original | Traduction | Features of Spring MVC |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/para[1] |
| Original | Traduction | If just focusing on the web support, some of the Spring's unique
features are: |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | Clear separation of roles: controller vs validator vs command
object vs form object vs model object, DispatcherServlet vs handler
mapping vs view resolver, etc. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | Powerful and straightforward configuration of both framework
and application classes as JavaBeans, including easy in-between
referencing via an application context, e.g. from web controllers to
business objects and validators. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | Adaptability, non-intrusiveness: Use whatever Controller
subclass you need (plain, command, form, wizard, multi action, or a
custom one) for a given scenario instead of deriving from
Action/ActionForm for everything. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | Reusable business code, no need for duplication: You can use
existing business objects as command or form objects instead of
mirroring them in special ActionForm subclasses. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[5]/para[1] |
| Original | Traduction | Customizable binding and validation: type mismatches as
application-level validation errors that keep the offending value,
localized date and number binding, etc instead of String-only form
objects with manual parsing and conversion to business
objects. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[6]/para[1] |
| Original | Traduction | Customizable handler mapping, customizable view resolution:
flexible model transfer via name/value Map, handler mapping and view
resolution strategies from simple to sophisticated instead of one
single way. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[7]/para[1] |
| Original | Traduction | Customizable locale and theme resolution, support for JSPs
with and without Spring tag library, support for JSTL, support for
Velocity without the need for extra bridges, etc. |
|
| + para | Ref. /chapter[1]/sect1[1]/sect2[2]/itemizedlist[1]/listitem[8]/para[1] |
| Original | Traduction | Simple but powerful tag library that avoids HTML generation at
any cost, allowing for maximum flexibility in terms of markup
code. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[2]/title[1] |
| Original | Traduction | The DispatcherServlet |
|
| + para | Ref. /chapter[1]/sect1[2]/para[1] |
| Original | Traduction | Spring's web framework is - like many other web frameworks - a
request driven web framework, designed around a servlet that dispatches
requests to controllers and offers other functionality facilitating the
development of web applications. Spring's
DispatcherServlet however, does more than just that. It
is completely integrated with the Spring ApplicationContext and allows you
to use every other feature Spring has. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[2] |
| Original | Traduction | Servlets are declared in the web.xml of your
web application, so is the DispatcherServlet. Requests that you want the
DispatcherServlet to handle, will have to be mapped, using a URL mapping
in the same web.xml file. |
|
| + programlisting | Ref. /chapter[1]/sect1[2]/programlisting[1] |
| Original | Traduction | <web-app>
...
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app> |
|
| + para | Ref. /chapter[1]/sect1[2]/para[3] |
| Original | Traduction | In the example above, all requests ending with
.form will be handled by the DispatcherServlet. Then,
the DispatcherServlet needs to be configured. As illustrated in , ApplicationContexts in Spring can be
scoped. In the web framework, each DispatcherServlet has its own
WebApplicationContext, which contains the
DispatcherServlet configuration beans. The default BeanFactory used by the
DispatcherServlet is the XmlBeanFactory and the
DispatcherServlet will on initialization look for a file named
[servlet-name]-servlet.xml in the
WEB-INF directory of your web application. The default
values used by the DispatcherServlet can be modified by using the servlet
initialization parameters (see below for more information). |
|
| + para | Ref. /chapter[1]/sect1[2]/para[4] |
| Original | Traduction | The WebApplicationContext is just an ordinary
ApplicationContext that has some extra features necessary for
web applications. It differs from a normal ApplicationContext in that it is
capable of resolving themes (see ),
and that is knows to which servlet it is associated (by having a link to
the ServletContext). The WebApplicationContext is bound
in the ServletContext, and using RequestContextUtils
you can always lookup the WebApplicationContext in case you need
it. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[5] |
| Original | Traduction | The Spring DispatcherServlet has a couple of special beans it uses,
in order to be able to process requests and render the appropriate views.
Those beans are included in the Spring framework and (optionally) have to
be configured in the WebApplicationContext, just as any other bean would
have to 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 DispatcherServlet. For most of
the beans, defaults are provided so you don't have to worry about
those. |
|
| + title | Ref. /chapter[1]/sect1[2]/table[1]/title[1] |
| Original | Traduction | Special beans in the WebApplicationContext |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Expression |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Explanation |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[1] |
| Original | Traduction | handler mapping(s) |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | () a list of pre- and
postprocessors and controllers that will be executed if they match
certain criteria (for instance a matching URL specified with the
controller) |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[1] |
| Original | Traduction | controller(s) |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | () the beans providing the
actual functionality (or at least, access to the functionality) as
part of the MVC triad |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[1] |
| Original | Traduction | view resolver |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[2] |
| Original | Traduction | () capable of resolving
view names and needed by the DispatcherServlet to resolves those
views with |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[1] |
| Original | Traduction | locale resolver |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[2] |
| Original | Traduction | () capable of resolves
the locale a client is using, in order to be able to offer
internationalized views |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[5]/entry[1] |
| Original | Traduction | theme resolver |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[5]/entry[2] |
| Original | Traduction | () capable of resolving
themes your web application can use e.g. to offer personalized
layouts |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[6]/entry[1] |
| Original | Traduction | multipart resolver |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[6]/entry[2] |
| Original | Traduction | () offers functionality to
process file uploads from HTML forms |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[7]/entry[1] |
| Original | Traduction | handlerexception resolver |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[1]/tgroup[1]/tbody[1]/row[7]/entry[2] |
| Original | Traduction | () offers
functionality to map exceptions to views or implement other more
complex exception handling code |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6] |
| Original | Traduction | When a DispatcherServlet is setup for use and a request comes in for
that specific DispatcherServlet it starts processing it. The list below
describes the complete process a request goes through if a
DispatcherServlet is supposed to handle it:
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[1]/para[1] |
| Original | Traduction | The WebApplicationContext is searched for and bound in the
request as an attribute in order for controller and other elements
in the chain of process to use it. It is bound by default under the
key
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[2]/para[1] |
| Original | Traduction | The locale resolver is bound to the request to let elements in
the chain resolve the locale to use when processing the request
(rendering the view, preparing data, etcetera). If you don't use the
resolver, it won't affect anything, so if you don't need locale
resolving, just don't bother |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[3]/para[1] |
| Original | Traduction | The theme resolver is bound to the request to let e.g. views
determine which theme to use (if you don't needs themes, don't
bother, the resolver is just bound and does not affect anything if
you don't use it) |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[4]/para[1] |
| Original | Traduction | If a multipart resolver is specified, the request is inspected
for multiparts and if so, it is wrapped in a
MultipartHttpServletRequest for further
processing by other elements in the chain (more information about
multipart handling is provided below) |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[5]/para[1] |
| Original | Traduction | An appropriate handler is searched for. If a handler is found,
it execution chain associated to the handler (preprocessors,
postprocessors, controllers) will be executed in order to prepare a
model |
|
| + para | Ref. /chapter[1]/sect1[2]/para[6]/orderedlist[1]/listitem[6]/para[1] |
| Original | Traduction | If a model is returned, the view is rendered, using the view
resolver that has been configured with the WebApplicationContext. If
no model was returned (which could be the result of a pre- or
postprocessor intercepting the request because of for instance
security reasons), no view is rendered as well, since the request
could already have been fulfilled |
|
|
|
| + para | Ref. /chapter[1]/sect1[2]/para[7] |
| Original | Traduction | Exceptions that might be thrown during processing of the request get
picked up by any of the handlerexception resolvers that are declared in
the WebApplicationContext. Using those exception resolvers you can define
custom behavior in case such exceptions get thrown. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[8] |
| Original | Traduction | The Spring DispatcherServlet also has support for returning the
last-modification-date, as specified by the Servlet
API. The process of determining the last modification date for a specific
request, is simple. The DispatcherServlet will first of all lookup an
appropriate handler mapping and test if the handler that matched
implements the interface
LastModified and if so, the value the of
long getLastModified(request) is returned to the
client. |
|
| + para | Ref. /chapter[1]/sect1[2]/para[9] |
| Original | Traduction | You can customize Spring's DispatcherServlet by adding context
parameters in the web.xml file or servlet init
parameters. The possibilities are listed below. |
|
| + title | Ref. /chapter[1]/sect1[2]/table[2]/title[1] |
| Original | Traduction | DispatcherServlet initialization parameters |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Parameter |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Explanation |
|
contextClass
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | Class that implements
WebApplicationContext, which will be used to
instantiate the context used by this servlet. If this parameter
isn't specified, the XmlWebApplicationContext
will be used |
|
contextConfigLocation
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | 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, of beans that are
defined twice, the latest takes precedence) |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/tbody[1]/row[3]/entry[1] |
| Original | Traduction | namespace |
|
| + entry | Ref. /chapter[1]/sect1[2]/table[2]/tgroup[1]/tbody[1]/row[3]/entry[2] |
| Original | Traduction | the namespace of the
WebApplicationContext. Defaults to
[server-name]-servlet |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[3]/title[1] |
| Original | Traduction | Controllers |
|
| + para | Ref. /chapter[1]/sect1[3]/para[1] |
| Original | Traduction | The notion of controller is part of the MVC design pattern.
Controllers define application behavior, or at least provide users with
access to the application behavior. Controllers interpret user input and
transform the user input into a sensible model which will be represented
to the user by the view. Spring has implemented the notion of a controller
in a very abstract way enabling a wide variety of different kinds of
controllers to be created. Spring contains formcontroller,
commandcontroller, controllers that execute wizard-style logic and
more. |
|
| + para | Ref. /chapter[1]/sect1[3]/para[2] |
| Original | Traduction | Spring's basis for the controller architecture is the
org.springframework.mvc.Controller interface, which is
listed below. | + programlisting | Ref. /chapter[1]/sect1[3]/para[2]/programlisting[1] |
| Original | Traduction | public interface Controller {
/**
* Process the request and return a ModelAndView object which the DispatcherServlet
* will render.
*/
ModelAndView handleRequest(
HttpServletRequest request,
HttpServletResponse response)
throws Exception;
} |
| As you can see, the Controller interface just states one
single method that should be capable of handling a request and return an
appropriate model and view. Those three concepts are the basis for the
Spring MVC implementation; ModelAndView and
Controller. While the Controller interface is quite
abstract, Spring offers a lot of controllers that already contain a lot of
functionality you might need. The controller interface just define the
most commons functionality offered by every controller: the functionality
of handling a request and returning a model and a view. |
| sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[1]/title[1] |
| Original | Traduction | AbstractController and WebContentGenerator |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[1] |
| Original | Traduction | Of course, just a controller interface isn't enough. To provide a
basic infrastructure, all of Spring's Controllers inherit from
AbstractController, a class offering caching support and for instance
the setting of the mimetype. |
|
| + title | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/title[1] |
| Original | Traduction | Features offered by the
AbstractController |
|
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Feature |
|
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Explanation |
|
supportedMethods
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | indicates what methods this controller should accept.
Usually this is set to both GET and
POST, but you can modify this to reflect the
method you want to support. If a request is received with a
method that is not supported by the controller, the client will
be informed of this (using a
ServletException)) |
|
requiresSession
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | 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
ServletException |
|
synchronizeSession
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[2] |
| Original | Traduction | use this if you want handling by this controller to be
synchronized on the user's session. To be more specific,
extending controller will override the
handleRequestInternal method, which will be
synchronized if you specify this variable |
|
cacheSeconds
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[2] |
| Original | Traduction | when you want a controller to generate caching directive
in the HTTP response, specify a positive integer here. By
default it is set to -1 so no caching
directives will be included |
|
useExpiresHeader
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[5]/entry[2] |
| Original | Traduction | tweaking of your controllers specifying the HTTP 1.0
compatible "Expires" header. By default
it's set to true, so you won't have to touch it |
|
useCacheHeader
| + entry | Ref. /chapter[1]/sect1[3]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[6]/entry[2] |
| Original | Traduction | tweaking of your controllers specifying the HTTP 1.1
compatible "Cache-Control" header. By
default this is set to true so you won't really have to touch
it |
|
the last two properties are actually part of the
WebContentGenerator which is the superclass of
AbstractController but to keeps things clear...
| + para | Ref. /chapter[1]/sect1[3]/sect2[1]/para[3] |
| Original | Traduction | When using the AbstractController as a baseclass for your
controllers (which is not recommended since there
are a lot of other controller that might already do the job for your)
you only have to override the
handleRequestInternal(HttpServletRequest,
HttpServletResponse)-method and implement your logic code and
return a ModelAndView object there. A short example
consisting of a class and a declaration in the web application context.
| + programlisting | Ref. /chapter[1]/sect1[3]/sect2[1]/para[3]/programlisting[1] |
| Original | Traduction | package samples;
public class SampleController extends AbstractController {
public ModelAndView handleRequestInternal(
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
ModelAndView mav = new ModelAndView("foo", new HashMap());
}
} |
| | + programlisting | Ref. /chapter[1]/sect1[3]/sect2[1]/para[3]/programlisting[2] |
| Original | Traduction | <bean id="sampleController" class="samples.SampleController">
<property name="cacheSeconds"><value>120</value</property>
</bean> |
| The class above and the declaration in the
web application context is all you need to do besides setting up a handler
mapping (see ) to get this very
simple controller working. This controller will generates caching
directives telling the client to cache things for 2 minutes before
rechecking. This controller furthermore returns an hard-coded view (hmm,
not so nice), named index (see for
more information about views). |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[2]/title[1] |
| Original | Traduction | Other simple controllers |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[2]/para[1] |
| Original | Traduction | Besides the AbstractController - which you could of course extend,
although a more concrete controller might offer you more functionality -
there are a couple of other simple controllers that might ease the pain
of developing simple MVC applications. The
ParameterizableViewController basically is the same
as the one in the example above, except for the fact that you can
specify its view name that it'll be returning in the
web application context (ahhh, no need to hard-code the viewname). |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[2]/para[2] |
| Original | Traduction | The FileNameViewController inspects the URL and
retrieves the filename of the file request (the filename of
http://www.springframework.org/index.html is
index) and uses that as a viewname. Nothing more to
it. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[3]/title[1] |
| Original | Traduction | The MultiActionController |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[1] |
| Original | Traduction | Spring offers a multi-action controller with which you aggregate
multiple actions into one controller, grouping functionality together.
The multi-action controller lives in a separate package -
org.springframework.web.mvc.multiaction - and is
capable of mapping requests to method names and then invoking the right
method name. Using the multi-action controller is especially handy when
you're having a lot of commons functionality in one controller, but want
to have multiple entry points to the controller to tweak behavior for
instance. |
|
| + title | Ref. /chapter[1]/sect1[3]/sect2[3]/table[1]/title[1] |
| Original | Traduction | Features offered by the
MultiActionController |
|
| + entry | Ref. /chapter[1]/sect1[3]/sect2[3]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Feature |
|
| + entry | Ref. /chapter[1]/sect1[3]/sect2[3]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Explanation |
|
delegate
| + entry | Ref. /chapter[1]/sect1[3]/sect2[3]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | there's two usage-scenarios for the
MultiActionController. Either you subclass the
MultiActionController and specify the methods that will be
resolved by the MethodNameResolver on the subclass (in case you
don't need this configuration parameter), or you define a
delegate object, on which methods resolved by the Resolver will
be invoked. If you choose to enter this scenario, you will have
to define the delegate using this configuration parameter as a
collaborator |
|
methodNameResolver
| + entry | Ref. /chapter[1]/sect1[3]/sect2[3]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | somehow, the MultiActionController will need to resolve
the method it has to invoke, based on the request that came in.
You can define a resolver that is capable of doing that using
this configuration parameter |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[2] |
| Original | Traduction | Methods defined for a multi-action controller will need to conform
to the following signature: | + programlisting | Ref. /chapter[1]/sect1[3]/sect2[3]/para[2]/programlisting[1] |
| Original | Traduction | // actionName can be replaced by any methodname
ModelAndView actionName(HttpServletRequest, HttpServletResponse); |
|
Method overloading is not allowed since it'll confuse the
MultiActionController. Furthermore, you can define exception
handlers capable of handling exception that will be thrown
form a method you specify. Exception handler methods need to return a
ModelAndView object, just as any other action method and will need to
conform to the following signature: | + programlisting | Ref. /chapter[1]/sect1[3]/sect2[3]/para[2]/programlisting[2] |
| Original | Traduction | // anyMeaningfulName can be replaced by any methodname
ModelAndView anyMeaningfulName(HttpServletRequest, HttpServletResponse, ExceptionClass); |
|
The ExceptionClass can be any
exception, as long as it's a subclass of
java.lang.Exception or
java.lang.RuntimeException. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[3] |
| Original | Traduction | The MethodNameResolver is supposed to resolve
method names based on the request coming in. There are three resolver to
your disposal, but of course you can implement more of them yourself if
you want.
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[3]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | ParameterMethodNameResolver - capable of
resolving a request parameter and using that as the method name
(http://www.sf.net/index.view?testParam=testIt
will result in a method testIt(HttpServletRequest,
HttpServletResponse) being called). Use the
paramName configuration parameter to tweak the
parameter that's inspected) |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[3]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | InternalPathMethodNameResolver -
retrieves the filename from the path and uses that as the method
name (http://www.sf.net/testing.view will
result in a method testing(HttpServletRequest,
HttpServletResponse) being called) |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[3]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | PropertiesMethodNameResolver - uses a
user-defined properties object with request URLs mapped to
methodnames. When the properties contain
/index/welcome.html=doIt and a request to
/index/welcome.html comes in, the
doIt(HttpServletRequest, HttpServletResponse)
method is called. This method name resolver works with the
PathMatcher (see ) so if the properties
contained /**/welcom?.html it would also have
worked! |
|
|
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[3]/para[4] |
| Original | Traduction | A couple of examples. First of all one showing the
ParameterMethodNameResolver and the delegate
property, which will accept requests to urls with the parameter method
included and set to retrieveIndex: | + programlisting | Ref. /chapter[1]/sect1[3]/sect2[3]/para[4]/programlisting[1] |
| Original | Traduction | <bean id="paramResolver" class="org....mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
</bean>
<bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
<property name="methodNameResolver"><ref bean="paramResolver"/></property>
<property name="delegate"><ref bean="sampleDelegate"/>
</bean>
<bean id="sampleDelegate" class="samples.SampleDelegate"/>
## together with
public class SampleDelegate {
public ModelAndView retrieveIndex(
HttpServletRequest req,
HttpServletResponse resp) {
return new ModelAndView("index", "date", new Long(System.currentTimeMillis()));
}
} |
| When using the delegates shown above, we could also use the
PropertiesMethodNameResolver to match a couple of
URLs to the method we defined: | + programlisting | Ref. /chapter[1]/sect1[3]/sect2[3]/para[4]/programlisting[2] |
| Original | Traduction | <bean id="propsResolver" class="org....mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/index/welcome.html">retrieveIndex</prop>
<prop key="/**/notwelcome.html">retrieveIndex</prop>
<prop key="/*/user?.html">retrieveIndex</prop>
</props>
</property>
</bean>
<bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
<property name="methodNameResolver"><ref bean="propsResolver"/></property>
<property name="delegate"><ref bean="sampleDelegate"/>
</bean> |
|
|
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[3]/sect2[4]/title[1] |
| Original | Traduction | CommandControllers |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1] |
| Original | Traduction | Spring's CommandControllers are a fundamental
part of the Spring MVC package. Command controllers provide a way to
interact with data objects and dynamically bind parameters from the
HttpServletRequest to the data object you're
specifying. This compares to Struts's actionforms, where in Spring, you
don't have to implement any interface of superclasses to do data binding.
First, let's examine what command controllers available, just to get
clear picture of what you can do with them:
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | AbstractCommandController - a command
controller you can use to create your own command controller,
capable of binding request parameters to a data object you're
specifying. 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 data object that has been
filled with the parameters from the request. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | AbstractFormController - an abstract
controller offering form submission support. Using this controller
you can model forms and populate them using a data object you're
retrieving in the controller. After a user has filled the form,
the AbstractFormController binds the fields, validates and hands
the object back to you - the controller - to take appropriate
action. Supported features are invalid form submission
(resubmission), validation, and the right workflow a form always
has. What views you tie to your AbstractFormController you decide
yourself. Use this controller if you need forms, but don't want to
specify what views you're going to show the user in the
applicationcontext |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | SimpleFormController - an even more
concrete FormController that helps you creating a form with
corresponding data object even more. The SimpleFormController
let's you specify a command object, a viewname for the form, a
viewname for page you want to show the user when formsubmission
has succeeded, and more |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | AbstractWizardFormController - as the
class name suggests, this is an abstract class--your
WizardController should extend it. This means you have to
implement both the validatePage(),
processFinish as well as
processCancel methods. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[2] |
| Original | Traduction | Probably you also want to write a contractor, which should
at the very least call setPages() and
setCommandName(). The former takes as its
argument an array of type String. This array is the list of views
which comprise your wizard. The latter takes as its argument a
String, which will be used to refer to your Command object from
within your views. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[3] |
| Original | Traduction | As with any instance of AbstractFormController, you are
required to use a Command object - a JavaBean which will be
populated with the data from your forms. You can do this in one of
two ways: either call setCommandClass() from
the constructor with the class of your command object, or
implement the formBackingObject()
method. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[4] |
| Original | Traduction | AbstractWizardFormController has a number of concrete
methods that you may wish to override. Of these, the ones you are
likely to find most useful are: referenceData
which you can use to pass model data to your view in the form of a
Map; getTargetPage if your wizard needs to
change page order or omit pages dynamically; and
onBindAndValidate if you want to override the
built-in binding and validation workflow. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[5] |
| Original | Traduction | Finally, it is worth pointing out the
setAllowDirtyBack and
setAllowDirtyForward, which you can call from
getTargetPage to allow users to move backwards
and forwards in the wizard even if validation fails for the
current page. |
|
| + para | Ref. /chapter[1]/sect1[3]/sect2[4]/para[1]/itemizedlist[1]/listitem[4]/para[6] |
| Original | Traduction | For a full list of methods, see the JavaDoc for
AbstractWizardFormController. There is an implemented example of
this wizard in the jPetStore included in the Spring distribution:
org.springframework.samples.jpetstore.web.spring.OrderFormController.java |
|
|
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[4]/title[1] |
| Original | Traduction | Handler mappings |
|
| + para | Ref. /chapter[1]/sect1[4]/para[1] |
| Original | Traduction | Using a handler mapping you can map incoming web requests to
appropriate handlers. There are some handler mapping you can use, for
example the SimpleUrlHandlerMapping or the
BeanNameUrlHandlerMapping, but let's first examine the
general concept of a HandlerMapping. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[2] |
| Original | Traduction | The functionality a basic HandlerMapping provides
is the delivering of a HandlerExecutionChain, first of
all containing one handler that matched the incoming request. The second
(but optional) element a handler execution chain will contain is a list of
handler interceptor that should be applied to the request. When a request
comes in, the DispatcherServlet will hand it over to
the handler mapping to let it inspect the request and come up with an
appropriate HandlerExecutionChain. When done, the DispatcherServlet will
execute the handler and interceptors in the chain (if any). |
|
| + para | Ref. /chapter[1]/sect1[4]/para[3] |
| Original | Traduction | 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-in in custom
HandlerMappings. Think of a custom handler mapping that
chooses a handler not only based on the URL of the request coming in, but
also on a specific state of the session associated with the
request. |
|
| + para | Ref. /chapter[1]/sect1[4]/para[4] |
| Original | Traduction | This section describes two of Spring's most often used handler mapping.
They both extend the AbstractHandlerMapping and share the following
properties
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[1]/para[1] |
| Original | Traduction | interceptors: the list of interceptors to use.
HandlerInterceptors are discussed further ahead |
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[2]/para[1] |
| Original | Traduction | defaultHandler: the default handler to use,
when this handler mapping does not result in a matching handler |
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[3]/para[1] |
| Original | Traduction | order: based on the value of the order property (see
the org.springframework.core.Ordered interface),
Spring will sort all handler mapping available in the context and
apply them in them one after the other.
|
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[4]/para[1] |
| Original | Traduction | alwaysUseFullPath: based on this setting,
Spring will either use the full path within the current servlet
context (if set to true) or the path within the current servlet
mapping (false, the default value). If for example a servlet is mapped using
/testing/* and you've set the alwaysUseFullPath property
to true, /testing/viewPage.html will match, whereas /viewPage.html
will only match if you leave the default value (false) in place
(Note: this property is only available for the
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping and its subclasses) |
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[5]/para[1] |
| Original | Traduction | urlPathHelper: using this property, you can
tweak the UrlPathHelper used when inspecting URLs. Normally, you shouldn't have to change the default value.
(Note: this property is only available for the
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping and its subclasses)
|
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[6]/para[1] |
| Original | Traduction | urlDecode: the default value for this property is false. The
HttpServletRequest returns request URLs and URIs that are not decoded. If you
do want them to be decoded before a HandlerMapping will use them to find an appropriate handler, you
have to set this to true (this requires JDK 1.4 however). Uses either the encoding specified by the
request or the default ISO-8859-1 encoding scheme.
(Note: this property is only available for the
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping and its subclasses)
|
|
| + para | Ref. /chapter[1]/sect1[4]/para[4]/itemizedlist[1]/listitem[7]/para[1] |
| Original | Traduction | lazyInitHandlers: allows for lazy initialization of singleton handlers
(prototype handlers are always lazily initialized). Default value is false
(Note: this property is only available for the
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping and its subclasses)
|
|
|
| sect2
| BeanNameUrlHandlerMapping | + para | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1] |
| Original | Traduction | A very simple, but very powerful handler mapping is the
BeanNameUrlHandlerMapping, which maps incoming HTTP
requests to names of beans, defined in the web application context. Let's
say we want to enable a user to insert an account and we've already
provided an appropriate FormController (see for more information on Command- and
FormControllers) and a JSP view (or Velocity template) that renders the
form. When using the BeanNameUrlHandlerMapping, we could map the HTTP
request with URL http://samples.com/editaccount.form
to the appropriate FormController as follows: | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/programlisting[1] |
| Original | Traduction | <beans>
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/editaccount.form"
class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView"><value>account</value></property>
<property name="successView"><value>account-created</value></property>
<property name="commandName"><value>Account</value></property>
<property name="commandClass"><value>samples.Account</value></property>
</bean>
<beans> |
| All incoming requests for the URL
/editaccount.form will now be handled by the
FormController in the source listing above. Of course we have to define
a servlet-mapping in web.xml as well, to let through all the requests
ending with .form. | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[1]/para[1]/programlisting[2] |
| Original | Traduction | <web-app>
...
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Maps the sample dispatcher to /*.form -->
<servlet-mapping>
<servlet-name>sample</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
...
</web-app> |
|
|
| NOTE: if you want to use the
BeanNameUrlHandlerMapping, you don't necessarily have
to define it in the web application context (as indicated above). By
default, if no handler mapping can be found in the context, the
DispatcherServlet creates a BeanNameUrlHandlerMapping
for you! | | sect2
| SimpleUrlHandlerMapping | + para | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1] |
| Original | Traduction | A further - and much more powerful handler mapping - is the
SimpleUrlHandlerMapping. This mapping is configurable
in the application context and has Ant-style path matching capabilities
(see ). A couple of example
will probably makes thing clear enough: | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction | <web-app>
...
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Maps the sample dispatcher to /*.form -->
<servlet-mapping>
<servlet-name>sample</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>sample</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
...
</web-app> |
| Allows all requests ending with .html and
.form to be handled by the sample dispatcher servlet. | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[2]/para[1]/programlisting[2] |
| Original | Traduction | <beans>
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/*/account.form">editAccountFormController</prop>
<prop key="/*/editaccount.form">editAccountFormController</prop>
<prop key="/ex/view*.html">someViewController</prop>
<prop key="/**/help.html">helpController</prop>
</props>
</property>
</bean>
<bean id="someViewController"
class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
<bean id="editAccountFormController"
class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView"><value>account</value></property>
<property name="successView"><value>account-created</value></property>
<property name="commandName"><value>Account</value></property>
<property name="commandClass"><value>samples.Account</value></property>
</bean>
<beans> |
| This handler mapping first of all reroutes all
requests in all directories for a file named
help.html to the
someViewController, which is a
UrlFilenameViewController (more about that can be found in ). Also, all requests for a resource
beginning with view, ending with
.html, in the directory ex, will
be rerouted to that specific controller. Furthermore, two mappings have
been defined that will match with the
editAccountFormController. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[4]/sect2[3]/title[1] |
| Original | Traduction | Adding HandlerInterceptors |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[1] |
| Original | Traduction | The handler mapping also has a notion of handler interceptors,
that can be extremely useful when you want to apply specific
functionality to all requests, for example the checking for a principal
or something alike. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[2] |
| Original | Traduction | Interceptors located in the handler mapping must implement
HandlerInterceptor from the
org.springframework.web.servlet-package. This
interface defines three methods, one that will be called
before the actual handler will be executed, one
that will be called after the handler is executed,
and one that is called after the complete request has
finished. Those three methods should provide you with enough
flexibility to do all kinds of pre- and post-processing. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[3] |
| Original | Traduction | The preHandle method has a boolean return
value. Using this value, you can tweak the behavior of the execution
chain. When returning true, the handler execution
chain will continue, when returning false, the DispatcherServlet assumes
the interceptor itself has taken care of requests (and for instance
rendered an appropriate view) and does not continue with executing the
other interceptors and the actual handler in the execution chain. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[4] |
| Original | Traduction | The following example provides an interceptor that intercepts all
requests and reroutes the user to a specific page if the time is not
between 9 a.m. and 6 p.m. | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[4]/programlisting[1] |
| Original | Traduction | <beans>
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="officeHoursInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="/*.form">editAccountFormController</prop>
<prop key="/*.view">editAccountFormController</prop>
</props>
</property>
</bean>
<bean id="officeHoursInterceptor"
class="samples.TimeBasedAccessInterceptor">
<property name="openingTime"><value>9</value></property>
<property name="closingTime"><value>18</value></property>
</bean>
<beans> |
| | + programlisting | Ref. /chapter[1]/sect1[4]/sect2[3]/para[4]/programlisting[2] |
| Original | Traduction | package samples;
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
Calendar cal = Calendar.getInstance();
int hour = cal.get(HOUR_OF_DAY);
if (openingTime <= hour < closingTime) {
return true;
} else {
response.sendRedirect("http://host.com/outsideOfficeHours.html");
return false;
}
}
} |
| Any request coming in, will be intercepted by the
TimeBasedAccessInterceptor, and if the current time
is outside office hours, the user will be redirect to a static html
file, saying for instance he can only access the website during office
hours. |
|
| + para | Ref. /chapter[1]/sect1[4]/sect2[3]/para[5] |
| Original | Traduction | As you can see, Spring has an adapter to make it easy for you to
extend the HandlerInterceptor. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[5]/title[1] |
| Original | Traduction | Views and resolving them |
|
| + para | Ref. /chapter[1]/sect1[5]/para[1] |
| Original | Traduction | No MVC framework for web applications is without a way to address
views. Spring provides view resolvers, which enable you to render models
in a browser without tying yourself to a specific view technology.
Out-of-the-box, Spring enables you to use Java Server Pages, Velocity
templates and XSLT views, for example. has details
of integrating various view technologies. |
|
| + para | Ref. /chapter[1]/sect1[5]/para[2] |
| Original | Traduction | The two classes which are important to the way Spring handles views
are the ViewResolver and the View.
The View interface addresses the preparation of the
request and hands the request over to one of the view technologies. The
ViewResolver provides a mapping between view names and
actual views. |
| sect2
| | + title | Ref. /chapter[1]/sect1[5]/sect2[1]/title[1] |
| Original | Traduction | ViewResolvers |
|
| + para | Ref. /chapter[1]/sect1[5]/sect2[1]/para[1] |
| Original | Traduction | As discussed before, all controllers in the Spring web framework,
return a ModelAndView instance. Views in Spring are
addressed by a view name and are resolved by a viewresolver. Spring
comes with quite a few view resolvers. We'll list most of them and then
provide a couple of examples. |
|
| + title | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/title[1] |
| Original | Traduction | View resolvers |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | ViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Description |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[1] |
| Original | Traduction | AbstractCachingViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | Abstract view resolver taking care of caching views. Lots
of views need preparation before they can be used, extending
from this viewresolver enables caching of views |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[1] |
| Original | Traduction | XmlViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | Implementation of ViewResolver that accepts a config file
written in XML to the same DTD as Spring's bean factories |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[1] |
| Original | Traduction | ResourceBundleViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[2] |
| Original | Traduction | Implementation of ViewResolver that uses bean definitions
in a ResourceBundle, specified by the bundle basename. The
bundle is typically defined in a properties file, located in the
classpath |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[1] |
| Original | Traduction | UrlBasedViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[4]/entry[2] |
| Original | Traduction | Simple implementation of ViewResolver that allows for
direct resolution of symbolic view names to URLs, without an
explicit mapping definition. This is appropriate if your
symbolic names match the names of your view resources in a
straightforward manner, without the need for arbitrary
mappings |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[5]/entry[1] |
| Original | Traduction | InternalResourceViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[5]/entry[2] |
| Original | Traduction | Convenience subclass of UrlBasedViewResolver that
supports InternalResourceView (i.e. Servlets and JSPs), and
subclasses like JstlView and TilesView. The view class for all
views generated by this resolver can be specified via
setViewClass. See UrlBasedViewResolver's javadocs for
details |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[6]/entry[1] |
| Original | Traduction | VelocityViewResolver / FreeMarkerViewResolver |
|
| + entry | Ref. /chapter[1]/sect1[5]/sect2[1]/table[1]/tgroup[1]/tbody[1]/row[6]/entry[2] |
| Original | Traduction | Convenience subclass of UrlBasedViewResolver that
supports VelocityView (i.e. Velocity templates) or
FreeMarkerView respectively and custom subclasses of
them |
|
| + para | Ref. /chapter[1]/sect1[5]/sect2[1]/para[2] |
| Original | Traduction | As an example, when using JSP for a view technology you can use
the the UrlBasedViewResolver. This view resolver
translates view names to a URL and hands the request over the
RequestDispatcher to render the view. | + programlisting | Ref. /chapter[1]/sect1[5]/sect2[1]/para[2]/programlisting[1] |
| Original | Traduction | <bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix"><value>/WEB-INF/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean> |
| When returning test as a
viewname, this view resolver will hand the request over to the
RequestDispatcher that'll send the request to
/WEB-INF/jsp/test.jsp. |
|
| + para | Ref. /chapter[1]/sect1[5]/sect2[1]/para[3] |
| Original | Traduction | When mixing different view technologies in a web application, you
can use the ResourceBundleViewResolver: | + programlisting | Ref. /chapter[1]/sect1[5]/sect2[1]/para[3]/programlisting[1] |
| Original | Traduction | <bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename"><value>views</value></property>
<property name="defaultParentView"><value>parentView</value></property>
</bean> |
|
|
|
| + para | Ref. /chapter[1]/sect1[5]/sect2[1]/para[4] |
| Original | Traduction | The ResourceBundleViewResolver inspects the ResourceBundle
identified by the basename and for each view it is supposed to resolve,
it uses the value of the property [viewname].class as
the view class and the value of the property
[viewname].url as the view url. As you can see, you
can identify a parent view, from which all view in the properties file
sort of extend. This way you can specify a default view class for
instance. |
|
| + para | Ref. /chapter[1]/sect1[5]/sect2[1]/para[5] |
| Original | Traduction | A note on caching: subclasses of
AbstractCachingViewResolver cache view instances
they've resolved. This greatly improves performance when using certain
view technology. It's possible to turn off the cache, by setting the
cache property to false. Furthermore, if you have the
requirement to be able to refresh a certain view at runtime (for example
when a Velocity template has been modified), you can use the
removeFromCache(String viewName, Locale loc)
method. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[6]/title[1] |
| Original | Traduction | Using locales |
|
| + para | Ref. /chapter[1]/sect1[6]/para[1] |
| Original | Traduction | Most parts of Spring's architecture support internationalization,
just as the Spring web framework does. SpringWEB enables you to
automatically resolve messages using the client's locale. This is done
with LocaleResolver objects. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[2] |
| Original | Traduction | When a request comes in, the DispatcherServlet looks for a locale
resolver and if it finds one it tries to use it and set the locale. Using
the RequestContext.getLocale() method, you can always
retrieve the locale that was resolved by the locale resolver. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[3] |
| Original | Traduction | Besides the automatic locale resolution, you can also attach an
interceptor to the handler mapping (see for more info on that), to
change the locale under specific circumstances, based on a parameter
occurring in the request for example. |
|
| + para | Ref. /chapter[1]/sect1[6]/para[4] |
| Original | Traduction | Locale resolvers and interceptors are all defined in the
org.springframework.web.servlet.i18n package, and are
configured in your application context in the normal way. Here is a
selection of the locale resolvers included in Spring. |
| sect2
| AcceptHeaderLocaleResolver | + para | Ref. /chapter[1]/sect1[6]/sect2[1]/para[1] |
| Original | Traduction | This locale resolver inspects the
accept-language header in the request that was sent
by the browser of the client. Usually this header field contains the
locale of the client's operating system. |
|
| | sect2
| CookieLocaleResolver | + para | Ref. /chapter[1]/sect1[6]/sect2[2]/para[1] |
| Original | Traduction | This locale resolver inspects a Cookie that might exist on the
client, to see if there's a locale specified. If so, it uses that
specific locale. Using the properties of this locale resolver, you can
specify the name of the cookie, as well as the maximum age.
| + programlisting | Ref. /chapter[1]/sect1[6]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction | <bean id="localeResolver">
<property name="cookieName"><value>clientlanguage</value></property>
<!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->
<property name="cookieMaxAge"><value>100000</value></property>
</bean> |
| This is an example of defining a
CookieLocaleResolver. |
|
| + title | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/title[1] |
| Original | Traduction | Special beans in the WebApplicationContext |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/thead[1]/row[1]/entry[1] |
| Original | Traduction | Property |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/thead[1]/row[1]/entry[2] |
| Original | Traduction | Default |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/thead[1]/row[1]/entry[3] |
| Original | Traduction | Description |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[1] |
| Original | Traduction | cookieName |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[2] |
| Original | Traduction | classname + LOCALE |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[1]/entry[3] |
| Original | Traduction | The name of the cookie |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[1] |
| Original | Traduction | cookieMaxAge |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[2] |
| Original | Traduction | Integer.MAX_INT |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[2]/entry[3] |
| Original | Traduction | The maximum time a cookie will stay persistent on the
client. If -1 is specified, the cookie will not be persisted, at
least, only until the client shuts down his or her
browser |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[1] |
| Original | Traduction | cookiePath |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[2] |
| Original | Traduction | / |
|
| + entry | Ref. /chapter[1]/sect1[6]/sect2[2]/table[1]/tgroup[1]/tbody[1]/row[3]/entry[3] |
| Original | Traduction | Using this parameter, you can limit the visibility of the
cookie to a certain part of your site. When cookiePath is
specified, the cookie will only be visible to that path, and the
paths below |
|
| | sect2
| SessionLocaleResolver | + para | Ref. /chapter[1]/sect1[6]/sect2[3]/para[1] |
| Original | Traduction | The SessionLocaleResolver allows you to
retrieve locales from the session that might be associated to the user's
request. |
|
| | sect2
| LocaleChangeInterceptor | + para | Ref. /chapter[1]/sect1[6]/sect2[4]/para[1] |
| Original | Traduction | You can build in changing of locales using the
LocaleChangeInterceptor. This interceptor needs to be
added to one of the handler mappings (see ) and it will detect a parameter in the
request and change the locale (it calls setLocale()
on the LocaleResolver that also exists in the context). | + programlisting | Ref. /chapter[1]/sect1[6]/sect2[4]/para[1]/programlisting[1] |
| Original | Traduction | <bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName"><value>siteLanguage</value></property>
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref local="localeChangeInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="/**/*.view">someController</prop>
</props>
</property>
</bean> |
| All calls to all *.view resources containing a
parameter named siteLanguage will now change the
locale. So a call to
http://www.sf.net/home.view?siteLanguage=nl will
change the site language to Dutch. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[7]/title[1] |
| Original | Traduction | Using themes |
|
| + para | Ref. /chapter[1]/sect1[7]/para[1] |
| Original | Traduction | Dummy paragraph |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[8]/title[1] |
| Original | Traduction | Spring's multipart (fileupload) support |
| sect2
| | + title | Ref. /chapter[1]/sect1[8]/sect2[1]/title[1] |
| Original | Traduction | Introduction |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[1]/para[1] |
| Original | Traduction | Spring has built-in multipart support to handle fileuploads in
web applications. The design for the multipart support is done with
pluggable MultipartResovler objects, defined in the
org.springframework.web.multipart package. Out of the
box, Spring provides MultipartResolver for use with Commons
FileUpload () and
COS FileUpload (). How uploading files is
supported will be described in the rest of this chapter. |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[1]/para[2] |
| Original | Traduction | By default, no multipart handling will be done by Spring, as some
developers will want to handle multiparts themselves. You'll have to
enable it yourself by adding a multipart resolver to the web application's
context. After you've done that, each request will be inspected for a
multipart that it might contain. If no such multipart is found, the
request will continue as expected. However, if a multipart is found in
the request, the MultipartResolver that has been declared in your
context will resolve. After that, the multipart attribute in your
request will be treated as any other attributes. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[8]/sect2[2]/title[1] |
| Original | Traduction | Using the MultipartResolver |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[2]/para[1] |
| Original | Traduction | The following example shows how to use the
CommonsMultipartResolver: | + programlisting | Ref. /chapter[1]/sect1[8]/sect2[2]/para[1]/programlisting[1] |
| Original | Traduction | <bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize">
<value>100000</value>
</property>
</bean> |
| This is an example using the
CosMultipartResolver: | + programlisting | Ref. /chapter[1]/sect1[8]/sect2[2]/para[1]/programlisting[2] |
| Original | Traduction | <bean id="multipartResolver"
class="org.springframework.web.multipart.cos.CosMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize">
<value>100000</value>
</property>
</bean> |
|
|
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[2]/para[2] |
| Original | Traduction | Of course you need to stick 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, while in the case of the
CosMultipartResolver, use cos.jar. |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[2]/para[3] |
| Original | Traduction | Now that you have seen how to set Spring up to handle multipart
requests, let's talk about how to actually use it. When the Spring
DispatcherServlet detects a Multipart request, it activates the resolver
that has been declared in your context and hands over the request. What
it basically does is wrap the current
HttpServletRequest into a
MultipartHttpServletRequest that has support for
multiparts. Using the MultipartHttpServletRequest you can get
information about the multiparts contained by this request and actually
get the multiparts themselves in your controllers. |
|
| | sect2
| | + title | Ref. /chapter[1]/sect1[8]/sect2[3]/title[1] |
| Original | Traduction | Handling a fileupload in a form |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[3]/para[1] |
| Original | Traduction | After the MultipartResolver has finished doing its job, the
request will be processed like any other. To use it, you create a form
with an upload field, then let Spring bind the file on your form. 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 beans
you have to register a custom editor with the
ServletRequestDatabinder. There are a couple of
editors available for handling files and setting the results on a bean.
There's a StringMultipartEditor capable of converting
files to Strings (using a user-defined character set) and there's a
ByteArrayMultipartEditor which converts files to byte
arrays. They function just as the CustomDateEditor
does. |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[3]/para[2] |
| Original | Traduction | So, to be able to upload files using a form in a website, declare
the resolver, a url mapping to a controller that will process the bean,
and the controller itself. | + programlisting | Ref. /chapter[1]/sect1[8]/sect2[3]/para[2]/programlisting[1] |
| Original | Traduction | <beans>
...
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/upload.form">fileUploadController</prop>
</props>
</property>
</bean>
<bean id="fileUploadController" class="examples.FileUploadController">
<property name="commandClass"><value>examples.FileUploadBean</value></property>
<property name="formView"><value>fileuploadform</value></property>
<property name="successView"><value>confirmation</value></property>
</bean>
</beans> |
|
|
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[3]/para[3] |
| Original | Traduction | After that, create the controller and the actual bean holding the
file property | + programlisting | Ref. /chapter[1]/sect1[8]/sect2[3]/para[3]/programlisting[1] |
| Original | Traduction | // snippet from FileUploadController
public class FileUploadController extends SimpleFormController {
protected ModelAndView onSubmit(
HttpServletRequest request,
HttpServletResponse response,
Object command,
BindException errors)
throws ServletException, IOException {
// 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
}
// well, let's do nothing with the bean for now and return:
return super.onSubmit(request, response, command, errors);
}
protected void initBinder(
HttpServletRequest request,
ServletRequestDataBinder binder)
throws ServletException {
// to actually be able to convert Multipart instance to byte[]
// we have to register a custom editor (in this case the
// ByteArrayMultipartEditor
binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
// now Spring knows how to handle multipart object and convert them
}
}
// snippet from FileUploadBean
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 typed
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 these
examples, 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, etcetera). |
|
| + para | Ref. /chapter[1]/sect1[8]/sect2[3]/para[4] |
| Original | Traduction | But we're still not finished. To actually let the user upload
something, we have to create a form: | + programlisting | Ref. /chapter[1]/sect1[8]/sect2[3]/para[4]/programlisting[1] |
| Original | Traduction | <html>
<head>
<title>Upload a file please</title>
</head>
<body>
<h1>Please upload a file</h1>
<form method="post" action="upload.form" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>
</body>
</html> |
| As you can see, we've created a field named
after the property of the bean that holds the byte[]. Furthermore we've
added the encoding attribute which is necessary to let the browser know
how to encode the multipart fields (do not forget this!). Right now
everything should work. |
|
| |
| | sect1
| | + title | Ref. /chapter[1]/sect1[9]/title[1] |
| Original | Traduction | Handling exceptions |
|
| + para | Ref. /chapter[1]/sect1[9]/para[1] |
| Original | Traduction | Spring provides HandlerExceptionResolvers to ease
the pain of unexpected exceptions occurring while your request is being
handled by a controller which matched the request.
HandlerExceptionResolvers somewhat resemble the
exception mappings you can define in the web application descriptor
web.xml. However, they provide a more flexible way to
handle exceptions. They provide information about what handler was
executing when the exception was thrown. Furthermore, a programmatic way
of handling exception gives you many more options for how to respond
appropriately before the request is forwarded to another URL (the same
end result as when using the servlet specific exception mappings). |
|
| + para | Ref. /chapter[1]/sect1[9]/para[2] |
| Original | Traduction | Besides implementing the
HandlerExceptionResolver, which is only a matter of
implementing the resolveException(Exception, Handler)
method and returning a ModelAndView, you may also use
the SimpleMappingExceptionResolver. This resolver
enables you to take the class name of any exception that might be thrown
and map it to a view name. This is functionally equivalent to the
exception mapping feature from the Servlet API, but it's also possible to
implement more fine grained mappings of exceptions from different
handlers. |
|
| | sect1
| | + title | Ref. /chapter[1]/sect1[10]/title[1] |
| Original | Traduction | Commonly used utilities |
| sect2
| | + title | Ref. /chapter[1]/sect1[10]/sect2[1]/title[1] |
| Original | Traduction | A little story about the pathmatcher |
|
| + para | Ref. /chapter[1]/sect1[10]/sect2[1]/para[1] |
| Original | Traduction | ToDo |
|
| |
| |
|