Question

All of my controllers extend the following abstract class:

public abstract class AbstractController {

    public HttpServletRequest request;
    public HttpServletResponse response;
    public ModelMap model;

}

Moreover, I implemented the following interceptor:

public class HttpRequestInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
        if (handler instanceof AbstractController) {
            AbstractController controller = (AbstractController) handler;
            controller.request = request;
            controller.response = response;
            controller.model = new ModelMap();
        }
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        if (handler instanceof AbstractController && modelAndView != null) {
            AbstractController controller = (AbstractController) handler;
            modelAndView.addAllObjects(controller.model);
        }
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }

}

This is a solution I found to improve the factorization of my code, since you won't need to pass the request, the response and the model as method parameters within your controllers. The solution works fine, until I found this issue:

public class HomeController extends AbstractController {

    @RequestMapping
    public void download1() {
        // use the parent attribute response
        File file = new File(MY_FILE_PATH);
        InputStream in = new BufferedInputStream(new FileInputStream(file));
        ServletOutputStream out = response.getOutputStream();
        IOUtils.copy(in, out);
        response.flushBuffer();
    }

    @RequestMapping
    public void download2(HttpServletResponse response) {
        // use the response passed as parameter
        File file = new File(MY_FILE_PATH);
        InputStream in = new BufferedInputStream(new FileInputStream(file));
        ServletOutputStream out = response.getOutputStream();
        IOUtils.copy(in, out);
        response.flushBuffer();
    }

}

Both of the two methods above make the browser downloading a file, but the download1 one generated an empty file while the download2 generates the original file as it should. Any idea why?

Thanks to the debugger, I noticed that in the postHandle method of the interceptor, the download2 method generates a modelAndView which equals null, while the download1 one generated an instanciated one. This should mean something for the issue, but I can't find what.

How get a response instanciated when passed as a parameter of a controller's method?

Was it helpful?

Solution

Don't do this :

public abstract class AbstractController {

    public HttpServletRequest request;
    public HttpServletResponse response;
    public ModelMap model;

}

Instance variables in controllers (which have default scope of singleton btw) is a bad idea.

OTHER TIPS

Just make something like this (to a txt file):

@RequestMapping(value="/download", method=RequestMethod.GET, produces=MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public String download(HttpServletResponse response) throws IOException {
    response.setContentType("application/force-download");
    FileReader fr = new FileReader("/folder/file.extension");
    return IOUtils.toString(fr); // IOUtils come from Apache Commons IO
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top