Struts 中结合 JFreeChart,iText 生成 PDF 报表

http://www.ibm.com/developerworks/cn/opensource/os-cn-strutspdf/index.html?ca=drs-#ibm-pcon

需求描述


本文中向读者朋友提供了一种 PDF 报表系统的解决方案,并将重点放在如何整合开源框架以实现系统要求,以及如何解决实际开发过程中的疑难问题上,对于广大的开源框架爱好者和开发人员具有一定的借鉴意义。该报表解决方案主要提供以下功能:
用户图片上传
根据数据生成柱状图,折线图
汇总数据及图片,最终以 PDF 进行呈现

回页首

开源框架整合

基于对开源领域中比较成熟的框架的比较,我们最终选择以 Struts 为基础,整合 common-fileupload,JFreechart 和 iText,以实现上述的系统功能。下面我们来讲述如何整合这些开源框架,建立开发环境。

Struts

Struts(http://struts.apache.org/) 是广泛使用的 MVC 框架,相信很多开发人员都非常熟悉,这不是本文的重点,仅会提及一个技术点,即如何在 Struts 框架中实现文件上传,将在下文中详细描述。

Commons-fileupload

Commons-fileupload (http://commons.apache.org/fileupload/) 能与 Servlet 及 Web application 很好地结合,基于对 Http request 的解析,可以被方便灵活地调用,从而提供高性能的文件上传功能。

JFreeChart

JFreeChart(http://www.jfree.org/) 主要是用来制作各种各样的图表,包括:饼图、柱状图 ( 普通柱状图以及堆栈柱状图 )、线图、区域图、分布图、混合图、甘特图以及一些仪表盘等等。本文中使用的是 jfreechart-1.0.13.jar。

iText

iText(http://itextpdf.com/) 是一个能够快速产生 PDF 文件的 Java 类库,与 Servlet 有很好的给合,可以非常方便完成 PDF 输出,最新的版本是 iText-5.0.4.jar。如果需要在报表中支持中文显示,还需要下载 iTextAsian.jar。

Eclipse 中整合开源框架

为完成开发框架的搭建工作,我们需要将上述的几个开源框架整合到 Eclipse 中。读者需要通过以上的链接下载相应的各个 Jar 包,然后导入到工程的类路径下。可以参考 Eclipse 的相关资料来完成这些配置操作。

回页首

Struts 中的文件上传

基于 Struts 框架实现文件上传需要注意以下两点:
Form 需要增加属性: enctype="multipart/form-data"。
如:<form method="post" id="reportForm" enctype="multipart/form-data">
需要直接继承自 Action,而不能是 DispatchAction。

以上两点需要在开发过程中加以注意,否则使用 ServletFileUpload 的 parseRequest() 方法解析 request 的时候,得不到 Form 中 file 域传递的值。JSP 页面的代码在这里不再赘述,下面通过代码及注释来说明 Commons-fileupload 的使用,读者可以根据实际需要设定上传图片的保存路径和文件的名称。

清单 1. 使用 Commons-fileupload 上传文件
DiskFileItemFactory factory = new DiskFileItemFactory();
// 实例化硬盘文件工厂
factory.setSizeThreshold(8192);// 存放临时文件的内存大小
String tempPath = request.getRealPath("/") + "/images/temp";
if(!new File(tempPath).isDirectory())
new File(tempPath).mkdirs();
factory.setRepository(new File(tempPath));

// 设置上传路径
uploadPath = request.getRealPath("/") + "/web/report/images/";
if(!new File(uploadPath).isDirectory())
new File(uploadPath).mkdirs();

// 初始化上传组件,循环 form 中的所有 input 类型为 file 的 field,上传文件
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
Iterator<FileItem> itr = items.iterator();
while (itr.hasNext()) {// 依次处理每个 form field
FileItem item = (FileItem) itr.next();
File savedFile = new File(uploadPath, "imageFileName.jpg");
item.write(savedFile);
}



回页首

JFreechart 生成报表

最新的 struts 2.0 已经集成了 JFreechart,作为一种 ResultType 在 Action 中可以直接返回,读者如果感兴趣可以参考其他相关的资源。本文中我们介绍如何基于 Struts 1.x 版本来集成使用 JFreechart。

生成图片报表

这里我们封装了一个实用类 ChartUtil,它继承自 JFreeChart 的 ServletUtilities 类,来提供本文所述报表方案的所有生成 JFreechart 报表的功能。清单 2 中给出了如何生成一个柱状图的方法,该方法的调用将会在清单 6 中看到。

清单 2. 封装 JFreechart 的 util 类,生成柱状图
public static String generateBarChart(HttpServletRequest request,
CategoryDataset dataset, int w, int h,double rangeMarker)
throws IOException {
JFreeChart chart = ChartFactory.createBarChart3D("Latency in ms", // 图表标题
"Time", // 目录轴的显示标签
"Milliseconds", // 数值轴的显示标签
dataset, // 数据集
PlotOrientation.VERTICAL, // 图表方向:水平、垂直
true, // 是否显示图例 ( 对于简单的柱状图必须是 false)
false, // 是否生成工具
false // 是否生成 URL 链接
);
setAttribute(chart);

createTempDir(request);

chart.getCategoryPlot().addRangeMarker(new ValueMarker(rangeMarker));

String tempDirName = request.getRealPath("/") + "/web/report/images/temp/";

String prefix = ServletUtilities.getTempFilePrefix();
if (request.getSession() == null) {
prefix = ServletUtilities.getTempOneTimeFilePrefix();
}

File tempFile = File.createTempFile(prefix, ".png",
new File(tempDirName));
try {
ChartRenderingInfo info = new ChartRenderingInfo(
new StandardEntityCollection());

ChartUtilities.saveChartAsPNG(tempFile, chart, w, h, info);
} catch (IOException e) {
e.printStackTrace();
}
return tempDirName + tempFile.getName();
}



修改默认图片保存路径

JFreeChart 默认将生成的图片保存在应用服务器的 temp 目录下,有些时候,我们不能使用默认的保存路径,而是需要能够再次通过应用程序读取这些图片,这时就需要将图片保存在应用程序的目录下。下面,我们将介绍如何实现对默认图片保存路径的修改,即在 ChartUtil 类中重写 createTempDir 方法,将图片保存在应用程序的 /web/report/images/temp 目录下。

清单 3. 重写 createTempDir 方法
protected static void createTempDir(HttpServletRequest request) {
String tempDirName = request.getRealPath("/") + "/web/report/images/temp";
if (tempDirName == null) {
throw new RuntimeException("Temp directory is null.");
}

File tempDir = new File(tempDirName);
if (!tempDir.exists()) {
tempDir.mkdirs();
}
}



如何定制图片样式

JFreeChart 提供了对图片格式修改的各种 API,包括对图片背景,文字显示,曲线,坐标等等一系列的格式设置,读者可以根据实际需要查询相应的 API 来实现。比如,上面的清单 2 中,我们有如下一行代码,实现了在柱状图中增加一条阈值线。

清单 4. 柱状图中增加阈值线
chart.getCategoryPlot().addRangeMarker(new ValueMarker(rangeMarker));



回页首

iText 生成 PDF 报表

iText 是一个 Java 类库,可以方便地创建,读取和操作 PDF 文件。下面我们通过一个最简单的例子来说明如何使用 iText。然后重点介绍一下几个比较重要的 object,并针对最常见的使用过程中遇到的问题给出一些建议。

清单 5. iText 的简单使用
//set pdf location and the title
String pdfLocation = request.getRealPath("/") + "/web/report/pdf/";
String pdfName= "test.pdf";
String pdfFile = pdfLocation + pdfName;

Document document = new Document();
try {
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFile));
document.open();
document.add(new Paragraph("Hello world"));
} catch (DocumentException de) {
System.err.println(de.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
} finally {
document.close();
}



iText 结构概览

从上面的代码片段中,我们可以看到 Document 对象是 iText 的基础,从 open,add,close 的调用过程,我们也可以很容易理解 iText 的使用。

iText 对于对象的组织,也是像实际的 PDF 文件中一样,是一种分级结构。Chunk(块)是 iText 中最小也是最重要的可以被加入到 Document 中的文本块,绝大部分的元素都可以被分割成 Chunk。Phrase 由一个或多个 Chunk 组成,它有一个主字体样式,同时包含在其中的 Chunk 可以通过设置使用不同于 Phrase 的其他字体样式。

下面我们通过代码片段来看看如何将图片写入到 PDF 文件中,其实,这与写入普通的文本并没有实质区别。我们通过 dataService 获取生成 JFreeChart 的数据集,然后调用 ChartUtil 生成图片并返回图片文件的路径及名称,进而得到一个 com.itextpdf.text.Image 对象,将它增加到一个 PdfPTable 中写入 PDF。

清单 6. 用 iText 将 JFreechart 图表写入 PDF
// 初始化一个 PdfPTable
PdfPTable BarTable = new PdfPTable(1);
PdfPCell cellDescription =
new PdfPCell(new Paragraph("This is a image from JFreechart"));
cellDescription .setBorder(PdfPCell.NO_BORDER);
BarTable.addCell(cellDescription );

// 生成柱状图
CategoryDataset latencyDataset = dataService.getLatencyDataset(nodeA, nodeB, month);
String fileName = ChartUtil.generateBarChart(request,
latencyDataset, 500, 200,link.getLatency());
Image imageLatency = Image.getInstance(fileName);

// 加到 table 中
PdfPCell cellImageLatency = new PdfPCell(imageLatency);
cellImageLatency.setBorder(PdfPCell.NO_BORDER);
cellImageLatency.setHorizontalAlignment(Element.ALIGN_CENTER);
BarTable.addCell(cellImageLatency);

// 生成曲线图
CategoryDataset lossDataset = dataService.getLossDataset(nodeA, nodeB, month);
fileName = ChartUtil.generateLineChart(request, lossDataset, 500, 200);
Image imageLoss = Image.getInstance(fileName);
// 加到 table 中
PdfPCell cellImageLoss = new PdfPCell(imageLoss);
cellImageLoss.setBorder(PdfPCell.NO_BORDER);
BarTable.addCell(cellImageLoss);
// 写入 PDF
document.add(BarTable);



iText 支持中文

为了让 iText 支持中文,我们需要下载语言包并加入到类路径中。最新的 iText-5.0.4.jar 对包结构进行了更改,由 com.lowagie.text.pdf.fonts 更新为 com.itextpdf.text.pdf.fonts,但是 iTextAsian.jar 依旧是沿用旧的包结构,因此我们需要修改 iTextAsian.jar 的包的结构,才能正确支持中文。

清单 7. iText 中如何支持中文字体
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED);
Font chineseFont= new Font(bfChinese, 12, Font.NORMAL);
PdfPCell cellReportSummary = newPdfPCell(newPhrase("支持中文",chineseFont));




参考资料

学习
参考 http://struts.apache.org/首页,查看 Struts 的最新信息。

参考 http://commons.apache.org/fileupload/,查看 commons-fileupload 的最新信息。

参考 http://itextpdf.com/首页,查看 iText 的最新信息。

参考 http://www.jfree.org/首页,查看 JFreechart 的最新信息。

访问 developerWorks Open source 专区获得丰富的 how-to 信息、工具和项目更新以及 最受欢迎的文章和教程,帮助您用开放源码技术进行开发,并将它们与 IBM 产品结合使用。

随时关注 developerWorks 技术活动和 网络广播。


讨论
欢迎加入 My developerWorks 中文社区。


作者简介

张永峰,IBM 中国软件开发实验室的一名软件工程师,具有多年开发经验及撰稿经验。对 Java、Web 开发的多个领域均有深刻的理解和认识。


黄健昌,IBM 中国软件开发实验室的一名高级软件工程师,对 Java 开发的多个领域均有深刻的理解和认识。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值