Чтение BLOB (PDF Content) из базы данных, редактирование и вывод PDF-файла без создания физического файла. - PullRequest
5 голосов
/ 28 марта 2011

Я использую базу данных Oracle и храню содержимое PDF в поле BLOB.

Я хочу прочитать содержимое BLOB, а затем отредактировать и вывести отредактированное содержимое.

Требуется редактированиесделать:

  • добавить заголовок над содержимым BLOB
  • добавить водяной знак на каждой странице
  • добавить нижний колонтитул на каждой странице

Затем мне нужно вывести файл без создания какого-либо физического файла, который находится в потоке ответов.

Я пытался добиться этого с помощью itext, но с ним ничего не получалось.Я застрял и не уверен, с чего начать.

Также иногда мне может понадобиться объединить содержимое BLOB-объектов в одно, но это то, что должно произойти раз в миллион ... так что это не проблема сейчас...

Как мне выполнить мои основные требования, описанные выше, в трех шагах, используемых в Java?Это возможно с Itext ??Или есть какая-нибудь другая библиотека, которая может помочь?

База данных: Oracle 10g Release 2

ОС: Linux Fedora / Redhat

Внешний интерфейс: Java / Servlet / JSP

РЕДАКТИРОВАТЬ

Вот что я пытался сделать

oracle.sql.BLOB blob = (BLOB) rs.getBlob("MYPDF");
byte[] bytes = blob.getBytes(1, (int) blob.length());
InputStream is = blob.getBinaryStream();
Document document=new Document();
ServletOutputStream servletOutputStream = response.getOutputStream();
PdfWriter writer=PdfWriter.getInstance(document, servletOutputStream);
document.open();
document.add(new Paragraph("Some title"));
document.add(new Paragraph("Some title"));
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
servletOutputStream.write(bytes, 0, bytes.length);
servletOutputStream.flush();
servletOutputStream.close();
document.close();

Программа выводит содержимое PDF в поле BLOB в базе данных и без заголовка.

и когда я немного изменяю код (изменяю порядок последних нескольких строк) на:

document.close();
servletOutputStream.flush();
servletOutputStream.close();

, я получаю документ с заголовком и без PDFсодержимое поля BLOB.Первое, что закрывается (servletoutputstream / document), выбрасывается в качестве вывода.

И когда я закрывал документ перед помещением содержимого BLOB-объекта в outputtream:

document.close();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
servletOutputStream.write(bytes, 0, bytes.length);
servletOutputStream.flush();
servletOutputStream.close();

Я получилбраузер отображает что-то вроде этого:

%PDF-1.4 %���� 2 0 obj <>stream x�+�r �26S�00SI�2P�5��1���BҸ4��sSJ2KrR5C��*P�B�5�+��k)&� endstream endobj 4 0 obj <<<>>>/MediaBox[0 0 595 842]>> endobj 1 0 obj <> endobj 3 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <> endobj xref 0 7 0000000000 65535 f 0000000304 00000 n 0000000015 00000 n 0000000392 00000 n 0000000147 00000 n 0000000443 00000 n 0000000488 00000 n trailer <]/Info 6 0 R/Size 7>> startxref 620 %%EOF 

Мне нужно, чтобы файл выводился с содержимым pdf и заголовком.

Надеюсь, это редактирование немного поможет ...

UPDATE (Файл, выброшенный в ответ с заголовком и содержимым большого двоичного объекта):

Document document = new Document(PageSize.A4, 108, 72, 30, 72);
PdfWriter writer = PdfWriter.getInstance(document, outputstream);

document.open();

///-----Added Some Title----///

rs = stmt.executeQuery(queryToGetBLOBCONTENT);

if (rs.next()) {


response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=watermark.pdf");
oracle.sql.BLOB blob = (BLOB) rs.getBlob("MYPDF");
byte[] bytes = blob.getBytes(1, (int) blob.length());
InputStream is = blob.getBinaryStream();
PdfReader pdfReader = new PdfReader(is, bytes);
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
PdfImportedPage page;
int currentPageNumber = 0;
int pageOfCurrentReaderPDF = 0;
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
    if (pageOfCurrentReaderPDF > 0) {
        document.newPage();
    }
    pageOfCurrentReaderPDF++;
    currentPageNumber++;
    page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);
    cb.addTemplate(page, 0, 0);
}
pageOfCurrentReaderPDF = 0;
outputstream.flush();
document.close();
outputstream.close();

}

В ответ на это я получаю файл с BLOB из базы данныхс заголовком вверху, и это делается без создания каких-либо физических файлов.

Теперь, чтобы сгенерировать водяной знак, и мне нужно передать документ в PDfreader, как я могу это сделать до закрытия документа (т.е. выполненияdocument.close(), в результате чего файл будет закрыт без водяного знака при закрытии потока)

Что я делаю не так в этом коде?Как я могу получить тот же файл с водяным знаком, и это тоже без создания файла в фоновом режиме.

Ответы [ 2 ]

2 голосов
/ 29 марта 2011

Вместо записи непосредственно в servletOutputStream, вы можете попробовать этот подход:

  1. Создать экземпляр ByteArrayOutputStream
  2. Создать экземпляр «объединенного» PDF-документа. То есть Форма PDF Blob + PDF с заголовком. Этот пример может помочь: http://java -x.blogspot.com / 2006/11 / merge-pdf-files-with-itext.html
  3. Запись объединенного PDF-файла в экземпляр ByteArrayOutputStream
  4. Задать длину содержимого ответа
  5. Установить тип контента и расположение контента
  6. Получить байты из ByteArrayOutputStream и записать эти байты в servletOutputStream
  7. Закрыть ByteArrayOutputStream
2 голосов
/ 28 марта 2011

Если вы не хотите создавать временные файлы, вам просто нужно получить PDF-файл как InputStream из БД и позволить iText прочитать его и, наконец, записать в OutputStream ответа.Ваш вопрос на самом деле слишком широк, чтобы дать подходящий ответ («Я никуда не ухожу» не дает много работы), поэтому вот широкий ответ:

InputStream input = resultSet.getBinaryStream("columnname");
PdfReader reader = new PdfReader(input);
// ...

OutputStream output = response.getOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(document, output);
// ...

Вы также можете пройтиоколо ByteArrayOutputStream вместо.


Обновление в соответствии с вашими проблемами:

  1. Вам необходимо установить заголовки ответа до того, как вы передадитетело ответа на PdfWriter.

    response.setContentType("application/pdf");
    response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
    PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
    // ...
    
  2. Избавьтесь от следующих строк.Они только испортили бы вещи.

    byte[] bytes = blob.getBytes(1, (int) blob.length());
    servletOutputStream.write(bytes, 0, bytes.length);
    servletOutputStream.flush();
    servletOutputStream.close();
    

    PdfWriter уже напишет в тело ответа.Вам не нужно повторять это самим.

...