8

I've an ErrorFilter which extends the spring GenericFilterBean. I want to show an error page decorated with tiles if some error happens.

Is there any way to set a view name from the filter?

<filter>
    <filter-name>errorFilter</filter-name>
    <filter-class>com.abc.filter.ErrorFilter</filter-class>
    <init-param>
        <param-name>errorPage</param-name>
        <param-value>/jsp/errorpage.jsp</param-value>
    </init-param>
</filter>

This is the configuration in web.xml and the doFilter method in errorfilter is the following:

public void doFilter(ServletRequest req, ServletResponse resp,
        FilterChain chain) throws IOException, ServletException {

    HttpServletRequest httpReq = (HttpServletRequest) req;
    StringBuffer reqUrl = httpReq.getRequestURL();
    try {
        chain.doFilter(req, resp);
    } catch (Exception ex) {
        String requestRepresentation = createRequestRepresentation(req);
        errorService.handleException(reqUrl.toString(), ex, requestRepresentation);
        req.getRequestDispatcher(
                getFilterConfig().getInitParameter("errorPage")).forward(req, resp);
    } catch (Error er) {
        errorService.handleError(reqUrl.toString(), er);
        req.getRequestDispatcher(
                getFilterConfig().getInitParameter("errorPage")).forward(req, resp);
    }
}

The current errorpage is not decorated with tiles, so I want to decorate it with normal header and footer and call that view name from the filter.

Is it possible ?

Edit: Basically we want to be able to do something similar to Controller-method i.e. return "view name";

Already tried:

  • httpResponse.sendRedirect("errorPageView"); does not work, it redirects to http://server/fooerrorPageView
  • request.getRequestDispatcher("errorPageView").forward(request, response); also doesn't, similar as above (no http redirect, but gives the same "no such page error" content)
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
coder247
  • 2,913
  • 19
  • 50
  • 70

5 Answers5

1

i think this is not possible, because this is a servlet filter, which would be applied after the spring request mapper servlet was applied. so basically, the request mapper servlet thinks it is finished, and passes the request back to the servlet container.

view names only work INSIDE of spring - outside of spring, in the servlet container, you will have to talk about urls, not view names.

a redirect to specific url would work. for this, you have to be aware of the differences between a redirect and a forward.

a redirect sends the following header to the client:

Location: http://server/new/location

along with the status code 301 (permanent redirect, to let the client know that it can cache this information) or 307 (temporary redirect, to tell the client it should ask again next time, because the redirect may change)

the forward on the request dispatcher basically mimics a new request, and you can send the request to ANY servlet in the same container. this means, you have to ALSO take the context path into consideration, meaning the answer @iimuhin gave:

    response.sendRedirect(
         request.getContextPath() + 
         getFilterConfig().getInitParameter("errorPage"));

is actually the right way to go. you can (should) add logging to see what actually happens and what paths are actually used.

also - you have to be aware of buffering. a servlet response is usually buffered, and nothing is sent to the client until either the buffer is full or the entire processing has finished.

when it is flushed, the headers are written first. this means that changing the headers AFTER the response has been flushed is not possible, because they're already sent out.

this is the reason why servlets can force flushing, but usually shouldn't.

in your case, you may want to increase the buffer size on the response:

    response.setBufferSize(int size) 

before calling chain.doFilter() to avoid premature flushing.

rmalchow
  • 2,689
  • 18
  • 31
  • Thank you so much for the detailed explanation on the matter. +1 for mentioning the difference between redirect and forward. – yuva Oct 18 '15 at 09:38
1

Why don't you use spring's error handling mechanism? here the good post about it (with examples) - https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

Other than that, not sure if there is a clean way of doing that. Other suggestions might be making a call to your application to get error page response and substitute response output with that (in that case you'll also need to use "buffered" http response to be sure that stream is not flushed yet) or make a redirect to the error url.

Maks
  • 202
  • 1
  • 9
  • Your suggestion works if the questioner wants to show error page from the controller. What he wants is to construct an error page from within the Servlet Filter which is before the request passes to the controller. So, Exception Handling can't work here. Your second suggestion is worth noting though. – yuva Oct 18 '15 at 09:35
  • 1
    thank you for your reply and evaluation, but why do you think that servlet filter is not able to catch exception thrown in spring controller or after spring controller execution (in other words on a way back AFTER controller execution)? – Maks Oct 19 '15 at 22:54
  • the whole point of my answer was: - use sring functionality if you can - if you (for whatever reason) is not able to use it, redirect or response parsing (in filter) is still an option. But that may only work if response is not committed yet. Does it make sense? – Maks Oct 19 '15 at 22:58
  • I did exactly as you described. In my custom Authentication Filter, I checked for the authentication, and in case of any exception I forwarded the request to the controller adding error attributes to the request object. While forwarding I checked for the response if it's already been committed or not. I also increased the buffer limit to avoid unintentional flushing. In controller, I get the added attribute from the request object and return the error page view from there. Can you please guide me on creating error page view from within the filter? Can I handle exception in filter? – yuva Oct 20 '15 at 13:39
1

Filter comes before Spring. Spring beans can be injected in Filter using ApplicationContextAware mechanism, but forming a Spring MVC view means you will have to get hold of entire spring MVC framework in your Filter. I think this is not possible and you will have to forward request using RequestDispatcher not to a spring view but to your own custom view.

gargkshitiz
  • 2,130
  • 17
  • 19
0

Just check your redirect url. you are able to access page with the url.

public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
        throws IOException {
    String redirectUrl = request.getContextPath() + url;
    redirectUrl = response.encodeRedirectURL(redirectUrl);

    if (logger.isDebugEnabled()) {
        logger.debug("Redirecting to '" + redirectUrl + "'");
    }

    response.sendRedirect(redirectUrl);
}
Vivek Adhikari
  • 221
  • 2
  • 7
0

There must be a way to do it with Spring MVC, but i suppose a redirect is enough.

try {
    chain.doFilter(req, resp);
} catch (Exception ex) {
    if (response.isCommitted()) {
        log(ex); // at least a part of the response is already sent to the client, you can't do much about it
    } else {
        session.setAttribute("last.exception", ex);
        response.sendRedirect(request.getContextPath() + getFilterConfig().getInitParameter("errorPage"));
    }
}

P.S. don't catch an Error!

Igor Mukhin
  • 15,014
  • 18
  • 52
  • 61