Chapter 11. Template with Tiles

When it comes to web application development, reusability and maintenance are two important factors that need to be considered. Apache Tiles is another popular open source framework that encourages reusable template-based web application development.

In this chapter, you are going to see how to incorporate the Apache Tiles framework within a Spring MVC application, so that we can obtain maximum reusability of frontend templates with the help of Apache Tiles. Apache Tiles are mostly used to reduce redundant code in the frontend by leveraging frontend templates. After finishing this chapter, you will have a basic idea about decomposing pages using reusable Apache Tile templates.

Enhancing reusability through Apache Tiles

In the past, we developed a series of web pages (Views) as part of our webstore application, such as a page to show products, another page to add products, and so on. Although every View has served a different purpose, all of them share a common visual pattern; each page has a header, a content area, and so on. We hardcoded and repeated those common elements in every JSP View page. But this is not a good idea because, in future, if we want to change the look and feel of any of these common elements, we have to change every page in order to maintain a consistent look and feel across all the web pages.

To address this problem, modern web applications use template mechanisms; Apache Tiles is one such template composition framework. Tiles allow developers to define reusable page fragments (tiles), which can be assembled into a complete web page at runtime. These fragments can have parameters to allow dynamic content. This increases the reusability of templates and reduces code duplication.

Time for action - creating Views for every View state

Okay, enough introduction, let's dive into Apache Tiles by defining a common layout for our web application and let the pages extend the layout:

  1. Open pom.xml. You can find pom.xml under the project root directory itself.
  2. You will be able to see some tabs under pom.xml; select the Dependencies tab and click on the Add button of the Dependencies section.
  3. A Select Dependency window will appear; enter org.apache.tiles as Group Id, tiles-extras as Artifact Id, 3.0.5 as Version, and select Scope as compile. Then click on the OK button and save pom.xml.
  4. Now create a directory structure called layouts/definitions/ under the src/main/webapp/WEB-INF/ directory and create an XML file called tiles.xml. Add the following content to it and save it:
          <?xml version="1.0" encoding="UTF-8" ?> 
          <!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> 
        
             <definition name="baseLayout" template="/WEB- 
          INF/layouts/template/baseLayout.jsp"> 
                <put-attribute name="title" value="Sample  
          Title" /> 
                <put-attribute name="heading" value="" /> 
                <put-attribute name="tagline" value="" /> 
                <put-attribute name="navigation" value="/WEB- 
          INF/layouts/template/navigation.jsp" /> 
                <put-attribute name="content" value="" /> 
                <put-attribute name="footer" value="/WEB- 
          INF/layouts/template/footer.jsp" /> 
             </definition> 
        
             <definition name="welcome" extends="baseLayout"> 
                <put-attribute name="title" value="Products" /> 
                <put-attribute name="heading" value="Products"  
          /> 
                <put-attribute name="tagline" value="All the  
          available products in our store" /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/products.jsp" /> 
             </definition> 
        
             <definition name="products" extends="baseLayout"> 
                <put-attribute name="title" value="Products" /> 
                <put-attribute name="heading" value="Products"  
          /> 
                <put-attribute name="tagline" value="All the  
          available products in our store" /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/products.jsp" /> 
             </definition> 
        
             <definition name="product" extends="baseLayout"> 
                <put-attribute name="title" value="Product" /> 
                <put-attribute name="heading" value="Product"  
          /> 
                <put-attribute name="tagline" value="Details"  
          /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/product.jsp" /> 
             </definition> 
        
             <definition name="addProduct"  
          extends="baseLayout"> 
                <put-attribute name="title" value="Products" /> 
                <put-attribute name="heading" value="Products"  
          /> 
                <put-attribute name="tagline" value="Add  
          Product" /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/addProduct.jsp" /> 
             </definition> 
        
             <definition name="login" extends="baseLayout"> 
                <put-attribute name="title" value="Login" /> 
                <put-attribute name="heading" value="Welcome to  
          Web Store!" /> 
                <put-attribute name="tagline" value="The one  
          and only amazing web store" /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/login.jsp" /> 
             </definition> 
        
             <definition name="cart" extends="baseLayout"> 
                <put-attribute name="title" value="Shopping  
          Cart" /> 
                <put-attribute name="heading" value="Cart" /> 
                <put-attribute name="tagline" value="All the  
          selected products in your cart" /> 
                <put-attribute name="content" value="/WEB- 
          INF/views/cart.jsp" /> 
             </definition> 
           
          </tiles-definitions> 
    
  5. Now create a directory called template under the src/main/webapp/WEB-INF/layouts/ directory and create a JSP file called baseLayout.jsp. Add the following content to it and save it:
          <%@ taglib prefix="c"  
          uri="http://java.sun.com/jsp/jstl/core"%> 
          <%@ taglib prefix="spring"  
          uri="http://www.springframework.org/tags"%> 
          <%@ taglib prefix="tiles"  
          uri="http://tiles.apache.org/tags-tiles"%> 
     
          <!DOCTYPE html> 
          <html lang="en"> 
          <head> 
          <meta charset="utf-8"> 
          <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
          <meta name="viewport" content="width=device-width,  
          initial-scale=1.0"> 
     
          <title><tiles:insertAttribute name="title" /></title> 
     
          <link rel="stylesheet"  
          href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css 
          /bootstrap.min.css"> 
     
          <script 
        
          src="https://ajax.googleapis.com/ajax/libs 
          /angularjs/1.5.1/angular.min.js"></script> 
     
          <script  
          src="/webstore/resources/js/controllers.js"></script> 
     
     
          </head> 
     
          <body> 
             <section class="container"> 
                <div class="pull-right" style="padding-right:  
          50px"> 
                   <a href="?language=en">English</a>|<a  
          href="?language=nl">Dutch</a> 
                   <a href="<c:url value="/logout"  
          />">Logout</a> 
                </div> 
             </section> 
     
             <div class="container"> 
                <div class="jumbotron"> 
                   <div class="header"> 
                      <ul class="nav nav-pills pull-right"> 
                         <tiles:insertAttribute  
          name="navigation" /> 
                      </ul> 
                      <h3 class="text-muted">Web Store</h3> 
                   </div> 
     
                   <h1> 
                      <tiles:insertAttribute name="heading" /> 
                   </h1> 
                   <p> 
                      <tiles:insertAttribute name="tagline" /> 
                   </p> 
                </div> 
     
                <div class="row"> 
                   <tiles:insertAttribute name="content" /> 
                </div> 
     
                <div class="footer"> 
                   <tiles:insertAttribute name="footer" /> 
                </div> 
     
             </div> 
          </body> 
          </html> 
    
  6. Under the same directory (template), create another template JSP file called navigation.jsp and add the following content to it:
          <%@ taglib prefix="spring"  
          uri="http://www.springframework.org/tags"%> 
     
          <li><a href="<spring:url  
          value="/market/products"/>">Home</a></li> 
          <li><a href="<spring:url  
          value="/market/products/"/>">Products</a></li> 
          <li><a href="<spring:url  
          value="/market/products/add"/>">Add Product</a></li> 
          <li><a href="<spring:url 
          value="/cart/"/>">Cart</a></li> 
    
  7. Similarly, create one last template JSP file called footer.jsp and add the following content to it:
          <p>&copy; Company 2016</p> 
    
  8. Now we have created the common base layout template and the tile definition for all our pages, we need to remove the common page elements from all our JSP View files. For example, if you remove all the common elements, such as the jumbotron section and others, from our products.jsp file, and keep only the container section, it would look as follows:

    Note

    Do not remove the tag lib references and link references.

          <%@ taglib prefix="c"  
          uri="http://java.sun.com/jsp/jstl/core"%> 
          <%@ taglib prefix="spring"  
          uri="http://www.springframework.org/tags"%> 
     
          <section class="container"> 
             <div class="row"> 
                <c:forEach items="${products}" var="product"> 
                   <div class="col-sm-6 col-md-3"  
          style="padding-bottom: 15px"> 
                      <div class="thumbnail"> 
                         <img src="<c:url  
          value="/img/${product.productId}.png"></c:url>" 
                            alt="image" style="width: 100%" /> 
                         <div class="caption"> 
                            <h3>${product.name}</h3> 
                            <p>${product.description}</p> 
                            <p>$${product.unitPrice}</p> 
                            <p>Available  
          ${product.unitsInStock} units in stock</p> 
                            <p> 
                               <a 
                                  href=" <spring:url  
          value="/market/product?id=${product.productId}" /> " 
                                  class="btn btn-primary">  
          <span class="glyphicon-info-sign  
          glyphicon" /></span> Details 
                               </a> 
                            </p> 
     
                         </div> 
                      </div> 
                   </div> 
                </c:forEach> 
             </div> 
          </section> 
    
  9. Similarly remove all the common elements other than the main container section from every JSP View file that is under the /src/main/webapp/WEB-INF/views directory; do not remove the taglib references.
  10. Now create a Tiles configuration called TilesConfig under the com.packt.webstore.config package in the src/main/java source folder, and add the following code to it:
          package com.packt.webstore.config; 
     
          import org.springframework.context.annotation.Bean; 
          import org.springframework.context 
          .annotation.Configuration; 
          import org.springframework.web.servlet 
          .view.UrlBasedViewResolver; 
          import org.springframework.web.servlet 
          .view.tiles3.TilesConfigurer; 
          import org.springframework.web.servlet 
          .view.tiles3.TilesView; 
     
          @Configuration 
          public class TilesConfig { 
     
              @Bean 
                 public UrlBasedViewResolver viewResolver() { 
                     UrlBasedViewResolver viewResolver = new  
          UrlBasedViewResolver(); 
                     viewResolver.setViewClass 
           (TilesView.class); 
                     viewResolver.setOrder(-2); 
                     return viewResolver; 
                 } 
     
                 @Bean 
                 public TilesConfigurer tilesConfigurer() { 
                     TilesConfigurer tilesConfigurer = new  
          TilesConfigurer(); 
                     tilesConfigurer.setDefinitions("/WEB- 
          INF/layouts/definitions/tiles.xml"); 
                     tilesConfigurer.setCheckRefresh(true); 
     
                     return tilesConfigurer; 
                 } 
          } 
    
  11. Now run our application and enter the URL http://localhost:8080/webstore/market/products. You will be able to see our regular products page with an extra navigation bar at the top and a footer at the bottom. You can add a product by clicking on the Add Product link:
    Time for action - creating Views for every View state

    Products page with the Apache Tiles View

What just happened?

To work with Apache Tiles, we need Apache Tiles related JARs, so from steps 1 to 3 we added those JARs via Maven dependencies. Step 4 is very important because we created our tiles definition file (tiles.xml) in that step. Understanding the tiles definition file is crucial to developing Apache Tiles-based applications, so you need to understand our tile definition file.

A tile definition file is a collection of definitions, where each definition can be associated with a template via the template attribute for the layout:

<definition name="baseLayout" template="/WEB-INF/layouts/template/baseLayout.jsp"> 
   <put-attribute name="title" value="Sample Title" /> 
   <put-attribute name="heading" value="Sample Heading" /> 
   <put-attribute name="tagline" value="Sample Tagline" /> 
   <put-attribute name="navigation" value="/WEB-INF/layouts/template/navigation.jsp" /> 
   <put-attribute name="content" value="" /> 
   <put-attribute name="footer" value="/WEB-INF/layouts/template/footer.jsp" /> 
</definition>  

Within each definition, we can define many attributes. These attributes can be a simple text value or a full-blown markup file. These attributes would be available in the template file via the <tiles:insertAttribute> tag. For example, if you open the base layout (baseLayout.jsp) template, you can see the following snippet under the jumbotron <div> tag:

<h1> 
   <tiles:insertAttribute name="heading" /> 
</h1> 
<p> 
   <tiles:insertAttribute name="tagline" /> 
</p> 

So at runtime, Apache Tiles would replace the <tiles:insertAttribute name="heading" /> tag with the value Sample Heading and similarly the <tiles:insertAttribute name="tagline" /> tag with the value Sample Tagline.

So the baseLayout definition is associated with the template /WEB-INF/layouts/template/baseLayout.jsp, and we can insert the defined attributes such as tile, heading, tagline, and more in the template using the <tiles:insertAttribute> tag.

Apache Tiles allows us to extend a definition just like how we extend a Java class, so that the defined attributes would be available for the derived definition, and we can even override those attributes values if we want. For example, look at the following definition from tile-definition.xml:

<definition name="products" extends="baseLayout"> 
   <put-attribute name="title" value="Products" /> 
   <put-attribute name="heading" value="Products" /> 
   <put-attribute name="tagline" value=" All the available products in our store" /> 
   <put-attribute name="content" value="/WEB-INF/views/products.jsp" /> 
   </definition> 

This definition is an extension of the baseLayout definition. We have only overridden the title, heading, tagline, and content attributes, and since we have not defined any template for this definition, it uses the same template that we configured for the baseLayout definition.

Similarly, we defined the tile definition for every possible logical View name that can be returned from our Controllers. Note that each definition name (except the baseLayout definition) is a Spring MVC logical View name.

From steps 5 to 7, we just created the templates that can be used in the tile definition. First, we created the base layout template (baseLayout.jsp), then the navigation template (navigation.jsp), and finally the footer template (footer.jsp).

Steps 8 and 9 explained how to remove the existing redundant content such as the jumbotron <div> tag from every JSP View page. Note you have to be careful while doing this—don't accidentally remove the taglib references.

In step 10, we defined our UrlBasedViewResolver for TilesView in order to resolve logical View names into the tiles View and also configured the TilesConfigurer to locate the tiles definition files by the Apache Tiles framework.

That's it; if you run our application and enter the URL http://localhost:8080/webstore/products, you will be able to see our regular products page with an extra navigation bar at the top and a footer at the bottom, as mentioned in step 11. You can add a product page by clicking on the Add Product link. Previously, every time a logical View name was returned by the Controller method, the InternalResourceViewResolver comes into action and finds the corresponding jsp View for the given logical View name. Now for every logical View name, the UrlBasedViewResolver will come into action and compose the corresponding View based on the template definition.

Pop quiz - Apache Tiles

Which of the following statements are true according to Apache Tiles?

  1. The logical View name returned by the Controller must be equal to the <definition> tag name.
  2. The <tiles:insertAttribute> tag acts as a placeholder in the template.
  3. A <definition> tag can extend another <definition> tag.
  4. All of the above.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.27.75