Проблема в ответе из потока вывода сервлета - PullRequest
0 голосов
/ 31 августа 2011

В моем веб-приложении на основе Java я пытаюсь записать некоторые файлы в ZIP-файл и предложить пользователю загрузить / отменить / сохранить. Время, когда открывается диалоговое окно загрузки, и если я нажимаю кнопку «Отмена», после этого, если я пытаюсь получить доступ к любым ссылкам в моем приложении, диалоговое окно открывается снова. Вот мой фрагмент кода.

private void sendResponse(byte[] buf, File tempFile) throws IOException {
    long length = tempFile.length();
    HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
    String disposition = "attachment; fileName=search_download.zip";
    ServletOutputStream servletOutputStream = null;
    InputStream in = null; 
    try {
        if (buf != null) {
            in = new BufferedInputStream(new FileInputStream(tempFile));
            servletOutputStream = response.getOutputStream();
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", disposition);
            while ((in != null) && ((length = in.read(buf)) != -1)) {
                servletOutputStream.write(buf, 0, (int) length);
            }
        }
    } finally {
        if (servletOutputStream != null) {
            servletOutputStream.close();
        }
        if (in != null) {
            in.close();
        }
        if (tempFile != null) {
            tempFile.delete();
        }
    }
    context.responseComplete();
}

Также, когда я нажимаю на кнопку Сохранить / Открыть, она работает как положено. Я надеюсь, что проблема в очистке объекта ответа. Пожалуйста, помогите мне в предоставлении некоторых решений.

EDIT downloadВыбранный метод

      public void downloadSelected() throws IOException {

    List<NodeRef> list = init();
    StringBuffer errors = new StringBuffer("");
    ZipOutputStream out = null;

    File tempFile = null;
    byte[] buf = null;
    try {
        if (list != null && list.size() > 0) {
            tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ZIP);
            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile)));
            buf = writeIntoZip(list,out);
            sendResponse(buf,tempFile);
        } else {
            errors.append("No Items Selected for Download");
            this.errorMessage = errors.toString();
        }
    } 
    catch(IOException e) {
        System.out.println("Cancelled");
    }       
}

Метод записи в Zip:

private byte[] writeIntoZip(List<NodeRef> list,ZipOutputStream out) throws IOException {
    String downloadUrl = "";
    InputStream bis = null;
    Node node = null;
    String nodeName = "";
    byte[] buf = null;
    Map<String,Integer> contents = new HashMap<String, Integer>();
    ContentReader reader = null;
    for (NodeRef nodeRef : list) {
        try {
            node = new Node(nodeRef);
            nodeName = node.getName();
            reader = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT);
            bis = new BufferedInputStream(reader.getContentInputStream());
            if (bis != null) {
                contents = setFiles(contents,nodeName);
                nodeName = getUniqueFileName(contents, nodeName);
                buf = new byte[4 * 1024];
                buf = writeOutputStream(bis).toByteArray();
                out.putNextEntry(new ZipEntry(nodeName));
                out.write(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if(out != null) {
                out.close();
            }
        }
    }
    if(out != null) {
        out.close();
    }
    return buf;
}

Спасибо, Jeya

1 Ответ

1 голос
/ 31 августа 2011

По общему признанию, я не уверен в коренной причине этой проблемы. Это поведение не объяснимо на основании кода, опубликованного до сих пор. SSCCE определенно поможет больше. Но я заметил несколько возможных причин этой проблемы. Возможно, исправление одного или всех из них решит конкретную проблему.

  1. Вы назначили JSF FacesContext как свойство компонента. Это плохо и определенно, если это бин с более широкой областью, чем область запроса. всегда должно быть получено в локальной области видимости метода FacesContext#getCurrentInstance(). Он возвращает именно локальную переменную потока и никогда не должен передаваться другим запросам. Возможно, вы поместили bean-компонент в область действия сеанса, и висящий объект response предыдущего запроса с уже установленными заголовками будет использован повторно.

  2. Вы не перехватываете методы IOException на close(). Если клиент отменяет загрузку, servletOutputStream.close() выдает IOException, указывая, что клиент прервал ответ. В вашем случае in больше не будет закрыт, а tempFile больше не будет удален и ответ JSF больше не будет завершен. Вам также следует перехватить close() и зарегистрировать / игнорировать исключение, чтобы вы могли убедиться, что finally завершит свою работу. Возможно, наличие tempFile имеет последствия для ваших будущих действий POST.

  3. Вы используете <h:commandLink> вместо <h:outputLink> или <h:link> или обычный <a> для постраничной навигации. Это использует POST вместо GET, что плохо для пользовательского опыта и SEO. Вы должны использовать ссылки GET вместо ссылок POST. См. Также Когда мне следует использовать h: outputLink вместо h: commandLink?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...