【发布时间】:2014-05-08 10:29:15
【问题描述】:
我想创建一个链接来启动与页面本身异步的文件下载,即我希望在文件下载期间不锁定页面。我应该让它在检票口外启动吗?或者检票口里面有什么东西可以让我设置一个绕过页面锁定的资源流?
我尝试过的事情:
DownloadLink- 锁定页面,如其文档中所述。这是我的出发点。ResourceLink- 没有在文档中明确说明锁定,所以我尝试了这个,但它也锁定了页面。-
此时我已经稍微调查了两个链接的代码,并注意到它们都通过
ResourceStreamRequestHandler安排下载。期望他的行为可能只是特定于处理程序的我试图安排我编写的自定义处理程序:private void sendFile(final File file) throws IOException { IRequestHandler fileDownloadHandler = new IRequestHandler() { @Override public void respond(IRequestCycle requestCycle) { WebResponse response = (WebResponse) requestCycle.getResponse(); OutputStream outStream = response.getOutputStream(); response.setContentType("audio/x-wav"); response.setContentLength((int)file.length()); String fileName = "Somethingsomething.wav"; // sets HTTP header response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); byte[] byteBuffer = new byte[1024]; DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(file)); int length = 0; // reads the file's bytes and writes them to the response stream while ((in != null) && ((length = in.read(byteBuffer)) != -1)) { outStream.write(byteBuffer,0,length); } in.close(); outStream.close(); } catch (IOException e) { throw new PortalError("IOException trying to write the response", e); } } @Override public void detach(IRequestCycle requestCycle) { } }; getRequestCycle().scheduleRequestHandlerAfterCurrent(fileDownloadHandler); } -
这也不太奏效,所以我进行了进一步调查。我注意到,与我预期的不同,“预定”请求处理程序不会像我预期的那样在单独的请求上执行,而是在同一个请求上执行。我想它一定是页面被第一个处理程序锁定,然后在第二个处理程序也在执行时保持锁定。所以我试图强制下载处理程序进入一个单独的请求(通过 ajax 行为):
public void startDownload(AjaxRequestTarget target) throws DownloadTargetNotFoundException{ target.appendJavaScript("setTimeout(\"window.location.href='" + getCallbackUrl() + "'\", 100);"); } @Override public void onRequest() { sendFile(getFile()); logger.debug("Download initiated"); }我找到了这个here 并希望它可能是我一直在寻找的东西。然而,不出所料,页面仍然被锁定(我想是因为仍然必须从页面中检索行为,为此必须获取页面锁定)。
我不知道接下来应该去哪里寻找,尤其是在这段时间试图让一个简单的下载链接正常工作之后。我正在考虑在检票口上方创建另一个网络过滤器,可以从检票口内部发出信号以在检票口过滤器完成其工作后创建下载(因此页面锁定已经释放),但这似乎有点过分像这样的任务。
欢迎提出任何建议。
【问题讨论】:
-
如果你问我,那看起来设计过度了。 1)创建可以将文件转储到响应的servlet(google:java FileServlet)。 2) 创建指向该 servlet 的链接/按钮。 3)用户点击链接/按钮,浏览器完成其余的工作。经典解决方案,完美运行。
-
由于几个原因,该解决方案不够灵活。首先,我必须在按钮/链接单击时生成文件(页面上的文件太多,无法全部预先生成),这需要在新的 servlet 中进行额外的依赖和处理。这可以解决,但我也不喜欢在 wicket 之外拥有任何组件的想法,因为那样我将失去使用 wicket 的好处(即我无法访问页面上的其他组件)。