应用Fusion Charts制作报表(dom4j生成XML)

使用Fusion Charts制作报表(dom4j生成XML)

转自:http://sarin.iteye.com/blog/711494

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

Java代码 应用Fusion Charts制作报表(dom4j生成XML)
  1. package org.xxx.core.util;   
  2.   
  3. import java.io.IOException;   
  4. import org.dom4j.Document;   
  5. import org.dom4j.DocumentHelper;   
  6. import org.dom4j.Element;   
  7. /**  
  8.  * 使用dom4j生成XML工具类  
  9.  *   
  10.  * @author Sarin  
  11.  *   
  12.  */  
  13. public class XMLUtil {   
  14.     private Document document = null;   
  15.   
  16.     public Document getDocument() {   
  17.         return document;   
  18.     }   
  19.     /**  
  20.      * 构造方法,初始化Document  
  21.      */  
  22.     public XMLUtil() {   
  23.         document = DocumentHelper.createDocument();   
  24.     }   
  25.     /**  
  26.      * 生成根节点  
  27.      *   
  28.      * @param rootName  
  29.      * @return  
  30.      */  
  31.     public Element addRoot(String rootName) {   
  32.         Element root = document.addElement(rootName);   
  33.         return root;   
  34.     }   
  35.     /**  
  36.      * 生成节点  
  37.      *   
  38.      * @param parentElement  
  39.      * @param elementName  
  40.      * @return  
  41.      */  
  42.     public Element addNode(Element parentElement, String elementName) {   
  43.         Element node = parentElement.addElement(elementName);   
  44.         return node;   
  45.     }   
  46.     /**  
  47.      * 为节点增加一个属性  
  48.      *   
  49.      * @param thisElement  
  50.      * @param attributeName  
  51.      * @param attributeValue  
  52.      */  
  53.     public void addAttribute(Element thisElement, String attributeName,   
  54.             String attributeValue) {   
  55.         thisElement.addAttribute(attributeName, attributeValue);   
  56.     }   
  57.     /**  
  58.      * 为节点增加多个属性  
  59.      *   
  60.      * @param thisElement  
  61.      * @param attributeNames  
  62.      * @param attributeValues  
  63.      */  
  64.     public void addAttributes(Element thisElement, String[] attributeNames, String[] attributeValues) {   
  65.         for (int i = 0; i < attributeNames.length; i++) {   
  66.             thisElement.addAttribute(attributeNames[i], attributeValues[i]);   
  67.         }   
  68.     }   
  69.     /**  
  70.      * 增加节点的值  
  71.      *   
  72.      * @param thisElement  
  73.      * @param text  
  74.      */  
  75.     public void addText(Element thisElement, String text) {   
  76.         thisElement.addText(text);   
  77.     }   
  78.     /**  
  79.      * 获取最终的XML  
  80.      *   
  81.      * @return  
  82.      * @throws IOException  
  83.      */  
  84.     public String getXML() {   
  85.         return document.asXML().substring(39);   
  86.     }   
  87. }  
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的格式。取自官方网站的一个示例:

Xml代码 应用Fusion Charts制作报表(dom4j生成XML)
  1. <graph  yAxisName='Sales Figure'  caption='Top 5 Sales Person'  numberPrefix='$' decimalPrecision='1'  divlinedecimalPrecision='0' limitsdecimalPrecision='0'>  
  2.         <set name='Alex' value='25000' color='AFD8F8'/>    
  3. <set name='Mark' value='35000' color='F6BD0F'/>  
  4. <set name='David' value='42300' color='8BBA00'/>  
  5. <set name='Graham' value='35300' color='FF8E46'/>  
  6. <set name='John' value='31300' color='008E8E'/>  
  7. </graph>  
<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框架来处理请求。

Java代码 应用Fusion Charts制作报表(dom4j生成XML)
  1. package org.xxx.app.action;   
  2.   
  3. import java.util.HashMap;   
  4. import java.util.List;   
  5. import java.util.Map;   
  6. import org.dom4j.Element;   
  7. import org.xxx.core.util.XMLUtil;   
  8.   
  9. public class ChartAction extends BaseAction {   
  10.     private String xmlStr;   
  11.   
  12.     public String getXmlStr() {   
  13.         return xmlStr;   
  14.     }   
  15.     public String chart() throws Exception {   
  16.         XMLUtil xml = new XMLUtil();   
  17.         Element graph = xml.addRoot("graph");   
  18.         xml.addAttribute(graph, "caption""访问统计");   
  19.         xml.addAttribute(graph, "subCaption""浏览器类型统计");   
  20.         xml.addAttribute(graph, "basefontsize""12");   
  21.         xml.addAttribute(graph, "xAxisName""浏览器类型");   
  22.         xml.addAttribute(graph, "decimalPrecision""0");// 小数精确度,0为精确到个位   
  23.         xml.addAttribute(graph, "showValues""0");// 在报表上不显示数值   
  24.         List browserList = getServMgr().getChartService().getStatsByType("browser");   
  25.         for (int i = 0; i < browserList.size(); i++) {   
  26.             Map item = (HashMap) browserList.get(i);   
  27.             Element set = xml.addNode(graph, "set");   
  28.             set.addAttribute("name", (String) item.get("statVar"));   
  29.             set.addAttribute("value", item.get("statCount").toString());   
  30.             set.addAttribute("color", Integer.toHexString(   
  31.                     (int) (Math.random() * 255 * 255 * 255)).toUpperCase());   
  32.         }   
  33.         xmlStr = xml.getXML();   
  34.         return "chart";   
  35.     }   
  36. }  
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来进行,方法如下:

Java代码 应用Fusion Charts制作报表(dom4j生成XML)
  1. private static final String SQL_GET_STATS = "select statVar,statCount from stats where statType=?";   
  2. public List getStatsByType(String type) {   
  3.     return jt.queryForList(SQL_GET_STATS, new Object[] { type });   
	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这篇,因为相同的演示,就用了同一个表结构。获取到数据遍历之后,就要在页面进行输出显示了,也很简单,页面如下:

Html代码 应用Fusion Charts制作报表(dom4j生成XML)
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5. <title>Fusion Chart Test</title>  
  6. <script type="text/javascript" src="${base}/js/FusionCharts.js"></script>  
  7. </head>  
  8. <body>  
  9. <div id="chartDiv"></div>  
  10. <script type="text/javascript">  
  11.     var chart = new FusionCharts("${base}/charts/FCF_Column3D.swf", "0", "800", "600");   
  12.     chart.setDataXML('${xmlStr}');   
  13.     chart.render('chartDiv');   
  14.     </script>    
  15.   
  16. </body>  
  17. </html>  
<!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即可。下面来看看生成的报表,非常的不错。
应用Fusion Charts制作报表(dom4j生成XML)
    希望对使用者有用,欢迎交流。