14.09.2017

Java. Печатаем PDF отчеты на основе HTML шаблонов.

Однажды я столкнулся с ситуацией, когда мне нужно было быстро сделать функционал для печати одного отчета из Java, который был несложен по структуре данных, но должен был быть красиво оформлен (с определенными шрифтами, изображением и т.п.). Если формировать PDF программно из Java, этого добиться сложно. Как правило, для печати PDF отчетов по шаблону, в Java используются библиотеки вроде JasperReports, Apache PDFBox и пр. Следовательно, если использовать типичные библиотеки для формирования отчетов, то нужно в первую очередь разработать соответствующий шаблон отчета.  И здесь я подумал: "один отчет, нужен дизайн шаблона. Быстро сделать дизайн? HTML/CSS!". Лень - двигатель прогресса. В итоге, я сделал печать PDF отчета на основе HTML шаблона. Приведу пример, который показывает, как можно получить PDF документ на основе HTML5 шаблона с произвольным дизайном. Разумеется, такой способ печати PDF не претендует на замену традиционных решений, но в некоторых случаях может быть полезен. 

Итак, в качестве шаблона используется HTML5 документ, который определяет структуру и дизайн шаблона. Данные, которые необходимо отображть в PDF отчете будут заполняться в документе с помощью библиотеки JSoup. Затем, заполненный документ будет преобразовываться в PDF с помощью библиотеки Openhtmltopdf. В демонстрационном проекте будет использоваться следующая структура:

В папке fonts положим шрифт, который будем использовать в отчете (он необходим для формирования PDF документа). items_report.html - шаблон отчета. В папку print будет сохраняться итоговый PDF документ.

Шаблон для отчета выглядит таким образом:

<!DOCTYPE HTML>
<html>
<head>
    <title></title>
    <meta charset="utf-8">
    <!-- CSS пропущен -->
</head>
<body>
<h2>Перечень товаров</h2>
<table id="goods-rows">
    <tr class="header-row">
        <td>Название</td>
        <td>Количество</td>
        <td>Цена, руб</td>
        <td>Наличие</td>
    </tr>
    <tr class="row-template">
        <td class="name"></td>
        <td class="count"></td>
        <td class="price"></td>
        <td class="available"></td>
    </tr>
</table>
<h3>Дата отчета: <span id="date"></span></h3>
</body>
</html>

При заполнении отчета данными, в качестве селекторов будут использоваться id элемента. В это примере возможно заполнение отдельных полей, которые идентифицируются по id элемента, и заполнение таблиц, которые также ищутся в HTML документе по id. В таблице должна присутствовать строка с классом row-template. Селекторами для столбцов являются CSS классы.

В классе HTMLPrintUtil имеется статический метод, который заполняет HTML шаблон данными и возвращает байты сформированного PDF документа (полный код см. HTMLPrintUtil.java):

public static byte[] printPdfReport(String reportTemplate, Map<String, Object> data) 
            throws Exception {

  Document report = fillReportTemplate(reportTemplate, data);
  org.w3c.dom.Document w3cDoc = DOMBuilder.jsoup2DOM(report);

  return buildPdfReportFromDocument(w3cDoc);
}

Вызов печати (полный код см. Main.java) будет выглядеть таким образом:

public static void main(String [] args) {
   try {
        byte[] pdf = HTMLPrintUtil.printPdfReport("items_report.html", getTestData());
        FileUtils.writeByteArrayToFile(new File("src/main/resources/print/goods.pdf"), pdf);

   } catch (Exception e) {
            e.printStackTrace();
   }
}

В результате вызова метода печати будет сформирован PDF документ такого вида:

Скачать пример



Теги: java programming

comments powered by Disqus