Экспорт в один HTML со встроенными изображениями с помощью отчета Jasper

может ли отчет Jasper экспортировать в один HTML со встроенными изображениями?

У меня есть вывод отчетов jasper в виде одного файла Excel, PDF, RTF. Но многоигровые HTML-файлы. Мне сложно управлять не одним файлом отчета, а многими файлами и папками в HTML-корпусе.

5 ответов


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

<img src="data:image/png;base64,iVBORw0K... " />

поэтому сначала вы должны использовать синтаксический анализатор xml java, чтобы найти все теги изображений в html http://www.mkyong.com/tutorials/java-xml-tutorials/. Затем вы прочитаете все файлы, конвертируете их в строку base64http://www.xinotes.org/notes/note/736/ и замените img's src с вышеуказанным форматом.


решение:

Map<String, String> images = new HashMap<>();

SimpleHtmlExporterOutput simpleHtmlExporterOutput = new SimpleHtmlExporterOutput(outputStream);
simpleHtmlExporterOutput.setImageHandler(new HtmlResourceHandler() {

            @Override
            public void handleResource(String id, byte[] data) {
                System.err.println("id" + id);
                images.put(id, "data:image/jpg;base64," + Base64.encodeBytes(data));
            }

            @Override
            public String getResourcePath(String id) {
                return images.get(id);
            }
        });

полный код:

package com.test.report;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRXmlDataSource;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.HtmlResourceHandler;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleHtmlReportConfiguration;

import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.olap4j.impl.Base64;

import com.artech.reportservice.reports.ReportType;

public class ReportTest {
    Map<String, String> images = new HashMap<>();

    @Test
    public void test() throws Exception {
        // String outFileName = "test.html";

        String xmlFileLocation = "/Users/skozlic/dev/VacationToolProject/wokspace/ReportService/src/test/resources/machineReportTestFile.xml";

        JasperReport reportTemplate = ReportType.MPM.getReportTemplate();
        JRXmlDataSource jrxmlds = ReportType.MPM.getReportDateSource(xmlFileLocation);
        JasperPrint jasperPrint = JasperFillManager.fillReport(reportTemplate, null, jrxmlds);

        HtmlExporter exporterHTML = new HtmlExporter();
        SimpleExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
        exporterHTML.setExporterInput(exporterInput);
        SimpleHtmlReportConfiguration reportExportConfiguration = new SimpleHtmlReportConfiguration();

        exporterHTML.setConfiguration(reportExportConfiguration);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        SimpleHtmlExporterOutput simpleHtmlExporterOutput = new SimpleHtmlExporterOutput(outputStream);
        simpleHtmlExporterOutput.setImageHandler(new HtmlResourceHandler() {

            @Override
            public void handleResource(String id, byte[] data) {
                System.err.println("id" + id);
                images.put(id, "data:image/jpg;base64," + Base64.encodeBytes(data));
            }

            @Override
            public String getResourcePath(String id) {
                return images.get(id);
            }
        });
        exporterHTML.setExporterOutput(simpleHtmlExporterOutput);

        exporterHTML.exportReport();
        FileUtils.writeByteArrayToFile(new File("test.html"), outputStream.toByteArray());

    }
}

я боролся с этим в течение последних нескольких дней и, наконец, решил это. Мои отчеты работают в веб-среде, поэтому я смог использовать net.sf.jasperreports.j2ee.servlets.ImageServlet для обслуживания изображений. Это требует некоторой настройки.

  1. использовать JRImageRenderer для отображения изображений в самом отчете:

    <image ... >
      ...
      <imageExpression>
        <![CDATA[net.sf.jasperreports.engine.JRImageRenderer.getInstance($F{image_data})]]>
      </imageExpression>
    </image>
    

    здесь $F{image_data} - это двоичные данные изображения.

  2. при экспорте отчета, назначить WebResourceHandler в качестве обработчика ресурсов HTML.

    SimpleHtmlExporterOutput exporterOutput = new SimpleHtmlExporterOutput(byteArrayOutputStream);
    HtmlResourceHandler imageHandler = new WebHtmlResourceHandler("https://www.mywebsite.com/report/image?image={0}");
    exporterOutput.setImageHandler(imageHandler);
    exporter.setExporterOutput(exporterOutput);
    exporter.exportReport();
    

    чтобы проверить, если вы теперь создаете отчет HTML и проверяете Источник, вы должны увидеть что-то вроде <img href="http://www.mywebsite.com/report/image?image=img_0_0_2.png" />.

  3. теперь вам нужно активировать ImageServlet, поэтому он может перехватывать и выполнять запросы изображения. Добавьте следующий блок в ваш :

    <servlet>
      <servlet-name>JasperImageServlet</servlet-name>
      <servlet-class>net.sf.jasperreports.j2ee.servlets.ImageServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>JasperImageServlet</servlet-name>
      <url-pattern>/report/image</url-pattern>
    </servlet-mapping>
    

    (заметьте, что тег /report/image путь соответствует аргументу URL, который мы передали WebHtmlResourceHandler.)

    запустите веб-сервер и попробуйте создать HTML доложите еще раз. Конечно, это все равно не сработает, но скопируйте URL-адрес изображения и вставьте его в браузер. Вы должны получить сообщение об ошибке от ImageServlet это

    в сеансе HTTP не найдено документов JasperPrint.

  4. последнее, что нужно сделать, это добавить JasperPrint объект для сеанса, поэтому ImageServlet знает, какой образ служить. В JSP это можно сделать так:

    JasperPrint jasperPrint = ...
    HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
    session.setAttribute(ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
    

теперь это должен работать.


Как отметил Илья, до недавнего времени uri данных не был перекрестно совместим, поэтому вам пришлось сохранить несколько файлов. Возможно, потребуется подать запрос на улучшение с помощью Jasper, чтобы запросить возможность сохранения html как одного файла со встроенными uris данных


небольшое улучшение к решению Дэйва Джарвиса.

вместо жесткого кодирования типа mime в

images.put(id, "data:image/jpg;base64," + Base64.encodeBytes(data));

вы можете попытаться обнаружить тип mime следующим образом:

// Find out the mime type
final ByteArrayInputStream bis = new ByteArrayInputStream( data );
final String mimeType = URLConnection.guessContentTypeFromStream( bis );
// Convert to an embedded "data" url.
final String base64Data = "data:"+mimeType+";base64,"+Base64.encodeBytes( data );
imagesMap.put( id, base64Data );