How do I add .jsp headers and footers to my Spring MVC web app?

18,474

I found your question whilst researching :-) Not sure if my solution is <good | bad | a hack | already exists> or if there is a better way but it's working for my current project.

In your myapp-servlet.xml you can extend the viewResolver viewClass with your own implementation:

myapp-servlet.xml

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:viewClass="com.my.app.view.JstlView"
  p:prefix="/WEB-INF/views/"
  p:suffix=".jsp"/>

By overriding the renderMergedOutputModel you can force all views to really be a template in which you can define your global layout and then simply <jsp:include/> your partial(s).

JstlView.java

package com.my.app.view;

import java.util.*;
import org.springframework.web.servlet.view.InternalResourceView;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JstlView extends InternalResourceView {
    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String dispatcherPath = prepareForRendering(request, response);

        // set original view being asked for as a request parameter
        request.setAttribute("partial", dispatcherPath.substring(dispatcherPath.lastIndexOf("/") + 1);

        // force everything to be template.jsp
        RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/template.jsp");
        rd.include(request, response);
    }
}

If you look Spring's InternalResourceView.java you'll get a better idea of what Spring is doing when determining what view to use.

template.jsp

<!doctype html>
<html lang="en">
<head></head>
<body>
    <header>
        <jsp:include page="header.jsp"/>
    </header>
    <jsp:include page="${partial}"/>
    <footer>
        <jsp:include page="footer.jsp"/>
    </footer>
</body>
</html>

How to obtain request / session / servletcontext attribute in JSP using EL? helped me here with getting the attribute value ${partial} out.

simple_partial.jsp

<p>I'm a partial!</p>

Then in a controller, return the simple_partial view

App.java

package com.my.app.controller;

import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value="/")
public class App{
    @RequestMapping(method = RequestMethod.GET)
    public String index() {
        return "simple_partial";
    }
}

which will get wrapped by the template.jsp and responded out.

Share:
18,474
Xonatron
Author by

Xonatron

Matthew Doucette: Co-founder + Board Member, Ignite Labs Game Development Faculty + Faculty Chair, NSCC Truro Campus Xbox MVP, Microsoft Co-founder + Game Producer + Lead Programmer + CEO, Xona Games (Full resume at matthewdoucette.com.)

Updated on June 14, 2022

Comments

  • Xonatron
    Xonatron almost 2 years

    How do I add .jsp headers and footers to my Spring MVC web app?

    I know there's many different answers, but I would like to know (them all really but more importantly) what is the proper way to do this? I'm just learning Spring and I have a hint the answer lies with HandlerInterceptor. For now, I might just do so .jsp includes. Even with this include solution, could you detail where I would place the headers/footers structurally? Any advice or direction would be great.

  • Xonatron
    Xonatron about 12 years
    Any answers not using other people's code? For now I do a simple include for a header and footer.
  • duffymo
    duffymo about 12 years
    Then that's your answer. You don't need anything else from this site.
  • Xonatron
    Xonatron about 12 years
    thank you, but my question was much beyond where I was already at. For anyone else reading this, I would still appreciate any input or elaboration.
  • duffymo
    duffymo about 12 years
    I'd recommend looking at the links I provided. Even if you don't want to use "other people's code", you can get insight into how they thought about it.
  • rmpt
    rmpt over 8 years
    clean and simple answer. But what if we want to add some exceptions to it? Say I want to have a login.jsp page without the header/footer, how can we reach that? And I think there's another issue. If we want a partial with some dynamic content passed through ModelAndView, they will not take effect, i.e., in the call stack Controller > Partial > ViewResolver, the data inside the model will be passed into the ViewResolver and reach the template and not the partial view. I do not know if I was clear, but I tried.
  • andyb
    andyb over 8 years
    Good questions. It's been a while since I wrote this and I can't exactly remember what I did. I think I used rd.forward(requestToExpose, getRequestToExpose(request)) in the JstlView to forward onto another resource. You can also get the path for the request dispatcher with prepareForRendering(getRequestToExpose(request), response). I believe that an @ResponseBody annotated method that does return new ModelAndView(partial, model, modelObject) was correctly reaching the partial. I probably used exposeModelAsRequestAttributes(model, requestToExpose) in my renderMergedOutputModel
  • andyb
    andyb over 8 years
    I'll try to find some of the code and edit my answer later.
  • Chizbox
    Chizbox over 5 years
    are there any updates on this? im also in the same scenario