|
From: <jue...@we...> - 2004-02-17 21:31:04
|
Jim,
=20
First of all, thanks for the extensive discussion of Spring's web =
configuration :-)
=20
Point taken that Spring's web MVC offers an awful lot of options, =
particularly in comparison to other web frameworks. However, you're =
using Petclinic's specific configuration style as reference here; there =
are much simpler styles available. Another point taken: Petclinic should =
probably illustrate a simpler style.
=20
As a counterexample, let's take "example-servlet.xml" from the =
"webapp-minimal" skeleton that ships with the Spring distribution. =
There, the web app consists of one controller; the entire configuration =
looks as follows (omitting comments):
=20
<beans>
<bean name=3D"/test" class=3D"example.ExampleController"/>
</beans>
=20
All the configuration options have implicit defaults; let's examine them =
one by one:
- The default ViewResolver is an InternalResourceViewResolver, simply =
interpreting view names as resource URLs in the web application. Our =
sample controller returns "/test.jsp"; this is obviously no true =
symbolic name but straightforward for simple purposes.
- The default HandlerMapping is a BeanNameUrlHandlerMapping, =
interpreting bean names as URLs within the DispatcherServlet mapping =
"/example/*". Our controller is therefore mapped to "/example/test".
- The default HandlerAdapter is a SimpleControllerHandlerAdapter, =
understanding how to handle Controller implementation. In typical =
applications, you never have to worry about this in the first place.
- Exception handling is delegated to the servlet container, as there is =
no default HandlerExceptionResolver. Specify your error pages in web.xml =
here, as usual.
- We don't have a MultiActionController here; therefore we don't need a =
MethodNameResolver.
=20
Obviously, the biggest drawback of this extremely simple configuration =
style is the lack of true symbolic view names. "example-servlet.xml" =
shows in a comment how to add a custom InternalResourceViewResolver that =
prepends and appends stuff to the symbolic view name:
=20
<bean id=3D"viewResolver" =
class=3D"org.springframework.web.servlet.view.InternalResourceViewResolve=
r">
<property =
name=3D"viewClass"><value>org.springframework.web.servlet.view.JstlView</=
value></property>
<property name=3D"prefix"><value>/WEB-INF/jsp/</value></property>
<property name=3D"suffix"><value>.jsp</value></property>
</bean>
If you add this bean to the above, the controller can for example return =
"test" to trigger the rendering of "/WEB-INF/jsp/test.jsp". Granted, =
there is a tight coupling between logical view names and actual resource =
names here - but it's not in the controller! If you want to map to =
arbitrary view resources, simply switch to a different ViewResolver. =
However, for many typical applications, such a prepend/append strategy =
is good enough (I tend to use it myself).
=20
You will have two separate configuration files if you use =
ResourceBundleViewResolver, but that's by no means a requirement. The =
main advantage of that ViewResolver is that it can easily use localized =
view mappings, i.e. different view resources for different languages. A =
further benefit is that you can define arbitrary view mappings (you can =
also have that via XmlViewResolver, in a separate XML view definition =
file).
=20
The above is basically also the configuration strategy that our =
JPetStore uses. The only difference is that we use two explicit =
HandlerMappings there, one for public controllers and one for secured =
controllers.
=20
Let's recap: A single bean configuration file with two beans, one for =
the controller and for the ViewResolver. If we add 10 more controllers, =
we'd have 12 beans: 11 controllers and one ViewResolver. Sounds pretty =
simple to me :-)
=20
So where's the difference to WebWork's configuration style?
- WebWork allows you to map the controller to a URL via the name; same =
here, thus no difference.
- WebWork allows you to specify the execute method in the action =
definition, but just one per action; I do not see much value in this. =
This is not the same as Spring's MultiActionController: You typically =
map multiple URLs to various methods of the same controller there; a =
separate configuration mechanism for that makes sense IMO.
- The single most significant difference is the view mapping: WebWork =
maps result names within the action definition; Spring maps them =
independent of controller definitions in separate HandlerMappings.
=20
We have somewhat different semantics in terms of view mapping: With =
WebWork, you typically use result names like "success" or "login" - =
result names for the specific action. With Spring, you typically use =
view names like "orderform" or "loginview" - view names that are =
independent of an action. With Spring's semantics, mapping them within =
the controller definition isn't appropriate, IMO; views should be =
defined separate of individual actions here.
=20
BTW, your "selectView" example from Petclinic's "findOwnerForm" is =
somewhat misleading: You can simply return the view name =
"selectOwnerView" from within a controller; the additional =
configurability of the symbolic view name is a decision that the =
application developer makes. This is similar with WebWork.
=20
Finally, I'd like to clarify that I do see the value in different =
configuration styles. My main intent is to show that you can use =
Spring's web MVC in a very simple fashion; the configuration options all =
have convenient defaults. Of course, there's always room for improvement =
or adding alternative configuration styles; maybe we can find something =
for the Spring 1.1 timeframe, based on your suggestions.
=20
However, if you want WebWork's result name semantics or throwaway =
controllers, I do recommend using WebWork on top of a Spring middle =
tier. Same for Struts if you want Struts' tag libraries; same for =
Tapestry if you want to work with page specifications and code-behind =
style MVC. Each framework has its particular advantages; I believe it's =
good to have those distinct, individual notions - they allow for true =
choice of style.
=20
Juergen
=20
________________________________
Von: spr...@li... im Auftrag =
von James Cook
Gesendet: Mo 16.02.2004 23:26
An: spr...@li...
Betreff: [Springframework-developer] Simpler Web MVC Configuration =
Proposal
I have previously developed web applications using WebWork (1 & 2), and =
I
have been drawn to the Spring Framework because of its complete IOC =
support
and more so, its excellent data abstraction layer. Particularly of =
interest
to me on my current project is its Hibernate support and Transaction
capabilities.
At the moment however, I am focused on some of the web tier =
architecture. It
may not be for everyone, but I find myself longing for WebWork's simple
configuration of the web tier. I realize that I could integrate Spring =
and
WebWork and be done with it, but I don't use WebWork's taglib, nor do I =
want
to introduce another dependency if I don't have to. Right now, I am =
trying
to get Spring's web MVC framework sorted out. I apologize in advance if =
I
misstate any facts or statements regarding the Spring Framework's
capabilities or implementation. I am a Spring-chicken at the moment. :-)
I think I understand the various mapping files that must be configured, =
and
the two, three, or twelve optional variants of each. As I was going =
through
each of the classes that provide a view resolver (InternalViewResolver,
ResourceBundleViewResolver and XmlViewResolver), I began to wonder if I =
was
the only person who would like a simplified configuration. I think the
primary differentiation when comparing Spring or WebWork on the Web-tier
alone, is WebWork's simpler and more cohesive configuration file. I =
don't
think either framework's WEB MVC configuration provides any more general
functionality than the other, but I would like an optional resolver =
class
that allows a single configuration file to specify the Controllers, URL
Mapping, View Resolvers and the parameters that each may take. I don't =
think
this would be difficult either because of Spring's pluggability.
In Spring, in order to use a single controller I have to configure the:
viewResolver / instance of ResourceBundleViewResolver, XmlViewResolver,
or InternalViewResolver.
Used by the dispatcher servlet to resolve the ModelAndView's view
name (and locale) to a View class.
This object is retrieved "by name" by the dispatcher servlet, hence
there is only one per servlet context.
handlerMapping / instance of BeanNameUrlHandlerMapping or
SimpleUrlHandlerMapping.
Used by the dispatcher to
There can be many url handlers in a single servlet context since the
dispatcher servlet searches for bean's in its context that implement
the HandlerMapping interface. They can also be sorted in order to
give one handler priority over another when there is a URL that
matches multiple HandlerMappings.
=20
controller / instance of the Controller interface. There are a bunch of
these, and this probably represents one of the more
confusing aspects of Spring.
=20
Each controller provides different functionality from the next, but
it seems like the design suffers a bit here. For example,
AbstractController is extended by MultiActionController,
BaseCommandController and ParameterizableViewController. Since a
controller must pick a single subclass to extend, a developer can
only take advantage of the benefits of one of these controllers. I
preferred WebWork's use of interfaces (and IOC) to drive the capabi-
lities of the Controller. This a moot point however, since I am only
focused on configuration at the moment.
Each of these three configuration areas (four if you count
ExceptionResolvers, five if you count HandlerAdapters, etc.) are =
powerful in
their flexibility, but somewhat cumbersome for someone coming from =
WebWork
(or Maverick). For many of us a simpler configuration would be a welcome
augmentation to Spring, and because of Spring's configuration =
flexibility, I
don't imagine it would take away from any features.
As an example for configuration, consider the following sample from the
petclinic example application that ships with Spring.
-----------------------------------------------------------------------
petclinic-servlet.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
<bean id=3D"viewResolver"
class=3D"org.springframework.web.servlet.view.ResourceBundleViewResolver"=
>
<property name=3D"basename"><value>views</value></property>
</bean>
<bean id=3D"urlMapping"
class=3D"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"=
>
<property name=3D"mappings">
<props>
<prop =
key=3D"/welcome.htm">clinicController</prop>
</props>
</property>
</bean>
<bean id=3D"clinicController"
class=3D"org.springframework.samples.petclinic.web.ClinicController">
<property name=3D"methodNameResolver">
<ref local=3D"clinicControllerResolver"/>
</property>
<property name=3D"clinic">
<ref bean=3D"clinic"/>
</property>
</bean>
<bean id=3D"clinicControllerResolver"
=20
class=3D"org.springframework.web.servlet.mvc.multiaction.PropertiesMethod=
NameR
esolver">
<property name=3D"mappings">
<props>
<prop key=3D"/welcome.htm">welcomeHandler</prop>
</props>
</property>
</bean>
views.properties
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
welcomeView.class=3Dorg.springframework.web.servlet.view.JstlView
welcomeView.url=3D/WEB-INF/jsp/welcome.jsp
-----------------------------------------------------------------------
This is a lot of configuration information when compared to a similar
WebWork configuration. It also is spread across two files, although I
suppose that there is a Spring technique to declare viewResolver data in =
the
petclinic-servlet.xml file, perhaps by using an XmlViewResolver and
embedding the XML data as an IOC property? Another unclear step is the
knowledge the developer must possess that his
ClinicController.welcomeHandler() method returns the view mapping named
'welcomeView'. It is this name that is looked up in the views.properties
file. This is somewhat unintuitive and other examples have tried to =
combat
this ambiguity by including the view mappings directly (sort of) in the
Controller configuration.
<bean id=3D"findOwnersForm"
=
class=3D"org.springframework.samples.petclinic.web.FindOwnersForm">
<property =
name=3D"formView"><value>findOwnersForm</value></property>
<property
name=3D"selectView"><value>selectOwnerView</value></property>
<property =
name=3D"successView"><value>ownerRedirect</value></property>
</bean>
This example demonstrates something us WebWork developers have used very
effectively for some time. The view is always returned as a simple =
string in
WebWork and this maps to the actual view via configuration information. =
The
same thing is occurring in the Spring example, but in a slightly =
backhanded
way. The SimpleFormController defines formView and successView as String
properties. If the controller completes successfully, it returns
getSuccessView() as its view and this in turn returns 'ownerRefirect' as =
the
mapped view. The developer also introduced a new view result called
'selectView'. In order to support this new result view, the developer =
has to
implement the selectView property in their subclass. Very cumbersome =
when
compared to WebWork's "always map" approach to view results.
Thanks for sticking with this unintentionally long post. I guess I set =
all
of this up to suggest an alternative approach to configuring Spring's =
web
MVC that is more compact and easier for new developers. It is based =
heavily
on WebWork's configuration, so it should prove even easier for WebWork
developers to migrate. I do realize that this configuration will ruffle =
the
feathers of some architects that laud Spring's separation of components, =
but
I appreciate the fact that a configuration change does not necessarily
negate an architecture. In fact it is a testament to Spring's solid
architecture that such a configuration may be made possible without =
changing
any of Spring's infrastructure.
proposed configuration - controller.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
<controller alias=3D"/welcome.htm"
=
class=3D"org.springframework.samples.petclinic.web.ClinicController"
method=3D"welcomeHandler">
<property name=3D"clinic"><ref bean=3D"clinic"/></property>
<results>
<result name=3D"selectView"
=20
class=3D"org.springframework.web.servlet.view.JstlView"
url=3D"/WEB-INF/jsp/welcome.jsp" />
<result name=3D"successView"
=20
class=3D"org.springframework.web.servlet.view.RedirectView"
url=3D"owner.htm" />
</results>
</controller>
These seven lines in a single file represent all of the configuration
information found in the prior 23 lines spread across a couple files. =
There
are probably other Spring capabilities that I am not representing here =
in
this small example, but this is at least 95 percent of the types of web
controllers that I use. I also am not showing the new configuration bean
that would have to be configured in the xxx-servlet.xml file.
I believe this configuration data should exist in the xxx-servlet.xml =
file
or loadable from a separate file. No matter where it exists, it should =
be
loadable as an applicationContext object with full Spring IOC =
capability,
including parameter substitution.
If I was going to approach writing this new configuration support bean I
would create a configuration bean that can read in the controller.xml =
file
in a Spring IOC manner. I guess I would base this work on =
XmlViewResolver,
although I am unsure if this includes all of the IOC benefits =
automatically?
<bean id=3D"viewResolver"
class=3D"org.springframework.web.servlet.mvc.ControllerConfig">
<property name=3D"location">
<value>/WEB-INF/controller.xml</value>
</property>
</bean>
I would have to give the bean an id of "viewResolver" because that is =
the
only property that the dispatcher loads by name. The dispatcher =
discovers
the other configuration parameters by searching for interface
implementations amongst all the configured beans.
So org.springframework.web.servlet.mvc.ControllerConfig would read the
controller.xml file and implement the following interfaces:
- org.springframework.web.servlet.ViewResolver
- org.springframework.web.servlet.HandlerExceptionResolver
- org.springframework.web.servlet.HandlerMapping
=20
I'm not sure what the best approach for loading the XML configuration =
file
is to get Spring's IOC support, including external bean references from =
the
applicationContext and servletContexts. Also it should be reloadable =
during
development through the use of a flag. Any ideas on where to start with
that?
=20
Once the configuration is loaded, it seems like the interface
implementations would be straightforward. =20
Thanks for reading this far. Hopefully it wasn't a waste of your time!=20
- jim cook
-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=3D1356&alloc_id=3D3438&op=3Dclick
_______________________________________________
Springframework-developer mailing list
Spr...@li...
https://lists.sourceforge.net/lists/listinfo/springframework-developer
|