Статьи

Использование динамически генерируемых диаграмм JFreeChart и JasperReports

Если вы читаете этот блог, это означает, что вы хотите использовать JasperReport с динамически создаваемыми изображениями. Пример таких сценариев использования при создании сложных диаграмм с использованием JFreeChart и последующем включении этих диаграмм в отчеты.

Каждый отчет в JasperReport использует источник данных для заполнения полей, нам нужно использовать JRBeanCollectionDataSource, который можно рассматривать как простую коллекцию JavaBeans. Каждый объект в JRBeanCollectionDataSource можно использовать для заполнения одной строки отчета или для подготовки вычисляемых значений и т. Д.

Каждый отчет в JasperReport представляет собой XML-файл, в котором описывается отчет. в нашем случае документ с описанием отчета выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="DataSourceReport" pageWidth="595" pageHeight="842" columnWidth="515" leftMargin="40" rightMargin="40" topMargin="50" bottomMargin="50">
<style name="Sans_Normal" isDefault="true" fontName="DejaVu Sans" fontSize="12" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false"/>
<style name="Sans_Bold" isDefault="false" fontName="DejaVu Sans" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false"/>
<style name="Sans_Italic" isDefault="false" fontName="DejaVu Sans" fontSize="12" isBold="false" isItalic="true" isUnderline="false" isStrikeThrough="false"/>
<field name="image" class="java.awt.image.BufferedImage"/>
<field name="description" class="java.lang.String"/>
<detail>
<band height="180">
<image scaleImage="RetainShape" hAlign="Center" isUsingCache="true" isLazy="true">
<reportElement x="67" y="17" width="344" height="140"/>
<imageExpression class="java.awt.Image"><![CDATA[$F{image}]]></imageExpression>
</image>
<textField>
<reportElement x="83" y="157" width="311" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>

Как видите, я определил два поля с именем image и description, которые являются двумя свойствами объектов ReportBean, включенных в источник данных. Отчет выглядит следующим образом в IreportDesigner (я использую плагин NetBeans для разработки отчетов).

отчет в конструкторе

Давайте посмотрим, какой класс JavaBean мы хотим использовать для переноса полей отчета из нашего Java-кода в движок JasperReport.

public class ChartBean {

public ChartBean(BufferedImage image, String description) {
setImage(image);
setDescription(description);
}



private java.awt.image.BufferedImage image;
private String description;

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public BufferedImage getImage() {
return image;
}

public void setImage(BufferedImage image) {
this.image = image;
}


}

Теперь нам нужно подготовить источник данных для отчета, подготовить источник данных. Я написал метод, подобный следующему фрагменту, который использует другой метод для извлечения BufferedImage из элементов JFreeChart, которые мы хотим включить в отчет.

public JRBeanCollectionDataSource prepareDataSource() {


List charts = new ArrayList();

for (int i = 0; i < 5; i++) {
JFreeChart chart = createChart("This is chart number: " + i);
BufferedImage bi = extractImage(chart, 800, 600);
ChartBean chartBean = new ChartBean(bi, "This is description for Chart: " + i);
charts.add(chartBean);
}

return new JRBeanCollectionDataSource(charts);
}

Метод createChart создает несколько типовых диаграмм, которые мы включим в отчет. метод прост в создании некоторых фиктивных кольцевых диаграмм без каких-либо конкретных и значимых данных.

private JFreeChart createChart(String chartTitle) {


DefaultPieDataset piedataset = new DefaultPieDataset();
piedataset.setValue("One", new Double(43.200000000000003D));
piedataset.setValue("Two", new Double(10D));
piedataset.setValue("Three", new Double(27.5D));
piedataset.setValue("Four", new Double(17.5D));
piedataset.setValue("Five", new Double(11D));
piedataset.setValue("Six", new Double(19.399999999999999D));


JFreeChart jfreechart = ChartFactory.createRingChart(chartTitle, piedataset, false, true, false);

RingPlot ringplot = (RingPlot) jfreechart.getPlot();
ringplot.setLabelFont(new Font("SansSerif", 0, 12));
ringplot.setNoDataMessage("No data available");
ringplot.setSectionDepth(0.34999999999999998D);
ringplot.setCircular(false);
ringplot.setLabelGap(0.02D);
return jfreechart;
}

Другой метод, который необходимо объяснить, это extractImage, который просто создает BufferedImage из заданного объекта JfreeChart.

 public BufferedImage extractImage(JFreeChart chart, int width, int height) {
BufferedImage img =
new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = img.createGraphics();
chart.draw(g2, new Rectangle2D.Double(0, 0, width, height));

g2.dispose();
return img;

}

Наконец, у меня есть метод с именем showReport, который использует созданный источник данных для подготовки отчета, а затем использует JRViewer для отображения отчета. Фрагмент кода выглядит следующим образом:

  public void showReport(JRBeanCollectionDataSource dataSource) {

try {
Map parameters = new HashMap();
JasperDesign jasperDesign = JRXmlLoader.load(this.getClass().getResourceAsStream("/jasperdynamic/report.jrxml"));
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
JRViewer viewer = new JRViewer(jasperPrint);
viewer.setSize(850, 500);
viewer.setMinimumSize(new Dimension(850, 510));
viewer.setPreferredSize(new Dimension(850, 510));

this.setLayout(new BorderLayout(10, 10));

this.setSize(850, 500);

this.getContentPane().add(viewer);
this.setVisible(true);

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

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

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jasperdynamic;

import javax.swing.JFrame;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.view.JRViewer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.RingPlot;
import org.jfree.data.general.DefaultPieDataset;

/**
*
* @author masoud
*/
public class Main extends JFrame {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main m = new Main();

m.showReport(m.prepareDataSource());

}

public JRBeanCollectionDataSource prepareDataSource() {


List charts = new ArrayList();

for (int i = 0; i < 5; i++) {
JFreeChart chart = createChart("This is chart number: " + i);
BufferedImage bi = extractImage(chart, 800, 600);
ChartBean chartBean = new ChartBean(bi, "This is description for Chart: " + i);
charts.add(chartBean);
}

return new JRBeanCollectionDataSource(charts);
}

public BufferedImage extractImage(JFreeChart chart, int width, int height) {
BufferedImage img =
new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = img.createGraphics();
chart.draw(g2, new Rectangle2D.Double(0, 0, width, height));

g2.dispose();
return img;

}

public void showReport(JRBeanCollectionDataSource dataSource) {

try {
Map parameters = new HashMap();
JasperDesign jasperDesign = JRXmlLoader.load(this.getClass().getResourceAsStream("/jasperdynamic/report.jrxml"));
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
JRViewer viewer = new JRViewer(jasperPrint);
viewer.setSize(850, 500);
viewer.setMinimumSize(new Dimension(850, 510));
viewer.setPreferredSize(new Dimension(850, 510));

this.setLayout(new BorderLayout(10, 10));

this.setSize(850, 500);

this.getContentPane().add(viewer);
this.setVisible(true);

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

private JFreeChart createChart(String chartTitle) {


DefaultPieDataset piedataset = new DefaultPieDataset();
piedataset.setValue("One", new Double(43.200000000000003D));
piedataset.setValue("Two", new Double(10D));
piedataset.setValue("Three", new Double(27.5D));
piedataset.setValue("Four", new Double(17.5D));
piedataset.setValue("Five", new Double(11D));
piedataset.setValue("Six", new Double(19.399999999999999D));


JFreeChart jfreechart = ChartFactory.createRingChart(chartTitle, piedataset, false, true, false);

RingPlot ringplot = (RingPlot) jfreechart.getPlot();
ringplot.setLabelFont(new Font("SansSerif", 0, 12));
ringplot.setNoDataMessage("No data available");
ringplot.setSectionDepth(0.34999999999999998D);
ringplot.setCircular(false);
ringplot.setLabelGap(0.02D);
return jfreechart;
}
}

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

отчет в конструкторе


С http://weblogs.java.net/blog/kalali