Spring MVC and Apache Tiles integration example

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏
Note: This is a re-edit of the post Spring 3 and Tiles 2 Integration. It uses now the latest version of Apache Tiles (at the time of the writing 3.0.1) and presents how Apache Tiles is used on top of Spring/Spring MVC to construct the layout of the Podcastpedia.org website
1. Why Apache Tiles?
Well, because it
- is a free open-sourced templating framework for modern Java applications. Based upon the Composite pattern it is built to simplify the development of user interfaces.
- remains, for complex web sites, the easiest and most elegant way to work alongside any MVC technology.
Tiles allows authors to define page fragments which can be assembled into a complete pages at runtime. These fragments, or tiles, can be used as simple includes in order to reduce the duplication of common page elements or embedded within other tiles to develop a series of reusable templates. These templates streamline the development of a consistent look and feel across an entire application.
Source code for this post is available on Github - podcastpedia.org is an open source project.
Contents
2. Necessary artifacts
Make sure you have the Tiles jars in the classpath. They can be downloaded directly from the official website, or by adding the proper dependencies to the pom.xml
file, if you use Apache Maven. I use the latter.
You can use one dependency to download all Tiles supported technologies with the following dependency declaration:
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>${tiles.version}</version>
</dependency>
or, as in my case where I didn’t need all the extras, you can put in your pom.xml
only the ones you need:
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-servlet</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-template</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-el</artifactId>
<version>${tiles.version}</version>
</dependency>
Note: The tiles.version
is currently 3.0.1. For this to work you need to use at least version 3.2 of Spring MVC.
3. Spring application context configuration for Tiles
For better readability and separation of concerns the Spring Tiles configuration has been placed in a separate application context file pcm-tiles.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:p="https://www.springframework.org/schema/p"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Views mapped in views.properties (PDF, XLS classes, and others) -->
<bean id="contentNegotiatingResolver"
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order"
value="#{T(org.springframework.core.Ordered).HIGHEST_PRECEDENCE}" />
<property name="favorPathExtension" value="true"/>
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
<constructor-arg>
<map>
<entry key="html" value="text/html"/>
<entry key="pdf" value="application/pdf"/>
<entry key="xsl" value="application/vnd.ms-excel"/>
<entry key="xml" value="application/xml"/>
<entry key="json" value="application/json"/>
<entry key="atom" value="application/xml"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
</bean>
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
<property name="order" value="#{contentNegotiatingResolver.order+1}" />
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views"/>
<property name="order" value="#{tilesViewResolver.order+1}" />
</bean>
<!-- Helper class to configure Tiles 3.x for the Spring Framework -->
<!-- See https://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/view/tiles2/TilesConfigurer.html -->
<!-- The actual tiles templates are in the tiles-definitions.xml -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tile-defs/templates.xml</value>
<value>/WEB-INF/tile-defs/definitions.xml</value>
</list>
</property>
</bean>
</beans>
Of interest here are
- the tilesViewResolver instance (line 37) which is a
org.springframework.web.servlet.View
implementation that retrieves the Tiles definitions. Theorder
and thecontentNegotiatingResolver
properties will be discussed in another post.
4. Creating and using Tiles pages
After installing and learning some of Tiles concepts, it’s time to show you how the pages are created for Podcastpedia.org
4.1. Create a template
Podcastpedia.org uses sort of a classic layout page structure:
As you can see the layout of the website is made of
- header which includes the social media connect, language selection logo and search bar
- navigation bar (menu)
- content – bulk data (body)
- footer which includes links to Contact, About Us, Disclaimer pages
The first step was to create a JSP page that acts as this layout and place it under _/WEB-INF/template/_template.jsp file:
<!DOCTYPE HTML>
<%@ include file="/WEB-INF/template/includes.jsp" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<html>
<head>
<meta name="google-site-verification" content="xxxxxxxxx" />
<title><tiles:insertAttribute name="title" ignore="true"/></title>
<meta name="description" content="<tiles:insertAttribute name="page_description" ignore="true"/>">
<c:url var="cssURL" value="/static/css/style.min.css"/>
<link href="${cssURL}" rel="stylesheet" type="text/css"/>
<link rel="icon" href="<c:url value="/static/images/favicon.ico"/>" type="image/x-icon" />
<link rel="shortcut icon" href="<c:url value="/static/images/favicon.ico"/>" type="image/x-icon" />
<meta charset="utf-8">
<meta property="og:image" content="<tiles:insertAttribute name="og_image" ignore="true"/>" />
<meta property="og:title" content="<tiles:insertAttribute name="og_title" ignore="true"/>" />
<meta property="og:description" content="<tiles:insertAttribute name="og_desc" ignore="true"/>"/>
<link rel="stylesheet" href="<tiles:insertAttribute name="jquery_ui_css" ignore="true"/>" />
</head>
<body>
<div id="banner">
<tiles:insertAttribute name="header" />
</div>
<div></div>
<tiles:insertAttribute name="navigation_bar" />
<div></div>
<div id="page">
<tiles:insertAttribute name="content" />
</div>
<div></div>
<div id="footer_wrapper">
<tiles:insertAttribute name="footer" />
</div>
</body>
</html>
You can see highlighted the four attributes header
, navigation_bar
(menu), content
(body) and footer
, which resemble the template layout from the picture. Besides these there are still some other Tiles attributes, like title
, page_description
or og_image
, that will get filled when rendering actual pages.
4.2. Create the composing pages
In this phase I had to create four JSP pages, that will take place of header
, navigation_bar
(menu), content
(body) and footer
attributes in the previously created template.
4.4. Create a definition
A definition is a composition to be rendered to the end user; essentially a definition is composed of a template and completely or partially filled attributes.
- If all of its attributes are filled, it can be rendered to the end user.
- If not all of its attributes are filled, it is called an abstract definition, and it can be used as a base definition for extended definitions, or their missing attributes can be filled at runtime.
4.4.1. Create abstract definition
Initially I created a /<em>WEB-INF/<em>tile-defs/template</em>.xml,</em>
with some default .jsp files (defaultHeader.jsp
, default_navigation_bar.jsp
, defaultContent.jsp
and defaultFooter.jsp
). This file acts as an abstract definition and is extended by all the other Tiles definitions across the Podcastpedia application:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "https://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
......
<definition name="defaultTemplate" template="/WEB-INF/template/template.jsp">
<put-attribute name="header" value="/WEB-INF/template/defaultHeader.jsp" />
<put-attribute name="navigation_bar" value="/WEB-INF/jsp/navigation_bar/default_navigation_bar.jsp" />
<put-attribute name="content" value="/WEB-INF/template/defaultContent.jsp"/>
<put-attribute name="footer" value="/WEB-INF/template/defaultFooter.jsp" />
</definition>
......
</tiles-definitions>
4.4.2. Create concrete definitions
Now let’s see some examples of definitions extending the defaultTemplate
defined above. For example the definition rendering the home page of Podcastpedia.org looks like the following:
<tiles-definitions>
......
<definition name="startPage_def" extends="defaultTemplate">
<put-attribute name="title" value="Podcastpedia, knowledge to go" />
<put-attribute name="page_description" value="Educate yourself with selected podcasts from various domains such as science, technology, education, medicine, people, environment, spirituality and much more..."/>
<put-attribute name="navigation_bar" value="/WEB-INF/jsp/navigation_bar/start_navigation_bar.jsp" />
<put-attribute name="content" value="/WEB-INF/jsp/start/start_page.jsp"/>
<put-attribute name="og_title" value="Podcastpedia, knowledge to go"/>
<put-attribute name="og_desc" value="Educate yourself with selected podcasts from various domains such as science, technology, education, medicine, people, environment, spirituality and much more..."/>
<put-attribute name="og_image" value="https://github.com/CodepediaOrg/podcastpedia/static/images/fb_share.png"/>
</definition>
......
</tiles-definitions>
Note that the Tiles attributes are filled with static values specific to the start page, and there are some attributes from the defaultTemplate
(like header
and footer
) that are not overriden – that means they will be inherited from the defaultTemplate
(one of the advantages of inheritence).
Let’s see another example. The podcastDetails
-definition is used to render a podcast details page :
<tiles-definitions>
......
<definition name="podcastDetails" extends="defaultTemplate">
<put-attribute name="title" expression="${podcast.title}"/>
<put-attribute name="page_description" expression="${podcast.description}"/>
<put-attribute name="navigation_bar" value="/WEB-INF/jsp/navigation_bar/podcast_details_navigation_bar.jsp" />
<put-attribute name="content" value="/WEB-INF/jsp/podcastDetails.jsp"/>
<put-attribute name="og_title" expression="${podcast.title}"/>
<put-attribute name="og_desc" expression="${podcast.description}"/>
<put-attribute name="og_image" expression="${podcast.urlOfImageToDisplay}"/>
</definition>
......
</tiles-definitions>
Notice here how I use dynamic values for the Tiles attributes – for example the title
attribute (line 4) is set dynamically with a value(${podcast.title}
) passed from the controller. If you follow the link – The Naked Scientist Podcast – and inspect the source code or the tab name in your browser, you will notice the title of the page was set to “- The Naked Scientists Podcast – Stripping Down Science”
Source code for this post is available on Github - podcastpedia.org is an open source project.
5. Summary
Well, this is pretty much all you need to do to integrate Tiles in Spring MVC – you’ve learned what libraries you need, how to configure Tiles in the application context, how to create abstract and concrete Tiles definitions, and fill them with both static and dynamic values.