Загрузка JSF в потоковом режиме на устройство Android возвращает файл .htm - PullRequest
3 голосов
/ 12 марта 2012

В настоящее время я сталкиваюсь со странной проблемой на своей веб-странице на устройствах Android.

Я хочу разрешить пользователю загружать pdf-файл на свое мобильное устройство.Поэтому я предоставляю кнопку загрузки, как в настройке, описанной здесь .

Все работает нормально, пока я использую свой настольный браузер * Mozilla Firefox 10. **, но как только я перехожу намое мобильное устройство (SGS II, версия Android 2.3.5) результат загрузки зависит от используемого мной браузера-приложения.

Mozilla и Opera mobile:
Кажется, что оба файла могут правильно загрузить файл.

Любое другое браузерное приложение (встроенное, Dolphin HD, ...):
Загружает файл с именем <filename>.pdf или <filename>.htm, который представляет файл .htm , показывающий html-источник страницы.

Что я пробовал:

  • Использовал метод StreamedContent из библиотеки PrimeFaces

    public StreamedContent getFile() {
        // prepare file for download
        // reference webDAV directory and get file as stream
        this.file = new Helper().getWebDavFile(customerId, fileName);
    
        return file;
    }
    
  • Потоковый файлвручную на страницу, как описано здесь .(Thx в 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>, поэтому яиспользовать метод, выполняющий перенаправление вместо возврата строки, но он работает в обоих направлениях)

    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, и я должен был бы сохранить каждый файл на сервере.Это увеличит нагрузку ввода-вывода и вынудит меня выполнить очистку вручную.

Методы Helper().getWebDavFile и Helper().getWebDavFileManually либо возвратят DefaultStreamedConten , используемый PrimeFacesили байт [] для моего собственного подхода.

Что я знаю до сих пор:

К сожалению, не решение моей проблемы :).
После многих часов использования Google я обнаружил, что существует возможность double-http-post-request .Это приведет к тому, что внутренний менеджер загрузок Android (используемый в случае загрузки поврежденного файла) отправит дополнительный пост-запрос, в котором состояние будет потеряно.

Как описано в этом блоге (см. Раздел GET, POST, REST [ОБНОВЛЕНИЕ 20120208] ) есть кто-то, кто сталкивается с той же проблемой.Я перепробовал все подходы, упомянутые в этом блоге, но безуспешно.
На этом форуме кто-то проанализировал такое же поведение с WireShark и пришел почти к тому же выводу.
Я не нашел больше ресурсов, поэтому я застрял в этом.

Я также разместил сообщение на форуме PrimeFaces , просто чтобы убедиться, что нет ни одного известногопроблемы, связанные с <p:fileDownload> компонентом.

Что я хотел бы знать:

Я что-то упустил?
Есть ли возможность загрузить потоковый файлс веб-страницы JSF (работающей по протоколу http) на устройстве Android?

Буду признателен за любую помощь / предложение / информацию!
Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 19 марта 2012

ОК, после того, как я столкнулся с некоторыми другими проблемами, у меня наконец-то появилось время проверить эту проблему.

Через несколько часов, потраченных на использование Google, я не получил никаких новых подсказок, как уже упоминалосьв моем вопросе.

Это все еще тот факт, что некоторые браузеры Android не в состоянии обработать POST-запрос и вернуть соответствующий файл.

Из-за этого я решил дать сервлет-подход (как упомянуто в комментариях и описано здесь ) попытаться создать свой собственный 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!

0 голосов
/ 28 февраля 2013

была такая же проблема. Я использовал пример кода с primefaces.org для загрузки PDF с мобильных устройств. Он работал нормально «на моей машине», но не на iPad Safari или Android-браузерах. Проблема заключалась в типе содержимого в Example-Controller, представленном в витрине:

file = new DefaultStreamedContent(stream, "image/jpg", "some.pdf");

, который работает только для изображений. Ну, мозг в режиме:

file = new DefaultStreamedContent(stream, "application/pdf", "some.pdf"); 

и теперь все работает нормально.

...