B/S環(huán)境下使用JFreeReport展示報表
肖菁
軟件工程師
king@vivianj.org
BEA dev2dev長(cháng)沙UserGroup Leader,開(kāi)源項目BuildFileDesigner、V-SuperMedia創(chuàng )始人,IBM developerWorks/BEA dev2dev/Sun技術(shù)社區撰稿人,主要研究J2EE編程技術(shù)、Web Service技術(shù)以及他們在 WebSphere、WebLogic、 Apache平臺上的實(shí)現,擁有 IBM 的 Developing With Websphere Studio證書(shū)。
[文章摘要] 本文主要講述如何在B/S環(huán)境下使用JFreeReport來(lái)展示報表,表現形式包括HTML表格、PDF文件、PNG圖片、XSL文件等。
[關(guān)鍵詞]: JFreeReport 報表
1 誰(shuí)需要閱讀這篇文章
本文的讀者是已經(jīng)可以熟練使用JFreeReport生成報表內容、能夠在GUI范圍內展示報表但還不是很清楚如何在Web環(huán)境下展示出來(lái)的用戶(hù)。如果你還不是很熟悉這方面的內容請閱讀作者的上一篇文章《使用JFreeReport生成報表》。
2 基礎知識
在作者的上一篇文章發(fā)表后,很多讀者發(fā)來(lái)E_Mail詢(xún)問(wèn)如何在Web環(huán)境下使用JFreeReport來(lái)展示報表內容,作者經(jīng)過(guò)研究后有了一些心得,因此記錄了下來(lái)和大家共享。下面就開(kāi)始一些準備工作。
2.1 JFreeReport目前支持的展示格式
JFreeReport目前支持的展示格式包括HTML表格形式、PDF文件、XSL文件、PNG文件,你還可以擴展JFreeReport來(lái)生成自己需要的展示形式。
2.2 展示原理
JFreeReport的展示原理是比較簡(jiǎn)單的:采用Servlet作為載體,根據已經(jīng)定義好的JFreeReport報表內容,轉化為對應的HTML源代碼、PDF文件、XSL文件或者PNG文件,發(fā)送給瀏覽器用于展示。
3 準備工作
3.1 Web容器準備
請下載一個(gè)支持Servlet的Web容器,作者這里采用的是Tomcat,版本是5.5.8
3.2 Web應用配置
在Tomcat下面新增加一個(gè)Web應用(作者配置該Web應用的上下文路徑為/jfr),然后將JFreeReport需要的支持jar文件放在該Web應用的lib目錄下,主要是解壓縮JFreeReport下載文件目錄下的jfreereport-xxx-all.jar(xxx是下載的JFreeReport版本號)和lib目錄下的所有jar文件。
4 開(kāi)始工作
接下來(lái)就開(kāi)始介紹如何使用JFreeReport來(lái)展示報表內容了,作者首先采用其中HelloWorld類(lèi)定義的簡(jiǎn)單報表來(lái)演示如何分別用HTML表格、PDF文件、XSL文件和PNG圖片來(lái)展示報表內容,最后給出了一個(gè)用HTML表格來(lái)展示復雜報表內容的例子。
4.1 準備報表內容
/*
* 2004-9-28 肖菁 創(chuàng )建
*/
package com.jandar.egov;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.jfree.report.Boot;
import org.jfree.report.ElementAlignment;
import org.jfree.report.JFreeReport;
import org.jfree.report.PageHeader;
import org.jfree.report.ReportProcessingException;
import org.jfree.report.ShapeElement;
import org.jfree.report.elementfactory.LabelElementFactory;
import org.jfree.report.elementfactory.StaticShapeElementFactory;
import org.jfree.report.elementfactory.TextFieldElementFactory;
import org.jfree.report.modules.gui.base.PreviewDialog;
import org.jfree.report.util.Log;
import org.jfree.ui.FloatDimension;
/**
* 使用JFreeReport生成報表的簡(jiǎn)單例子,用于演示使用JFreeReport生成報表的一些基本步驟
*
* 本例子中,為了簡(jiǎn)化操作,報表定義是使用java直接編碼
*
*/
public class HelloWorld {
public HelloWorld(){}
/**
* 創(chuàng )建生成報表需要用到的數據
*
* @返回一個(gè)TableModel實(shí)例
*/
public TableModel getTableModel(){
Object[] columes = new String[]{"id","name"};
TableModel tableModel = new DefaultTableModel(columes,100);
//生成100條記錄
for(int i = 0; i<100 ; i++){
tableModel.setValueAt("100" + i,i,0);
tableModel.setValueAt("中文" + i,i,1);
}
return tableModel;
}
/**
* 創(chuàng )建一個(gè)報表定義,定義報表的列信息
*
* @返回一個(gè)報表定義實(shí)例
*/
public JFreeReport getReportDefinition(){
JFreeReport jFreeReport = new JFreeReport();
jFreeReport.setName("中文測試");
//定義報表的第一列
TextFieldElementFactory colume1 = new TextFieldElementFactory();
colume1.setName("id");
//定義列的起始位置
colume1.setAbsolutePosition(new Point2D.Float(0, 0));
//定義列的范圍
colume1.setMinimumSize(new FloatDimension(150, 20));
//定義顯示TableModel中的哪一列數據
colume1.setFieldname("id");
jFreeReport.getItemBand().addElement(colume1.createElement());
TextFieldElementFactory colume2 = new TextFieldElementFactory();
colume2.setName("name");
colume2.setAbsolutePosition(new Point2D.Float(200, 0));
colume2.setMinimumSize(new FloatDimension(150, 20));
colume2.setFieldname("name");
jFreeReport.getItemBand().addElement(colume2.createElement());
return jFreeReport;
}
/**
* 創(chuàng )建一個(gè)表頭定義,定義報表的表頭信息
*
* @返回一個(gè)報表表頭實(shí)例
*/
public PageHeader getPageHeader(){
PageHeader pageHeader = new PageHeader();
//定義將表頭處畫(huà)填充過(guò)的框
ShapeElement shape =StaticShapeElementFactory.createRectangleShapeElement("id",
new Color(204,204,204),
null,
new Rectangle(0, 0, -100, 20),
false,
true);
pageHeader.addElement(shape);
//定義將表頭第一列
LabelElementFactory colume1 = new LabelElementFactory();
colume1.setName("id");
colume1.setAbsolutePosition(new Point2D.Float(0, 10));
colume1.setMinimumSize(new FloatDimension(150, 20));
//設置列的對齊方式
colume1.setHorizontalAlignment(ElementAlignment.CENTER);
//設置列中顯示的文字
colume1.setText("Id");
pageHeader.addElement(colume1.createElement());
LabelElementFactory colume2 = new LabelElementFactory();colume2.setName("name");
colume2.setAbsolutePosition(new Point2D.Float(200, 10));
colume2.setMinimumSize(new FloatDimension(150, 20));
colume2.setText("Name");
colume2.setHorizontalAlignment(ElementAlignment.CENTER);
pageHeader.addElement(colume2.createElement());
return pageHeader;
}
/**
* 創(chuàng )建一個(gè)完整的報表定義
*
* @返回一個(gè)報表定義的實(shí)例
*/
public JFreeReport getReport(){
TableModel data = getTableModel();
JFreeReport report = getReportDefinition();
PageHeader pageHeader = getPageHeader();
report.setPageHeader(pageHeader);
report.setData(data);
return report;
}
}
4.2 簡(jiǎn)單報表的展示
4.2.1 簡(jiǎn)單報表的HTML展示
JFreeReport提供HtmlProcessor類(lèi)來(lái)將輸入的JFreeReport報表變成HTML表格形式,最后通過(guò)Servlet的輸出通道展示給用戶(hù),具體的用法如下例:
/*
* 2004-9-28 肖菁 創(chuàng )建
*/
package com.jandar.egov;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jfree.report.JFreeReport;
import org.jfree.report.modules.output.table.base.TableProcessor;
import org.jfree.report.modules.output.table.html.HtmlProcessor;
import org.jfree.report.modules.output.table.html.StreamHtmlFilesystem;
import org.jfree.report.util.Log;
/**
* HtmlExampleServlet演示如何通過(guò)HTML表格在Web環(huán)境下展示JFreeReport定義的表格
*/
public class HtmlExampleServlet extends HttpServlet
{
public void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
public void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException
{
TableProcessor worker;
//設置輸出頁(yè)面的Meta信息
response.setHeader("Content-Disposition", "inline; filename=\"" + "unknown.html" + "\"");
//設置頁(yè)面的輸出格式
response.setHeader("Content-Type", "text/html");
try
{
//獲取Servlet的輸出流
OutputStream out = response.getOutputStream();
//獲取HelloWorld中定義的報表
HelloWorld helloWorld = new HelloWorld();
JFreeReport report = helloWorld.getReport();
//將報表和Servlet的輸出流作為參數傳遞給TableProcessor的實(shí)例
final HtmlProcessor processor = new HtmlProcessor(report);
processor.setFilesystem(new StreamHtmlFilesystem(out));
worker = processor;
}
catch (Exception e)
{
Log.debug("無(wú)法解析報表定義", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
try
{
//輸出結果
worker.processReport();
}
catch (Exception e)
{
Log.debug("輸出結果產(chǎn)生錯誤", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
}
}
[注] 這里需要提醒大家的是Web下面的JFreeReport展示內容并不具備和GUI界面下同樣的分頁(yè)能力,也就是說(shuō)不管你的報表內容有多少,他們都會(huì )在一頁(yè)中顯示。
4.2.2 報表的XSL文件展示
XSL展示的方法和HTML的基本類(lèi)似,只是采用ExcelProcessor作為處理類(lèi),然后將輸出文件格式修改為"application/vnd.ms-excel",具體的代碼調用如下(注意粗體顯示的地方):
/*
* TableProcessor是處理HTML輸出的類(lèi)
* 他將提供的JFreeReport報表定義轉化為HTML表格內容,然后通過(guò)Servlet的輸出流展示給用戶(hù)
*/
TableProcessor worker;
//設置輸出頁(yè)面的Meta信息
response.setHeader(
"Content-Disposition",
"inline; filename=\"" + "unknown.xls" + "\"");
//設置頁(yè)面的輸出格式
response.setHeader("Content-Type", "application/vnd.ms-excel");
try {
//獲取Servlet的輸出流
OutputStream out = response.getOutputStream();
//獲取HelloWorld中定義的報表
HelloWorld helloWorld = new HelloWorld();
JFreeReport report = helloWorld.getReport();
//將報表和Servlet的輸出流作為參數傳遞給TableProcessor的實(shí)例
final ExcelProcessor processor = new ExcelProcessor(report);
processor.setOutputStream(out);
worker = processor;
} catch (Exception e) {
Log.debug("無(wú)法解析報表定義", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
try {
//輸出結果
worker.processReport();
} catch (Exception e) {
Log.debug("輸出結果產(chǎn)生錯誤", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
4.2.3 報表的PNG圖片展示
報表的PNG圖片展示和上面的處理有些不同,他是先將報表內容存入BufferedImage對象中緩存起來(lái),然后通過(guò)Servlet的輸出通道傳輸給用戶(hù)的,所以處理過(guò)程比其他幾個(gè)復雜一些,具體的調用代碼如下:
//定義緩存圖片的對象
BufferedImage image = null;
//獲取當前需要顯示的頁(yè)數
String param = request.getParameter("page");
if (param == null) {
Log.debug("Page attribute is missing");
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
int page = 0;
try {
page = Integer.parseInt(param);
} catch (Exception e) {
Log.debug("The page-parameter is invalid", e);
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
PageableReportProcessor worker;
//設置輸出頁(yè)面的Meta信息
response.setHeader(
"Content-Disposition",
"inline;filename=\"report-page-" + page + ".png\"");
//設置頁(yè)面的輸出格式
response.setHeader("Content-Type", "image/png");
// 獲取HelloWorld中定義的報表
HelloWorld helloWorld = new HelloWorld();
JFreeReport report = helloWorld.getReport();
try {
// 初始化輸出對象
worker = new PageableReportProcessor(report);
//獲取頁(yè)面格式
final PageFormat pageFormat =
worker.getReport().getDefaultPageFormat();
//創(chuàng )建被緩存的報表內容
image = Util.createImage(pageFormat);
final Graphics2D g2 = image.createGraphics();
g2.setPaint(Color.white);
g2.fillRect(
0,
0,
(int) pageFormat.getWidth(),
(int) pageFormat.getHeight());
//將報表內容輸出到緩存中
final G2OutputTarget target = new G2OutputTarget(g2, pageFormat);
target.open();
worker.setOutputTarget(target);
ReportStateList pageStateList = worker.repaginate();
ReportState state = pageStateList.get(page);
worker.processPage(state, target);
target.close();
//獲取Servlet的輸出流
final ServletOutputStream out = response.getOutputStream();
// 輸出圖片
final PngEncoder encoder = new PngEncoder(image, true, 0, 9);
final byte[] data = encoder.pngEncode();
out.write(data);
out.flush();
} catch (Exception e) {
Log.debug("無(wú)法解析報表定義", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
聯(lián)系客服