3

Ok, I have been trying to implement a system in which after check the parameters on the request, like the Path, i will actually modify the response to answer with different data. Idea is to create backend demo functionality, in this way client can Demo (NOT TEST) the application without actually making DB requests.

So, my first try was using servlet filters, a very good answer for this can be found here, and also some good document called The Essentials of Filters. But I could not make it work, i think because I'm using spring with @Controller and @ResponseBody, even I follow exactly same sample I would get a null as wrapperResponse.

Then I tried the Interceptors, here there is good example, and a good actually answer here. But the problem with this is that normally people will use the postHandle to modify the body, and I really do not want the handle to even trigger, because this means that the DB calls will be also triggered. And if I use the preHandler as here it will just make a new servlet, and I don't want that.

Finally I try @ControllerAdvice which basically allows you to re-write the body before is sent, but again, the handler gets processed and all DB calls with it.

MY goal, is that I do not have to put repeated code in each handler, I could make a preHandler insert some extra header and check that header in the @ControllerAdvice, but this means that i have to make some IF/ELSE in the handler so it doesn't get processed and I have to repeat that on the 100s of @Controllers that i have in the system, i want to be DRY.

I'm pretty sure the solution is on the filter in the way of this answer

public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {

System.out.println("BEFORE filter");
PrintWriter out = response.getWriter();
CharResponseWrapper responseWrapper = new CharResponseWrapper(
        (HttpServletResponse) response);

chain.doFilter(request, responseWrapper);

String servletResponse = new String(responseWrapper.toString());

out.write(servletResponse + " filtered"); // Here you can change the response


System.out.println("AFTER filter, original response: "
        + servletResponse);

}

But I can't make it work with spring and @ResponseBody calls. And true be told, this doesn't answer my question.

Community
  • 1
  • 1
OscarSanhueza
  • 317
  • 2
  • 13

1 Answers1

1

This is the way I manage to do this.

First I created an interceptor, which actually filter the request to pass just the want we want to demo. In the pre handler instead of trying to create a response there using the Response outstream I just used the RequestDispatcher to forward the request to a new controller, which I called Demo controller.

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception {
    // TODO Auto-generated method stub

    Pattern pattern = Pattern.compile("someregex");
    Matcher matcher = pattern.matcher(request.getPathInfo());

    if (matcher.find())
    {
        if (matcher.group(0).equals("SOMETHING"))
        {
            HandlerMethod handlerMethod = ((HandlerMethod)handler);
            request.setAttribute("methodName", handlerMethod.getBeanType().getSimpleName());
            request.getRequestDispatcher("/demo").forward(request, response);
            return false;
        }
        return true;
    }
    else
    {
        return true;
    }
}

In the Demo controller then you can create a proper response you want to demo. The good thing here is that in the new demo forwarded request will have an attribute for the original request javax.servlet.forward.request_uri, and that you can insert data, as the controllerName on the request before forward. All this data can be extracted in the Demo controller in order to generate the required data.

OscarSanhueza
  • 317
  • 2
  • 13