Convention over Configuration for Spring MVC
From Coder's Log
After finally deciding to get on the ruby on rails wagon, and building a few small websites, it suddenly got that much more tedious to maintain spring's *-servlet.xml files. Most of the changes in the files are so repetitive that there had to be a better away, and with the latest version of spring(2.0.2) it is actually quite possible. Techincaly it was possible before but prior to this version there are bugs in the UrlFilenameResolver
Contents |
Autowire you Controllers
Nothing really special here but autowiring your controllers could save quite a bit of copy pasting
<bean id="myController" class="x.y.z.MyController" autowire="byName" />
Autowire will match all bean properties in the controller to already existing beans in the context so injecting the Dao objects can most of the time be done automatically by maintaining the names of the beans same as the names of the properties
Auto map controllers to urls
Often enough we want our urls to resemble the names of the controllers we have in the context such that a bean of type Controller which is called "welcomeController" should be mapped to a url servlet/welcome. Thats where ControllerClassNameHandlerMapping comes in and it does just that. I also suggest ordering urlMappings this way if you have multiple you won't go scratching your head why something isn't working right away.
<bean id="urlMappingControllers" class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"> <property name="order" value="1" /> </bean>
Auto map jsps/velocity/freemarker templates
Not all templates need to be backed by a Controller, sometimes its sufficient just to be able to import other templates to produce an informational page.
The following code will try to resolve any url using the viewResolver configured in the xml file.
<bean id="filenameViewController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /> <bean id="urlMappingNoControllers" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="*">filenameViewController</prop> </props> </property> <property name="order" value="2" /> </bean>
Note: The order parameter is what gives the other urlMapping a priority over this one such that if no other mapping can match a url try to resolve a template name. Note: This has to be the last resolver in the chain.
Putting everything together
As you have probably noticed the xml above is pretty generic and it would be great if we could isolate all of that generic code and put it into a separate file that we could later import
default-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- DEFAULTS, RESOLVERS, MAPPERS -->
<bean id="filenameViewController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
<bean id="urlMappingControllers" class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="order" value="1" />
</bean>
<bean id="urlMappingNoControllers" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="*">filenameViewController</prop>
</props>
</property>
<property name="order" value="2" />
</bean>
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="order" value="1" />
<property name="prefix" ref="prefix" />
<property name="suffix" value=".ftl" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
</beans>
using the default-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"> <bean id="myController" class="x.y.z.MyController" autowire="byName" /> <bean id="prefix" class="java.lang.String"> <constructor-arg value="/conversion/" /> </bean> <import resource="default-servlet.xml"/> </beans>
The bean prefix defines the prefix used by the view resolver
