6

I have a Spring MVC application that is using Tile3. I have many static pages that need to embed them in the template of the website that is currently provided by tile3. (I need to have the same footer and header on all pages, either dynamic or static but not sure how to do the addressing for static pages).

Examples of static pages are index.jsp and aboutus.jsp. How can I access these static pages? should I do it through a controller?

I know I can use jsp:include but is that a good practice? isn't there any alternative as I am using tiles? This tutorial suggested to have separate controllers but I am not sure if that would be an optimal solution. As it sends unnecessary requests to the server.

Please let me know if there is any better option than Tiles

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">


   <listener>
       <listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
   </listener>
   <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>springapp</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springapp</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>


    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/springapp-servlet.xml</param-value>
    </context-param>



</web-app>

tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
  "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
  "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>
    <definition name="baseLayout" template="/WEB-INF/templates/baseLayout.jsp">
        <put-attribute name="title" value="Title is here (Tile)"/>
           <put-attribute name="header" value="header.jsp"/>
              <put-attribute name="menu" value="Title is here (Tile)"/>
                 <put-attribute name="body" value="Title is here (Tile)"/>
                 <put-attribute name="footer" value="footer.jsp"/>

    </definition>

    <definition name="hello" extends="baseLayout">
        <put-attribute name="title" value="HELERE"/>
          <put-attribute name="body" value="/WEB-INF/pages/pages/ewfsdfsdf.jsp"/>
    </definition>

        <definition name="index" extends="baseLayout">
        <put-attribute name="title" value="HELERE"/>
          <put-attribute name="body" value="/WEB-INF/pages/index.jsp"/>
    </definition>
</tiles-definitions>

Controller

@Controller
public class HelloController {

    protected final Log logger = LogFactory.getLog(getClass());

    public HelloController() {
        System.err.println("Constructor of HelloController");
    }

    @RequestMapping("/index.htm")
    public String index(){
        System.err.println("in index method");
        return "index";
    }

baseLayout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><tiles:insertAttribute name="title"/></title>
</head>
<body>
      <div id="container">
         <tiles:insertAttribute name="header"/>
         <tiles:insertAttribute name="menu"/>
         <tiles:insertAttribute name="body"/>
         <tiles:insertAttribute name="footer"/>
      </div>
</body>
</html>

index.jsp

<p>

This is the body of index page

</p>

Using JSP:include

   pros
     - No extra load neither on DB nor on server
   cons
     - To backup need to backup all static files
     - Might have overwork as each page should be prepared separately rather than having a single template for all pages and just populate the template
     - If need to add something to static pages need to change all pages.
Jack
  • 6,430
  • 27
  • 80
  • 151

3 Answers3

4

I just have found a great solution for it, to handle static pages we can use <mvc:view-controller> in servlet, sample code is here and here, it works with Tiles as well just make sure you have a definition for each path in your tiles.xml file.

 <mvc:view-controller path="/index" />
 <mvc:view-controller path="/"  view-name="index"/>
Jack
  • 6,430
  • 27
  • 80
  • 151
  • 1
    Thanks for the update Jack. So you added these lines only or were there additional modifications as well ? – Gyan Jun 17 '15 at 09:10
  • @Gyanapriya no problem they are the only lines I've added. Of course, you would need mvc namespace as well. Please vote the question and the answer up if you like them thanks. – Jack Jun 17 '15 at 10:09
  • 1
    Well done Jack, I wait to see if there would be any better solution before awarding the bounty. – Daniel Newtown Jun 17 '15 at 10:15
2

The way you have done it should work, but creating a new Mapper function for each static page is not a good idea. What you can do is in your controller

@RequestMapping("/page/{viewName}.htm")
public String index(@PathVariable(value="viewName") String viewName, Model model){
    if(isValidView(viewName)){
        model.addAttribute("viewName", viewName);
        return "page";
    }

    return null;
}

But you have to make sure the viewName is valid otherwise it would be security issue.

Also read this article

edit

isValidView function would can go either same class or BaseController class or a service call to check againts DB. Checking that file exists is not a good idea not because is takes resources but because the Path can be different on production server.

If the body of static page is just HTML you can load the content in DB and just do

<jsp:include page="/WEB-INF/pages/header.jsp"/>
${htmlContent}
<jsp:include page="/WEB-INF/pages/footer.jsp"/>

OR if you want to keep the body dynamic.

for tiles.xml you can have

<definition name="pageLayout" extends="baseLayout">
    <put-attribute name="title" value="HELERE"/>
      <put-attribute name="body" value="/WEB-INF/page.jpg"/>
</definition>

for page.jsp

<jsp:include page="/WEB-INF/pages/header.jsp"/>
<jsp:include page="/WEB-INF/pages/page/${viewName}.jsp"/>
<jsp:include page="/WEB-INF/pages/footer.jsp"/>
Zeronex
  • 434
  • 1
  • 3
  • 8
  • Thanks, should I have isValidView in the same class? Another problem is whenever I want to add a new static page I have to add its name to the isValidName method. If I want to check the filesystem to see if the file exists that would be an extra IO which is so expensive. – Jack Mar 04 '15 at 02:45
  • Is not there any better solution rather than sending a DB query? I suppose the best option would be to use include page. In other words, just include other pages into static pages and show them without using controller. – Jack Mar 04 '15 at 03:32
  • 1
    Well in that case create a new folder called **pages** in the same folder as **WEB-INF** and use extension **"html"** for file names and can access them directly without controller or tiles. You would have to copy and paste the header and footer in each static file. – Zeronex Mar 04 '15 at 04:55
  • I have mentioned using html file name extension because in **web.xml** you are only passing request for ***.htm** and not all requests. – Zeronex Mar 04 '15 at 04:56
  • 1
    In this case, I suppose rather than using DB for it, It would better to use in static pages, and move them to a visible location to public. – Jack Mar 12 '15 at 01:39
1

Well you could always load everything on the baseLayout page and create a higher level. What i mean is something like the following :

<div id=header> <tiles:insertAttribute name="header" /></div>
<div id=header> <tiles:insertAttribute name="menu" /></div> <iframe id='dynFrame' contenteditable="true"></iframe>' <div id=footer> <tiles:insertAttribute name="footer" /></div>

Now you can load content to this iframe from menu clicks with a simple script that says : loadPage(pageLink); And for the content of the function could be : $("#dynFrame").attr("src",pageLink);
The menu clicks can pass urls to the loadPage function and you would have only one copy of any static page you want to load.

I hope this helps.

Gyan
  • 1,176
  • 1
  • 12
  • 26
  • 1
    Is not there any better option? using iframe has more dis than advantages. – Jack Mar 12 '15 at 22:56
  • The thing is to keep that center portion dynamic and always changing. you'll have to figure out a way to configure tiles to extend from a different base and load the html content inside via ajax calls perhaps. If your ajax reply from the controller can be configured to return only that tile which needs to be loaded, you should be well on your way to getting this done. – Gyan Mar 13 '15 at 11:39