我目前在Android设备的网页上遇到了一个奇怪的问题。
我想要做的是允许用户将pdf文件下载到他的移动设备。因此,我提供了一个下载按钮,如在here所描述的设置中那样。
只要我使用桌面浏览器* Mozilla Firefox 10,一切正常。**但是一旦我更改为我的移动设备(SGS II,Android vers.2.3.5)下载结果取决于我使用的浏览器应用程序。
Mozilla和Opera mobile:
两者似乎都能正确下载文件。
任何其他浏览器应用(内置Dolphin HD,......):
下载名为<filename>.pdf
或<filename>.htm
的文件,这两个文件都代表 .htm - 文件,显示网页的html源代码。
我尝试过的事情:
使用 PrimeFaces 库中的StreamedContent
方法
public StreamedContent getFile() {
// prepare file for download
// reference webDAV directory and get file as stream
this.file = new Helper().getWebDavFile(customerId, fileName);
return file;
}
按照here所述手动将文件流式传输到页面。 (感谢BalusC)
public void download() throws IOException {
byte[] is = new Helper().getWebDavFileManually(customerId, fileName);
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType("application/pdf");
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName.toUpperCase() + "\"");
OutputStream output = ec.getResponseOutputStream();
output.write(is);
fc.responseComplete();
}
将<a href="">
设置为文件的本地副本
(我目前正在使用<p:commandButton>
,因此我使用执行重定向的方法而不是返回String,但它可以两种方式工作)
public void goToLink() throws IOException {
// get WebDAV file and save temporarily
byte[] b = new Helper().getWebDavFileManually(customerId, fileName);
String path = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/") + fileName;
File f = new File(path);
try {
FileOutputStream fos = new FileOutputStream(f);
fos.write(b);
link = "http://someurl/somepage/" + fileName;
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
// use link
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(link);
}
即使在我的Android设备上,这个最终方法也能正常工作但我不希望走这条路线,如果我可以避免它,因为文件从WebDAV流式传输我必须将每个文件保存到服务器。这会产生更多的IO负载,并迫使我手动清理。
方法Helper().getWebDavFile
和Helper().getWebDavFileManually
要么返回PrimeFaces使用的 DefaultStreamedConten ,要么为我自己的方法返回 byte [] 。
到目前为止我所知道的事情:
不幸的是不是我的问题的解决方案:) 经过几个小时的谷歌使用后,我发现有可能出现双-http-post-request 。这将导致机器人内部下载管理器(在文件下载中断时使用)发送一个额外的后请求,其中状态丢失。
如this blog中所述(请参阅 GET,POST,REST [更新20120208] 部分),有人面临同样的问题。我已尝试过本博客中提到的所有方法,但没有成功
在此forum,有人用 WireShark 分析了相同的行为并得出了几乎相同的结论。
我没有找到任何更多的资源,所以我一直坚持这一点。
我还发布了PrimeFaces forum,以确保没有关于<p:fileDownload>
组件的任何已知问题。
我想知道的事情:
我错过了什么吗? 有没有可能从Android设备上的JSF(http-post操作)网页下载流文件?
任何帮助/建议/信息将不胜感激! 提前致谢!
答案 0 :(得分:1)
好的,在我遇到其他一些问题之后,我终于抽出时间来回避这个问题了。
在使用谷歌后花了几个小时的时间我没有得到任何新的线索,如我在问题中已经提到的那样。
事实上,某些Android浏览器无法处理POST请求并返回相应的文件。
因此,我选择提供 servlet-approach (如评论中所述并描述here),尝试构建我自己的http-GET请求。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
// Initialize servlet response
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(mime);
response.setHeader("Content-Length", String.valueOf(data.length));
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// write to response
BufferedOutputStream output = null;
try {
output = new BufferedOutputStream(response.getOutputStream());
output.write(data);
}
finally {
output.close();
}
并且无论使用哪种浏览器,任何 Android设备都可以下载
再次感谢@BalusC指出我正确的方向。
如果我找到时间,我也会尝试使用JSF-GET方法,但起初我很满意。
如果有人遇到同样的问题或能够提出另一种解决方案,我将不胜感激!
这对我有帮助,我会玩得开心:D!
答案 1 :(得分:0)
有同样的问题。我使用了primefaces.org中的示例代码来下载带有移动设备的pdf。它“在我的机器上”运行良好,但不适用于iPad Safari或Android浏览器。 问题是展示中提供的Example-Controller中的内容类型:
file = new DefaultStreamedContent(stream, "image/jpg", "some.pdf");
仅适用于图像。好吧,大脑模式:
file = new DefaultStreamedContent(stream, "application/pdf", "some.pdf");
现在一切正常。