Friday 8 June 2012

Tiles Tutorial / Setup

Tiles

Tiles is a layout technology which carves pages into different sections or 'tiles'.  These can then be controlled and set using an xml file.  The easiest way to see this is just from a simple example.

Basic Tiles Config

The basic tiles configuration is an xml file (or multiple files) which defines the layouts.


<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
      
<tiles-definitions>

    <!-- Main layout -->
    <definition name="myapp.main" template="/WEB-INF/views/main.jsp">
        <put-attribute name="header" value="
/WEB-INF/views/header.jsp" />
        <put-attribute name="footer" value="
/WEB-INF/views/footer.jsp" />
    </definition>

    <definition name="myapp.home" extends="
myapp.main">
        <put-attribute name="body" value="
/WEB-INF/views/home.jsp" />
    </definition>

</tiles-definitions>

JSP Layout

The main.jsp page above is a standard JSP page which has a couple of 'holders' for the tiles elements.

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

    <html>
       <head />
        <body> 
            <!-- header -->
            <div class="header">
                <tiles:insertAttribute name="header" />
            </div>
             
            <!-- Central Container -->
            <div class="main_content">
                <tiles:insertAttribute name="body" />
            </div>
             
            <!-- footer -->
            <div class="footer">
                <tiles:insertAttribute name="footer" />
            </div>
        </body>
    </html>

Here you can see that the 'tiles' elements are brought in by the tiles tag.  These place holders are resolved by the xml file configuration for the page that has been requested. The ModelAndView will control the tiles name that is to be used.

Controller

The ModelAndView which is returned by the Controller will define the view to use based on the definition name in the tiles configuration.  For example


    ModelAndView mav = new ModelAndView("myapp.home");

This will use the 'myapp.home' definition which itself extends the 'myapp.main' definition.  As a result the full page is rendered using this hierarchy.

Spring Config

Finally the spring configuration needs to be told how to resolve the view name.  This is standard with spring, whether it is jsp view resolver, Freemarker, etc.  For tiles the configuration looks like this,

    <!-- Configure Tiles -->
    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">

        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles/myapp.xml</value>
            </list>
        </property>

        <property name="preparerFactoryClass"
                  value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/>
    </bean>

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

Here the 'tileConfigurer' gives a list of the definitions that are used.  This means that the definitions can be split into logical lumps and you don't end up with a file which is unmanageably large!  The 'viewResolver' is a standard spring element which tells spring how to resolve the view name.

Maven

Maven dependencies,

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

Preparer Classes

In the situation of having a menu defined in Tiles you don't want to have to remember to get every controller to put particular elements in the model. An easy way of extracting this is to use a ViewPreparer. Implement the ViewPreparer interface and complete the execute() method.  Then in the tiles definition you can add a preparer="myAppPreparer"

    <!-- Main layout -->
    <definition name="myapp.main" template="/WEB-INF/views/main.jsp" preparer="myAppPreparer">
        <put-attribute name="header" value="
/WEB-INF/views/header.jsp" />
        <put-attribute name="footer" value="
/WEB-INF/views/footer.jsp" />
    </definition>

The preparer name here is a fully qualified path name by default but can be a spring bean and therefore have its dependencies injected by spring. To make spring resolve these beans you need to have the 'preparerFactoryClass' configured in the spring tilesConfigurer(see above).

The HttpServletRequest can be obtained within a ViewPreparer as follows,

    /**
     * {@inheritDoc}
     */
    @Override
    public void execute(final TilesRequestContext tilesRequestContext, final AttributeContext attributeContext)
    {
        final HttpServletRequest request = (HttpServletRequest) tilesRequestContext.getRequestObjects()[0];
        ... other code to add to the request ...
    }

Loose Ends

There are occasions when a url is required within the application or spring context and the url needs to be mapped to the tiles names.  This is possible by using a spring mvc:controller

  <mvc:view-controller path="my_url" view-name="my.tiles.definition"/>

This then allows the 'my_url' to be used within the application and context.

No comments:

Post a Comment