Auto scanning tiles defs with spring MVC


The merits of Tiles vs Sitemesh
If you’re using Spring MVC with JSP then the chances are you’re going to want some kind of templating framework to build the pages. I started using Apache Tiles first but became frustrated with the amount of XML config required. Each page to be rendered via tiles needs to be defined in an XML file, if you have a lot of views this file will quickly become unwieldy.

Looking for an alternative I came across a framework called sitemesh. This takes a different approach to tiles resulting in far less configuration. The main difference is that tiles is a composite view framework, whereas, sitemesh is a decorator. A tiles view is composed of many smaller components, these might be the header, sidebar and body content. Each component in the definition will be a JSP containing markup for just that part of the page. Sitemesh on the other hand can take an entire webpage and merge it with a decorator page to get the final result.

I tried Sitemesh because I was drawn to the minimal configuration but after a while I found I wanted some of the old Tiles functionality. Specifically I found I wanted to create different sidebar fragments for different groups of pages. You could do this using Sitemesh by creating different decorators based on url patterns but this would place restrictions on the urls. I decided to take another look at tiles and see if there was a more convenient way of organising the tiles defs.

Configuring tiles with Spring MVC
As it turns out Spring MVC provides a neat way of configuring tiles. First we need to setup a view resolver for tiles based views. You can configure as many view revolvers as you like with an order of priority so I have a JSP resolver that is used if a tiles definition cannot be found.

Here is a snippet from the context-servlet.xml.

  <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass">
      <value>org.springframework.web.servlet.view.tiles2.TilesView</value>
    </property>
    <property name="order" value="0" />
  </bean>

  <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="order" value="1" />
  </bean> 

Now when my Spring MVC controllers return a String (view name), first it will check for a tile definition with a matching name and if that fails it then looks for a jsp in /WEB-INF/jsp/***viewname***.jsp. This gives me the flexibility of being able to display plain old JSP’s if I want too. This is the typical tiles configuration that I had used previously.

The cool bit is the way we load the tiles definitions. As of Tiles 2.2 there is a new auto-loader which automatically configures Tiles and turns on all the new features. It’s kind of like Tiles’ answer to mvc:annotation-driven. This means we no longer have to manually enter locations for the tiles xml configurations. Instead they will be scanned automatically providing we use the correct naming convention. This allows us to separate the definitions into as many files as is convenient whilst not having to maintain a list of the xml files in the context-servlet.xml.

  <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
    <property name="completeAutoload" value="true" />
  </bean> 

See Spring doc

This tells spring to defer configuring tiles to the new auto-loader in Tiles 2.2. To use this you’ll need to make sure you have tiles 2.2 or greater and also tiles-extras.jar. This is the tiles part of my pom if you’re using Maven.

  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>2.2.2</version>
  </dependency>

  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>2.2.2</version>
  </dependency>
		
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>2.2.2</version>
  </dependency>

From the Tiles documentation here is a list of the features this will turn on.

  • Freemarker and Velocity support
  • using EL, OGNL and MVEL as evaluation languages
  • using Wildcards and Regular expression as pattern matching languages
  • loading Tiles 1.x definition files
  • loads all the files named “tiles*.xml” under /WEB-INF and under every META-INF in any part of the classpath

A hierarchy of tiles
So now I have a folder structure under WEB-INF which contains all of my tiles views. At the top level I have a basic template.

    <definition name="base.definition" template="/WEB-INF/jsp/template/layout.jsp">
        <put-attribute name="title" value="" />
        <put-attribute name="header" value="/WEB-INF/jsp/template/header.jsp" />
        <put-attribute name="sidebar" value="/WEB-INF/jsp/template/sidebars/sidebar.jsp" />
        <put-attribute name="body" value="" />
        <put-attribute name="footer" value="/WEB-INF/jsp/template/footer.jsp" />
    </definition>

I then override this basic template with child templates that contain the correct sidebar to suit the context. E.G. for the admin section:

    <definition name="admin.definition" extends="base.definition">
        <put-attribute name="sidebar" value="/WEB-INF/jsp/template/sidebars/admin.jsp" />
    </definition>

Finally I can create my admin views based on the admin template.

    <definition name="admin" extends="admin.definition">
        <put-attribute name="title" value=" - Admin" />
        <put-attribute name="body" value="/WEB-INF/jsp/views/admin/admin.jsp" />
    </definition>

I could have setup my tiles defs like this before without the auto-loader. The only difference now is it’s easier for me to split the defs up into different tiles.xml files. This allows you to put the tiles defs in the same folder as the related JSP’s and have the whole lot organised in a logical folder structure. It also means you’re less likely to have to maintain one monster of an xml file that contains all your definitions or have to keep dipping into the context.xml to keep adding a new tiles.xml location.

Note: in the next post you can combine this with wildcards to really minimize the xml configuration required.
Wild card tiles defs with spring MVC

Advertisements

2 thoughts on “Auto scanning tiles defs with spring MVC

  1. Pingback: Wild card tiles defs with spring MVC | Ben Thurley

  2. Nick Weedon

    Nice article. Its a shame that in view of tiles-extras JAR dependencies, it is quite monolithic. Use of tiles-extras seems to be a necessary evil however if you are to use the ‘completeAutoload’ functionality as the required classes are directly within tiles-extras jar file.

    Excluding unwanted dependencies such as velocity or freemarker does not work as tiles-extras really does require these JAR files, even if you are not using freemarker of velocity.

    I am guessing that the reason for these dependencies is that completeAutoload also handles velocity and freemarker configuration files. It would be nice however if tiles-extras were broken up into smaller libraries.

    My main gripe is the velocity and freemarker logging that I see now when my application starts. A small price to pay however for such great functionality 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s