Возврат PDF-файла из Java-бина в JSP - PullRequest
1 голос
/ 20 октября 2008

РЕДАКТИРОВАТЬ: См. мой рабочий код в ответах ниже.


Вкратце: У меня есть файл JSP, который вызывает метод в Java Bean. Этот метод создает файл PDF и теоретически возвращает его в JSP, чтобы пользователь мог его скачать. Однако при загрузке PDF Adobe Reader выдает ошибку: Файл не начинается с «% PDF -» .

Подробно: Пока JSP успешно вызывает метод, создается PDF, а затем появляется JSP, чтобы предоставить пользователю готовый файл PDF. Однако, как только Adobe Reader пытается открыть файл PDF, выдает ошибку: Файл не начинается с «% PDF -» . На всякий случай, у меня есть метод создания PDF на моем рабочем столе, чтобы я мог проверить его; когда я открываю его обычно в Windows, это выглядит нормально. Так почему же выход из JSP отличается?

Для создания PDF я использую Apache FOP . Я следую одному из их самых простых примеров, за исключением передачи полученного PDF-файла в JSP вместо простого сохранения его на локальном компьютере. Я следовал их базовому шаблону использования и этому примеру кода .

Вот мой файл JSP:

<%@ taglib uri="utilTLD" prefix="util" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ page language="java" session="false" %>
<%@ page contentType="application/pdf" %>

<%-- Construct and initialise the PrintReportsBean --%>
<jsp:useBean id="printReportsBean" scope="request" class="some.package.printreports.PrintReportsBean" />
<jsp:setProperty name="printReportsBean" property="*"/>

<c:set scope="page" var="xml" value="${printReportsBean.download}"/>

Вот мой метод Java Bean:

//earlier in the class...
private static FopFactory fopFactory = FopFactory.newInstance();

public File getDownload() throws UtilException {

    OutputStream out = null;
    File pdf = new File("C:\\documents and settings\\me\\Desktop\\HelloWorld.pdf");
    File fo  = new File("C:\\somedirectory", "HelloWorld.fo");

    try {

        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        out = new FileOutputStream(pdf);
        out = new BufferedOutputStream(out);

        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(); //identity transformer

        Source src = new StreamSource(fo);

        Result res = new SAXResult(fop.getDefaultHandler());

        transformer.transform(src, res);

        return pdf;

    } catch (Exception e) {

         throw new UtilException("Could not get download. Msg = "+e.getMessage());

    } finally {

         try {
             out.close();
         } catch (IOException io) {
             throw new UtilException("Could not close OutputStream. Msg = "+io.getMessage());
         }
    }
}

Я понимаю, что это очень специфическая проблема, но любая помощь будет высоко ценится!

Ответы [ 4 ]

4 голосов
/ 21 октября 2008

Хорошо, у меня это работает. Вот как я это сделал:

JSP:

<%@ taglib uri="utilTLD" prefix="util" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ page language="java" session="false" %>
<%@ page contentType="application/pdf" %>

<%-- Construct and initialise the PrintReportsBean --%>
<jsp:useBean id="printReportsBean" scope="request" class="some.package.PrintReportsBean" />
<jsp:setProperty name="printReportsBean" property="*"/>

<%
    // get report format as input parameter     
    ServletOutputStream servletOutputStream = response.getOutputStream();

    // reset buffer to remove any initial spaces
    response.resetBuffer(); 

    response.setHeader("Content-disposition", "attachment; filename=HelloWorld.pdf");

    // check that user is authorised to download product
    printReportsBean.getDownload(servletOutputStream);
%>

Метод Java Bean:

//earlier in the class...
private static FopFactory fopFactory = FopFactory.newInstance();

public void getDownload(ServletOutputStream servletOutputStream) throws UtilException {

    OutputStream outputStream = null;

    File fo  = new File("C:\\some\\path", "HelloWorld.fo");

    try {

        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        outputStream = new BufferedOutputStream(servletOutputStream);

        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, outputStream);

        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(); //identity transformer

        Source src = new StreamSource(fo);

        Result res = new SAXResult(fop.getDefaultHandler());

        transformer.transform(src, res);

    } catch (Exception e) {

        throw new UtilException("Could not get download. Msg = "+e.getMessage());

    } finally {

        try {
            outputStream.close();
        } catch (IOException io) {
            throw new UtilException("Could not close OutputStream. Msg = "+io.getMessage());
        }
     }
 }

Спасибо всем за вклад!

4 голосов
/ 20 октября 2008

Способ, которым я реализовал этот тип функции в прошлом, - заставить сервлет записать содержимое файла PDF в ответ в виде потока. У меня больше нет исходного кода (и прошло не менее года с тех пор, как я работал с сервлетом / jsp), но вот что вы можете попробовать:

В сервлете получите дескриптор потока вывода ответа. Измените MIME-тип ответа на «application / pdf», и пусть сервлет выполнит обработку файла, которая у вас есть в вашем примере. Только вместо того, чтобы возвращать объект File, пусть сервлет записывает файл в выходной поток. Посмотрите примеры файлового ввода-вывода и просто замените любые строки outfile.write (...) на responseStream.write (...), и вы должны быть готовы к работе. После того, как вы очистите и закроете выходной поток и выполните возврат, если я правильно помню, браузер сможет получить pdf из ответа.

3 голосов
/ 20 октября 2008

Просто предположение, но вы проверили тип MIME, который возвращает ваша страница JSP?

edit: если бы я действительно прочитал код, который вы разместили, я бы увидел, что вы его установили, так что не берите в голову:)

edit2: Разве строки перевода тегов JSP в вашем коде JSP не попадут в поток вывода? Может ли это скинуть ответ, возвращаемый сервером? Я ничего не знаю о формате PDF, но зависит ли это от того, что определенные символы маркера находятся в определенных местах в файле? (Возвращенное сообщение об ошибке звучит так же, как и оно).

0 голосов
/ 20 октября 2008

Я согласен с matt b , возможно, это пробелы между тегами JSP. Попробуйте поставить директиву

<%@ page trimDirectiveWhitespaces="true" %>
...