Monday, January 19, 2015

Spring 4 and Tiles 3 programmatic or annotation based configuration

In the following tutorial, we are going to use programmatic / no-xml based spring 4.0.1 MVC project and Apache tile 3 configuration. I have used maven with STS 3.6.2.RELEASE to create the project.


Following are the versions user in this tutorial

  • Spring: 4.0.1.RELEASE
  • Java: 1.8
  • Servlet-api: 3.1.0
  • Servlet-jsp: 2.2
  • Servlet-jstl: 1.2
  • Apache tiles: 3.0.5

Now, lets see step by step approach of programmatic configuration of spring mvc project.


  • Create Project
    For project creation checkout "Spring 4 programmatic or annotation based configuration

  • Add following dependencies to pom.xml
    <!-- Apache Tiles -->
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-api</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-core</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-template</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-el</artifactId>
    <version>3.0.5</version>
    <scope>compile</scope>
    </dependency>
  • Add TilesViewResolver and TilesConfigurer to MVCConfig class file
    package com.test.web.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.support.ReloadableResourceBundleMessageSource;
    import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
    import org.springframework.web.servlet.view.tiles3.TilesView;
    import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

    /**
     * @author Bhimu
     *
     *<code>Spring MVC configuration class</code>
     */
    @EnableWebMvc
    @Configuration
    @ComponentScan(basePackages = { "com.skillzview.web" })
    public class MVCConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }


    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
    }


    /**
    * <code>Resolves views selected for rendering by @Controllers to tiles resources in the Apache TilesConfigurer bean</code>
    */
    @Bean
    public TilesViewResolver getTilesViewResolver() {
    TilesViewResolver tilesViewResolver = new TilesViewResolver();
    tilesViewResolver.setViewClass(TilesView.class);
    return tilesViewResolver;
    }


    /**
    * <code>Configures Apache tiles definitions bean used by Apache TilesViewResolver to resolve views selected for rendering by @Controllers</code>
    */
    @Bean
    public TilesConfigurer getTilesConfigurer() {
    TilesConfigurer tilesConfigurer = new TilesConfigurer();
    tilesConfigurer.setCheckRefresh(true);
    tilesConfigurer.setDefinitionsFactoryClass(TilesDefinitionsConfig.class);

    // Add apache tiles definitions
    TilesDefinitionsConfig.addDefinitions();

    return tilesConfigurer;
    }
    }
  • Create TilesDefinitionsConfig which implements DefinitionsFactory interface.
    package com.test.web.config;

    import java.util.HashMap;
    import java.util.Map;

    import org.apache.tiles.Attribute;
    import org.apache.tiles.Definition;
    import org.apache.tiles.definition.DefinitionsFactory;
    import org.apache.tiles.request.Request;

    /**
     * @author Bhimu
     *
     * <code>Apache tiles configuration class. Implements DefinitionsFactory to provide programmatic configuration for Apache tiles.</code>
     *
     */
    public final class TilesDefinitionsConfig implements DefinitionsFactory {

    private static final Map<String, Definition> tilesDefinitions = new HashMap<String,Definition>();
    private static final Attribute BASE_TEMPLATE = new Attribute("/WEB-INF/views/layout/defaultLayout.jsp");

    @Override
    public Definition getDefinition(String name, Request tilesContext) {
    return tilesDefinitions.get(name);
    }

    /**
    * @param name <code>Name of the view</code>
    * @param title <code>Page title</code>
    * @param body <code>Body JSP file path</code>
    *
    * <code>Adds default layout definitions</code>
    */
    private static void addDefaultLayoutDef(String name, String title, String body) {
    Map<String, Attribute> attributes = new HashMap<String,Attribute>();

    attributes.put("title", new Attribute(title));
    attributes.put("header", new Attribute("/WEB-INF/views/layout/header.jsp"));
    //attributes.put("menu", new Attribute("/WEB-INF/views/layout/menu.jsp"));
    attributes.put("body", new Attribute(body));
    attributes.put("footer", new Attribute("/WEB-INF/views/layout/footer.jsp"));

    tilesDefinitions.put(name, new Definition(name, BASE_TEMPLATE, attributes));
    }

    /**
    * <code>Add Apache tiles definitions</code>
    */
    public static void addDefinitions(){
    addDefaultLayoutDef("home", "Home", "/WEB-INF/views/home.jsp");
    }
    }
  • Create layout JSP files.
  • defaultLayout.jsp contents.
    <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  
    <html>
      <head>    
       <title><tiles:insertAttribute name="title" ignore="true"></tiles:insertAttribute></title>
    </head>
    <body style="background-color: #FFF">
    <div class="page">
           <tiles:insertAttribute name="header" />
           <div class="content">
            <div id="body">
                <tiles:insertAttribute name="body" />
               </div>
           </div>
           <tiles:insertAttribute name="footer" />
       </div>
    </body>
    </html>
  • Put whatever content you want in header, footer and body(home.jsp) pages.

We are all set with configuration. now run your application. I have used tomcat 8 to run the project.

2 comments:

  1. I used aforesaid versions, still I get this error while running my app:
    SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.view.tiles3.TilesConfigurer#0' defined in ServletContext resource [/WEB-INF/spitter-servlet.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.apache.tiles.access.TilesAccess.setContainer(Lorg/apache/tiles/request/ApplicationContext;Lorg/apache/tiles/TilesContainer;Ljava/lang/String;)V

    ReplyDelete
  2. hi thanks for your articlce :-)

    I have found this example project:
    https://bitbucket.org/zxmax/spring-tiles/commits/3b58108b63f473fd0f81251d9ef0b7567caea9e2#chg-src/main/java/net/zxmax/config/TilesDefinitionConfig.java

    It is focused on a little detail about addDefaultLayoutDef method.
    Title and name parameters must be different.

    ReplyDelete