[code]
使用Fusion Chart制作报表(dom4j生成XML)

首次看到Fusion Chart是在Bug Free上,有个统计功能,看到了这个数据报表,也是Flash实现的,和Open Flash Chart类似,但是数据格式完全不同。OFC使用JSON数据,而Fusion Chart使用XML数据,OFC是单文件的,而FC是多文件(不同的Flash显示不同类型的报表)。Fusion Chart的官方网站是http://www.fusioncharts.com/free ,可以下载开发包和查看示例。下载Fusion Charts Free后的开发包内有swf文件,示例代码和支持的JS文件。我们只要swf和js即可,开发环境自行搭建,非常简单,注意这里我们使用免费的Fusion Charts Free。
因为Fusion Chart的数据源是XML格式,那么就要准备生成XML的API,这有很多选择,如JDOM,DOM4J都不错。因为Hibernate默认只用了Dom4J来解析XML,那么为了避免过多引入JAR依赖,就使用Dom4j来生成XML文本。下面先对Dom4j做个初步的封装,使得使用起来方便一些。

package org.xxx.core.util; 


import java.io.IOException; 

import org.dom4j.Document; 

import org.dom4j.DocumentHelper; 

import org.dom4j.Element; 

/** 

 * 使用dom4j生成XML工具类 

 * 

 * @author Sarin 

 * 

 */ 

public class XMLUtil { 

 private Document document = null; 


 public Document getDocument() { 

 return document; 

 } 

 /** 

 * 构造方法,初始化Document 

 */ 

 public XMLUtil() { 

 document = DocumentHelper.createDocument(); 

 } 

 /** 

 * 生成根节点 

 * 

 * @param rootName 

 * @return 

 */ 

 public Element addRoot(String rootName) { 

 Element root = document.addElement(rootName); 

 return root; 

 } 

 /** 

 * 生成节点 

 * 

 * @param parentElement 

 * @param elementName 

 * @return 

 */ 

 public Element addNode(Element parentElement, String elementName) { 

 Element node = parentElement.addElement(elementName); 

 return node; 

 } 

 /** 

 * 为节点增加一个属性 

 * 

 * @param thisElement 

 * @param attributeName 

 * @param attributeValue 

 */ 

 public void addAttribute(Element thisElement, String attributeName, 

 String attributeValue) { 

 thisElement.addAttribute(attributeName, attributeValue); 

 } 

 /** 

 * 为节点增加多个属性 

 * 

 * @param thisElement 

 * @param attributeNames 

 * @param attributeValues 

 */ 

 public void addAttributes(Element thisElement, String[] attributeNames, String[] attributeValues) { 

 for (int i = 0; i < attributeNames.length; i++) { 

 thisElement.addAttribute(attributeNames[i], attributeValues[i]); 

 } 

 } 

 /** 

 * 增加节点的值 

 * 

 * @param thisElement 

 * @param text 

 */ 

 public void addText(Element thisElement, String text) { 

 thisElement.addText(text); 

 } 

 /** 

 * 获取最终的XML 

 * 

 * @return 

 * @throws IOException 

 */ 

 public String getXML() { 

 return document.asXML().substring(39); 

 } 

}


获取的XML因为包含声明,而Fusion Chart中不需要,所以这里就从根标记处开始截取。下面来看看Fusion Chart解析XML的格式。取自官方网站的一个示例:

<graph yAxisName='Sales Figure' caption='Top 5 Sales Person' numberPrefix='$' decimalPrecision='1' divlinedecimalPrecision='0' limitsdecimalPrecision='0'> 

 <set name='Alex' value='25000' color='AFD8F8'/> 

<set name='Mark' value='35000' color='F6BD0F'/> 

<set name='David' value='42300' color='8BBA00'/> 

<set name='Graham' value='35300' color='FF8E46'/> 

<set name='John' value='31300' color='008E8E'/> 

</graph>



根标记是graph,其中有可配置的属性,可以参考官方文档,这里不详细列出了。单分类报表中使用set子标记作为数据,下面来看一个具体的数据源生成方法,使用了Struts2作为Web框架来处理请求。

package org.xxx.app.action; 


import java.util.HashMap; 

import java.util.List; 

import java.util.Map; 

import org.dom4j.Element; 

import org.xxx.core.util.XMLUtil; 


public class ChartAction extends BaseAction { 

 private String xmlStr; 


 public String getXmlStr() { 

 return xmlStr; 

 } 

 public String chart() throws Exception { 

 XMLUtil xml = new XMLUtil(); 

 Element graph = xml.addRoot("graph"); 

 xml.addAttribute(graph, "caption", "访问统计"); 

 xml.addAttribute(graph, "subCaption", "浏览器类型统计"); 

 xml.addAttribute(graph, "basefontsize", "12"); 

 xml.addAttribute(graph, "xAxisName", "浏览器类型"); 

 xml.addAttribute(graph, "decimalPrecision", "0");// 小数精确度,0为精确到个位 

 xml.addAttribute(graph, "showValues", "0");// 在报表上不显示数值 

 List browserList = getServMgr().getChartService().getStatsByType("browser"); 

 for (int i = 0; i < browserList.size(); i++) { 

 Map item = (HashMap) browserList.get(i); 

 Element set = xml.addNode(graph, "set"); 

 set.addAttribute("name", (String) item.get("statVar")); 

 set.addAttribute("value", item.get("statCount").toString()); 

 set.addAttribute("color", Integer.toHexString( 

 (int) (Math.random() * 255 * 255 * 255)).toUpperCase()); 

 } 

 xmlStr = xml.getXML(); 

 return "chart"; 

 } 

}



数据的获取使用了Spring的JdbcTemplate来进行,方法如下:

private static final String SQL_GET_STATS = "select statVar,statCount from stats where statType=?"; 

 public List getStatsByType(String type) { 

 return jt.queryForList(SQL_GET_STATS, new Object[] { type }); 

}


数据表的结构可以参考 http://sarin.iteye.com/admin/blogs/685354这篇,因为相同的演示,就用了同一个表结构。获取到数据遍历之后,就要在页面进行输出显示了,也很简单,页面如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml"> 

<head> 

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<title>Fusion Chart Test</title> 

<script type="text/javascript" src="${base}/js/FusionCharts.js"></script> 

</head> 

<body> 

<div id="chartDiv"></div> 

<script type="text/javascript"> 

 var chart = new FusionCharts("${base}/charts/FCF_Column3D.swf", "0", "800", "600"); 

 chart.setDataXML('${xmlStr}'); 

 chart.render('chartDiv'); 

 </script> 


</body> 

</html>



使用setDataXML()方法获取传递过来的xmlStr,就是我们需要的XML数据。简单的报表这样就可以了。如果是多类别报表,只是在XML格式上有所不同,参考官方示例,重新编写XML即可。下面来看看生成的报表,非常的不错。

[/code]