2

I would like to have a Servlet handle all requests to JSP pages first. The Servlet will be used to set server side variables depending on the requested JSP.

For example, what I would like to achieve is given the url:example.com/index.jsp, the Servlet first handles the request by parsing out the requested JSP (index.jsp), sets variables that are specific to the requested index.jsp (using request.setAttribute) and then dispatches to the actual index.jsp (eg. /WEB-INF/index.jsp). The JSP will then have the correct variables it needs.

My problem so far is that I'm using "/*" as the mapping pattern for my Servlet. It handles the request, then uses requestDispatcher.forward("/WEB-INF/index.jsp") which ends up in an infinite loop since this matches the "/*" pattern as well.

How should my Servlet(s) handle the requested url? What should the I use as the mapping pattern(s) in web.xml?

Is there a standard setup for this? I'm just looking for a "best practices" way to set up pre-processing for all my JSPs.

Matthew
  • 8,183
  • 10
  • 37
  • 65
  • Actually the forward() call should not run through the pattern match. Can you check if maybe index.jsp forwards back to '/' or something? – John Smith Aug 10 '12 at 12:59
  • @kw4nta the WEB-INF/index.jsp doesn't do any forwarding and I don't see anything in web.xml (I removed the welcome file entry as well). Is there somewhere else I should check? – Matthew Aug 10 '12 at 13:06
  • 1
    @kw4nta: You are wrong. How do you think that the JSPs are otherwise handled by the container's builtin `JspServlet` which is mapped on `*.jsp`? Matthew: please don't pay attention to this incorrect statement. It would only confuse you more. – BalusC Aug 10 '12 at 13:08

1 Answers1

1

The /* is in first place a strange choice for a servlet URL pattern. This is normally exclusively to be used by filters. Servlets are by default namely also invoked on forwards and includes, but filters not. Using /* would completely override the container's builtin JspServlet which ought to be invoked on *.jsp during a forward.

Rather use a more specific URL pattern like /pages/*, /app/*, *.do, *.html, etcetera.

When using a prefix servlet mapping, like /pages/* and you would like to hide the extra path from the URL, then you should keep the prefix servlet mapping as is, put all other resources in a common path (usually it are only the static resources like CSS/JS/images) and create an additional filter which checks if it's a resource request and if so, then continue the chain or if not, then forward to the servlet. This does not change the URL. The servlet can in turn just safely forward to the JSP.

Here's an example assuming that your servlet is mapped on /pages/* and that all your (static) resources which should not be handled by the servlet are placed in /resources folder (you can just keep your JSPs in /WEB-INF, that part doesn't need to be changed; the forward wouldn't hit the filter anyway).

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/resources/")) {
    chain.doFilter(request, response);
} else {
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

Finally just map the above filter on an URL pattern of /*.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks BalusC. Does this mean that the url used to access would be example.com/pages/index.jsp instead of example.com/index.jsp? – Matthew Aug 10 '12 at 13:24
  • Without the filter, yes, but with the filter, no. – BalusC Aug 10 '12 at 13:24
  • This works wonderfully. For anyone that was experiencing something similar to my problem, adding the filter does the trick by sending JSP requests to "/pages/theRequested.jsp" which the Servlet then handles by stripping off "/pages/" substituting "/WEB-INF/" and then uses RequestDispatcher#forward to the right location: "/WEB-INF/theRequested.jsp" – Matthew Aug 10 '12 at 13:55
  • You're welcome. You can by the way also just use straight `request.getPathInfo()` without the need to strip/manipulate the URI: `getRequestDispatcher("/WEB-INF" + request.getPathInfo())`. See also the "Design patterns" link in the "See also" section of my answer. – BalusC Aug 10 '12 at 13:57