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的问题,如下所示。