在Android设备上的JSF流下载返回.htm文件

时间:2012-03-12 12:53:02

标签: java-ee jsf-2 download http-post android

我目前在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().getWebDavFileHelper().getWebDavFileManually要么返回PrimeFaces使用的 DefaultStreamedConten ,要么为我自己的方法返回 byte []

到目前为止我所知道的事情:

不幸的是不是我的问题的解决方案:) 经过几个小时的谷歌使用后,我发现有可能出现双-http-post-request 。这将导致机器人内部下载管理器(在文件下载中断时使用)发送一个额外的后请求,其中状态丢失。

this blog中所述(请参阅 GET,POST,REST [更新20120208] 部分),有人面临同样的问题。我已尝试过本博客中提到的所有方法,但没有成功 在此forum,有人用 WireShark 分析了相同的行为并得出了几乎相同的结论。
我没有找到任何更多的资源,所以我一直坚持这一点。

我还发布了PrimeFaces forum,以确保没有关于<p:fileDownload>组件的任何已知问题。

我想知道的事情:

我错过了什么吗? 有没有可能从Android设备上的JSF(http-post操作)网页下载流文件?

任何帮助/建议/信息将不胜感激! 提前致谢!

2 个答案:

答案 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"); 

现在一切正常。