How to handle addressing to static pages in Spring MVC
Asked Answered
K

3

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.
Karlotta answered 4/3, 2015 at 1:52 Comment(3)
post an example of your JSP fileMarvellamarvellous
@Marvellamarvellous I just put a sample for index.jspKarlotta
Thanks Daniel for the bounty.Karlotta
K
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"/>
Karlotta answered 17/6, 2015 at 2:30 Comment(3)
Thanks for the update Jack. So you added these lines only or were there additional modifications as well ?Apple
@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.Karlotta
Well done Jack, I wait to see if there would be any better solution before awarding the bounty.Midis
M
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"/>
Marvellamarvellous answered 4/3, 2015 at 2:19 Comment(5)
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.Karlotta
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.Karlotta
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.Marvellamarvellous
I have mentioned using html file name extension because in web.xml you are only passing request for *.htm and not all requests.Marvellamarvellous
In this case, I suppose rather than using DB for it, It would better to use <jsp:include> in static pages, and move them to a visible location to public.Karlotta
A
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.

Apple answered 12/3, 2015 at 13:38 Comment(2)
Is not there any better option? using iframe has more dis than advantages.Karlotta
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.Apple

© 2022 - 2024 — McMap. All rights reserved.