Spring MVC Tiles Integration on Eclipse and Tomcat

Spring MVC allows integration with many technologies. If you remember Sturts with Tiles, then a similar feature is provided by Spring MVC. There is minor variation in the way Spring MVC Tiles integration on Eclipse and Tomcat is implemented. Here are the details in this tutorial.In this article, we take previous example forward for Spring MVC Tiles integration. You are already aware of the advantages of usage of Tiles in an application. How you can define layout, and then configure to plug-in different strings and jsps. This technology allows us to reuse presentation tier components in an elegant way.

In the previous article, if you look at the controller, at the end of onSubmit() method, we gave the Jsp path to which the control is to be directed. This would be the first place where the change is required. Instead of Jsp name, now we will give an identifier, which represents the construct of multiple components as per Tiles requirement. Next, we need something which identifies that the forward/redirect given by the controller is actually pointing to a tiles composition to construct a page. In short, this will integrate Spring MVC with Tiles. Further, we require tiles definitions for all our views. Last is the change in existing jsps to pull out the common part in the layout jsp and other component jsps, and keep only the functional presentation in our old jsps. Let us see each of the changes one by one, and the rationale behind those changes.

Changes Required for Spring MVC Tiles Integraiton:

Additional Jars:

To enable tiles functionality in our application, we need following jars. The ‘commons’ jars are required by tiles.

tiles-api-2.0.6.jar

tiles-core-2.0.6.jar

tiles-jsp-2.0.6.jar

commons-beanutils-1.7.0.jar

commons-digester-1.8.jar

Jsp Changes:

Earlier we had jsps, which did entire presentation business for us. If you observe these jsps in your practical examples, there will be considerable amount of code that can be reused. This code can be javascript, stylesheets, headers, footers, left menu (with minor change) and some includes. Using tiles we can identify these plugable components. Following layout jsp has such place holders, which define the reusable components. (This is just an example, in reality the layout jsp can be more complex than this).

In this jsp, we have two types of place holders, one is for string, and other is for jsps itself. In Tiles 2, there is insertAttribute element in tag library, that is used to insert a jsp, while strings are inserted using getAsString element, same as Tiles 1.

Layout.jsp

layout.jsp

In this example, I am not putting anything in left.jsp, header.jsp and footer.jsp. All jsps are just to print whether those are left, header, or footer.

Main change is in the jsps containing functionality. We have to moved the common part out from here to the layout.jsp. This is how the helloworld.jsp will look like. Similar change is done in hellovisitor.jsp.

Helloworld.jsp

 helloworld.jsp

Configuration Changes:

First thing we need to introduce in configuration is the assembling of the different jsp components. In this xml below, we have one base definition which assembles all components, and then we have page specific definitions which extend from this base definition. This is inheritance in object oriented terms. The definition name ‘helloworld’ will be used to represent the view.

Layout-tiles.xml


 Second major configuration change is in the SpringMVCTutorial-servlet.xml, here we need to integrate the spring container with tiles. If you compare this xml with the previous one, then following changes can be seen.

We are using url mapping handler, hence the helloworld.htm mapping to the controller bean is now defined. Thus the bean is independent of its usage now. (This has nothing to do with tiles integration, but it is cleaner way of using Spring MVC configuration.)

We are going to use url based view resolver with tiles to resolve the view name given by controller class, and map it to the tiles definition.

Next is tiles configure, this integrates our layout-tiles.xml with spring container. You have to give the layout definition in this configuration as a property. At applications start up all the definitions will be loaded in memory by the (application) server, and kept ready for use.

SpringMVCTutorial-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”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd”>

<bean class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
<property name=”mappings”>
<props>
<prop key=”/helloworld.htm”>helloWorldController</prop>
<prop key=”/hellovisitor.htm”>helloVisitorController</prop>
</props>
</property>
</bean>

<bean id=”helloWorldController”
class=”com.myorg.springmvctutorial.web.controller.HelloWorldController” >
</bean>
<bean id=”helloVisitorController”
class=”com.myorg.springmvctutorial.web.controller.HelloVisitorController” >
<property name=”commandName”>
<value>visitor</value>
</property>
<property name=”commandClass”
value=”com.myorg.springmvctutorial.web.command.Visitor” />
<property name=”bindOnNewForm”>
<value>true</value>
</property>
</bean>
<bean id=”viewResolver”
class=”org.springframework.web.servlet.view.UrlBasedViewResolver”>
<property name=”viewClass”>
<value>
org.springframework.web.servlet.view.tiles2.TilesView
</value>
</property>
</bean>
<bean id=”tilesConfigurer” class=”org.springframework.web.servlet.view.tiles2.TilesConfigurer”>
<property name=”definitions”>
<list>
<value>/WEB-INF/layout-tiles.xml</value>
</list>
</property>
</bean>

</beans>

Java Code Change:

It is simple, now we are going to use different view name. Hence the last line of onSubmit() method will be

      return new ModelAndView(“hellovisitor”, dataMap);

See it working:

Build the project and run on tomcat server. This is how the page will be presented when accessed.

 Spring MVC Tiles Integration

Problems Faced in Spring MVC Tiles Integration:

Instead of jsp, only jsp names presented on the page displayed. I ended up in putting an hour to solve this, when I accessed the url after deploying on tomcat, instead of above output, it presented only the header.jsp, footer.jsp etc. arranged by layout, instead of actually executing the jsps. The problem was in layout definition. – I am having the jsps in document root. Hence in attribute definition I gave    <put-attribute name=”body” value=”hellovisitor.jsp“/>, and not “/helloworld.jsp”. It caused the trouble.

Second was the submit button was doing nothing on press. After, looking at the ‘view source’ of the presented page, I found that the form:form tag is not executed by the tag library. I had moved all tag library definitions to the layout.jsp. When I moved those to the respective components and kept only tiles definition in the layout.jsp, it worked properly.

Source Code:

You can download the complete source code (excluding libraries) here.

References:

Spring MVC Documentation

3 Comments

  1. i m getting this error in spring tiles tutorila can u please help me out i m stucking so much time please help me.. m using all the jar file as per your tutorial instructions …………

    javax.servlet.ServletException: Servlet.init() for servlet SpringMVCTutorial threw exception
    org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
    org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
    java.lang.Thread.run(Unknown Source)

    root cause

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ’tilesConfigurer’ defined in ServletContext resource [/WEB-INF/SpringMVCTutorial-servlet.xml]: Invocation of init method failed; nested exception is org.apache.tiles.definition.DefinitionsFactoryException: XML error reading definitions.
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    java.security.AccessController.doPrivileged(Native Method)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:402)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
    javax.servlet.GenericServlet.init(GenericServlet.java:212)
    org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
    org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
    java.lang.Thread.run(Unknown Source)

    root cause

    org.apache.tiles.definition.DefinitionsFactoryException: XML error reading definitions.
    org.apache.tiles.definition.digester.DigesterDefinitionsReader.read(DigesterDefinitionsReader.java:270)
    org.apache.tiles.definition.UrlDefinitionsFactory.readDefinitions(UrlDefinitionsFactory.java:286)
    org.apache.tiles.definition.UrlDefinitionsFactory.init(UrlDefinitionsFactory.java:130)
    org.apache.tiles.impl.BasicTilesContainer.initializeDefinitionsFactory(BasicTilesContainer.java:406)
    org.apache.tiles.impl.BasicTilesContainer.init(BasicTilesContainer.java:130)
    org.apache.tiles.factory.TilesContainerFactory.initializeContainer(TilesContainerFactory.java:232)
    org.apache.tiles.factory.TilesContainerFactory.createTilesContainer(TilesContainerFactory.java:198)
    org.apache.tiles.factory.TilesContainerFactory.createContainer(TilesContainerFactory.java:163)
    org.springframework.web.servlet.view.tiles2.TilesConfigurer.createTilesContainer(TilesConfigurer.java:214)
    org.springframework.web.servlet.view.tiles2.TilesConfigurer.afterPropertiesSet(TilesConfigurer.java:201)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    java.security.AccessController.doPrivileged(Native Method)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:402)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
    javax.servlet.GenericServlet.init(GenericServlet.java:212)
    org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
    org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
    java.lang.Thread.run(Unknown Source)

    root cause

    org.xml.sax.SAXParseException: Document is invalid: no grammar found.
    org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
    org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
    org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
    org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
    org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    org.apache.commons.digester.Digester.parse(Digester.java:1765)
    org.apache.tiles.definition.digester.DigesterDefinitionsReader.read(DigesterDefinitionsReader.java:267)
    org.apache.tiles.definition.UrlDefinitionsFactory.readDefinitions(UrlDefinitionsFactory.java:286)
    org.apache.tiles.definition.UrlDefinitionsFactory.init(UrlDefinitionsFactory.java:130)
    org.apache.tiles.impl.BasicTilesContainer.initializeDefinitionsFactory(BasicTilesContainer.java:406)
    org.apache.tiles.impl.BasicTilesContainer.init(BasicTilesContainer.java:130)
    org.apache.tiles.factory.TilesContainerFactory.initializeContainer(TilesContainerFactory.java:232)
    org.apache.tiles.factory.TilesContainerFactory.createTilesContainer(TilesContainerFactory.java:198)
    org.apache.tiles.factory.TilesContainerFactory.createContainer(TilesContainerFactory.java:163)
    org.springframework.web.servlet.view.tiles2.TilesConfigurer.createTilesContainer(TilesConfigurer.java:214)
    org.springframework.web.servlet.view.tiles2.TilesConfigurer.afterPropertiesSet(TilesConfigurer.java:201)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    java.security.AccessController.doPrivileged(Native Method)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:402)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
    javax.servlet.GenericServlet.init(GenericServlet.java:212)
    org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
    org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)

    • root cause

      org.xml.sax.SAXParseException: Document is invalid: no grammar found.

      As per above exception, there is problem with the xml configuration for tiles. Please check the version of tiles as there is difference between the previous config schema as compared to recent one.

  2. Ashish’ problems may have nothing to do with the Tiles version. They may be due to the copy of the SpringMVCTutorial-servlet.xml file displayed, i.e., if he used the version of the file found in the zip he’d be fine, but if he cut and pasted it from the online version an XML exception would be thrown as it is not well-formed XML (the close tag for on line 23 should come after line 19; the close tag on line 39 should actually come after line 23).

Leave a Reply

Your email address will not be published.


*