Экспорт в один 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
для обслуживания изображений. Это требует некоторой настройки.
-
использовать
JRImageRenderer
для отображения изображений в самом отчете:<image ... > ... <imageExpression> <![CDATA[net.sf.jasperreports.engine.JRImageRenderer.getInstance($F{image_data})]]> </imageExpression> </image>
здесь
$F{image_data}
- это двоичные данные изображения. -
при экспорте отчета, назначить
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" />
. -
теперь вам нужно активировать
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.
-
последнее, что нужно сделать, это добавить
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 );