Java 使用SpringMVC和自行实现的拦截器强制下载文件会产生一个奇怪的问题

Java 使用SpringMVC和自行实现的拦截器强制下载文件会产生一个奇怪的问题,java,spring-mvc,httpresponse,interceptor,force-download,Java,Spring Mvc,Httpresponse,Interceptor,Force Download,我的所有控制器都扩展了以下抽象类: public abstract class AbstractController { public HttpServletRequest request; public HttpServletResponse response; public ModelMap model; } 此外,我实现了以下拦截器: public class HttpRequestInterceptor implements HandlerIntercept

我的所有控制器都扩展了以下抽象类:

public abstract class AbstractController {

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

}
此外,我实现了以下拦截器:

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 {
    }

}
这是我发现的一个改进代码分解的解决方案,因为您不需要在控制器中将请求、响应和模型作为方法参数传递。解决方案工作正常,直到我发现这个问题:

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();
    }

}
上述两种方法都使浏览器下载一个文件,但download1生成一个空文件,download2生成它应该生成的原始文件。知道为什么吗

多亏了调试器,我注意到在拦截器的postHandle方法中,download2方法生成了一个等于null的modelAndView,而download1方法生成了一个实例化的modelAndView。这应该对这个问题有意义,但我找不到什么

当作为控制器方法的参数传递时,如何获取实例响应?

不要这样做:

public abstract class AbstractController {

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

}

默认范围为singleton btw的控制器中的实例变量是个坏主意。

只需将类似的内容写入txt文件:

@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
}

您是否在原型范围内定义控制器?否则,您不应该在它们的字段中存储任何会话状态,因为所有请求都共享同一个控制器实例。我从来没有听说过原型范围。。。您是什么意思?您正在请求之间共享实例变量,这些变量不是由spring管理的。控制器由多个请求并发访问,因此应该是线程安全的。拥有实例变量会导致这种情况。我在测试中遇到问题,因为Jackson ObjectMapper正在尝试序列化该文件。我解决了将products属性添加到@RequestMapping的问题,如下所示。