Вперед в JSP после вызова ServletOutputStream

Насколько я могу судить, это подпадает под «вы не можете этого сделать». Я собираюсь переосмыслить свое решение и обойти его, но я подумал, что спросить здесь стоит хотя бы попробовать.

Мой сервлет JSP/Spring/Struts создает отчеты, записывает их в PDF и ставит в очередь для загрузки, а затем ждет, пока пользователь запросит дополнительные отчеты. Детали не слишком важны. Я передаю PDF на сервер с помощью следующего вызова функции:

public static void streamFileToBrowser(File docFile, HttpServletResponse response) throws Exception {
try {
    // return file to user
    // set contextType
    response.setContentType("application/pdf");
    // setting some response headers
    response.setHeader("Expires", "0");
    response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
    response.setHeader("Pragma", "public");
    response.setHeader("Content-Disposition","attachment; filename=" + docFile.getName() );

    ServletOutputStream outs = response.getOutputStream();
    byte[] outputFileBytes = util_getBytesFromFile(docFile.getAbsolutePath());
    response.setContentLength(outputFileBytes.length);
    outs.write(outputFileBytes);    // byte[]
    outs.flush();
    outs.close();
    } catch (Exception e) {
        throw e;
    }
}

Это довольно прямолинейно. Я использую объект ответа ServletOutputStream для отправки своих битов. Это работает хорошо.

Однако иногда я ловлю некоторые ошибки, возникающие при формировании отчетов. Это информативные сообщения типа "Нет заказов от аккаунта бла-бла-бла". У меня есть раздел в моем JSP, который будет их перехватывать и отображать.

Итак, вот в чем загвоздка: когда у меня нет отчета для отправки, я не вызываю вышеуказанную функцию. Но я всегда вызываю что-то вроде:

return mapping.findForward("pullReports");

как последняя строка в моем методе ActionForward, и появляются ошибки. Однако, если у меня есть биты для отправки через функцию streamFileToBrowser(), мой возможный вызов map.findForward ничего не делает.

Немного копания говорит мне, что Struts может обрабатывать только один ответ на объект HttpServletResponse за раз. Я использовал его с моим вызовом streamFileToBrowser(), поэтому возможный вызов map.findForward(...) ничего не делает для моего клиента.

Кто-нибудь еще сталкивался с этим и нашел решение?


person Berin    schedule 25.02.2010    source источник


Ответы (2)


Что я сделал, так это удостоверился, что, насколько это возможно, все ошибки будут обнаружены до начала генерации PDF. Таким образом, вы можете отправить обратно старый простой набор ошибок формы или что-то еще. Как только вы начнете отправлять обратно такое вложение, браузер не будет обращать внимания ни на что другое. Если вы абсолютно не можете найти ошибки до того, как приступите к созданию PDF-файла, я думаю, единственное, что вы можете сделать, это встроить сообщения об ошибках в сам PDF-файл (я знаю, что это неприятно).

person Pointy    schedule 25.02.2010
comment
Примерно в этом направлении я и двигался. Затем сообщения об ошибках становятся чем-то вроде «не делайте этого» и требуют от пользователя очистить свой запрос перед получением отчета. Не совсем то, к чему я стремился, но соответствует спецификации, в которой я предупреждаю пользователя о том, почему данные отсутствуют в отчете, который они пытались создать. - person Berin; 25.02.2010

Просто перестройте код так, чтобы элемент util переместился на передний план в его собственном блоке try-catch и оставил ответ нетронутым до тех пор, пока блок try не будет передан.

byte[] outputFileBytes;

try {
    outputFileBytes = util_getBytesFromFile(docFile.getAbsolutePath());
} catch (Exception e) {
    throw e; // Do the forward call when this is caught in the calling method. If necessary, wrap in a more specific excaption so that you can distinguish what action to take.
}

response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setHeader("Content-Disposition","attachment; filename=" + docFile.getName() );
response.setContentLength(outputFileBytes.length);
ServletOutputStream outs = response.getOutputStream();
outs.write(outputFileBytes);    // byte[]
outs.close();

Имейте в виду, что это захват памяти. Если можете, лучше пусть util вернет InputStream (нет, не ByteArrayInputStream).

person BalusC    schedule 25.02.2010