最近在做报表,但客户要求加上一些图表显得更为生动,于是我就学习了下jfreechart发现也挺简单的。下面就记录下我在Struts2的环境下是如何生成一些饼图、柱状图和折线图的~~~
首先struts2若要支持jfreechart是需要引入struts2-jfreechart-plugin-2.x.x.jar包的,正如struts2支持ireport需要引入struts2-jasperreport-plungin-2.x..x.jar包一样。
最核心的struts.xml的配置必不可少(以饼图为例,其他原理类似):
<package name="chartPackage" extends="jfreechart-default" namespace="/"> <action name="xxxChart" class="com.xx.xx.XXXChartAction"> <result name="pie" type="chart"> <param name="width">450</param> <param name="height">350</param> </result> </action> </package>
注意到extends="jfreechart-default"了没,这是struts2配置支持JFreeChart的核心所在。
当然我们要在XXXChartAction里这样写了:
public String pie() throws Exception { //得到List<Map<String, String>> list过程略 JFreeChart chart = JFreeChartService.createPieChart(list); this.setChart(chart); return "pie"; }
其中JFreeChartService这个类是专门用于根据数据集生成不同chart的工具类。
不妨看下生成饼图的方法:
/** * 根据数据源绘制3D饼图 * @param list * @return */ public static JFreeChart createPieChart(List<Map<String, Object>> list) { int size = list.size(); DefaultPieDataset dpd = new DefaultPieDataset(); String[] appIds = new String[size]; long[] totalCnts = new long[size]; for(int i=0; i<size; i++) { //。。。。。。。。。。 dpd.setValue(appId, totalSum);//appId为饼图的每一块的key, totalSum为该块对应的值 appIds[i] = appId; totalCnts[i] = totalSum; } //源码:public static JFreeChart createPieChart3D(String title, PieDataset dataset, boolean legend, boolean tooltips, boolean urls) JFreeChart chart = ChartFactory.createPieChart3D("交易量饼图", dpd, true, true, false); //字体设置 chart.setTitle(new TextTitle("交易量饼图", new Font("黑体", Font.ITALIC , 25))); Font font = new Font("宋体", Font.ITALIC, 12); PiePlot plot = (PiePlot) chart.getPlot(); // chart.getTitle().setFont(font); plot.setLabelFont(font); chart.getLegend().setItemFont(font); return chart; }
同理,生成柱状图和折线图大同小异!
柱状图:
/** * 根据数据源绘制3D柱状图 * @param list * @return */ public static JFreeChart createBarChart(List<Map<String, Object>> list) { int size = list.size(); String[] appIds = new String[size]; double[] ratios = new double[size]; for(int i=0; i<size; i++) { Map<String, Object> map = list.get(i); //。。。。。。。。。。 } String[] rowKeys = new String[]{"成功率"}; double[][] data = new double[1][size]; data[0] = ratios; //源码:public static CategoryDataset createCategoryDataset(Comparable rowKeys[], Comparable columnKeys[], double data[][]) CategoryDataset dataset = DatasetUtilities.createCategoryDataset(rowKeys, appIds, data); //源码: public static JFreeChart createBarChart3D(String title, String categoryAxisLabel, String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) // JFreeChart chart = ChartFactory.createBarChart("成功率柱状图", "系统", "成功率", dataset, PlotOrientation.VERTICAL, false, false, false); JFreeChart chart = ChartFactory.createLineChart3D("成功率柱状图", "系统", "成功率", dataset, PlotOrientation.VERTICAL, false, false, false); //重新设置图标标题,改变字体 chart.setTitle(new TextTitle("成功率柱状图", new Font("黑体", Font.ITALIC , 22))); CategoryPlot plot = (CategoryPlot)chart.getPlot(); //取得横轴 CategoryAxis categoryAxis = plot.getDomainAxis(); //设置横轴显示标签的字体 categoryAxis.setLabelFont(new Font("宋体" , Font.BOLD , 18)); //分类标签以45度角倾斜 categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); categoryAxis.setTickLabelFont(new Font("宋体" , Font.ITALIC , 15)); CategoryAxis domainAxis = plot.getDomainAxis(); //设置距离图片左端距离 domainAxis.setLowerMargin(0.1); //设置距离图片右端距离 domainAxis.setUpperMargin(0.1); BarRenderer3D renderer = new BarRenderer3D(); renderer.setItemMargin(0.1);//组内柱子间隔为组宽的10% renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());//显示柱子上的数值 renderer.setBaseItemLabelsVisible(true); plot.setRenderer(renderer);//使用我们设计的效果 //取得纵轴 NumberAxis numberAxis = (NumberAxis)plot.getRangeAxis(); //设置纵轴显示标签的字体 numberAxis.setLabelFont(new Font("宋体" , Font.BOLD , 18)); // 设置最高的一个 Item 与图片顶端的距离 numberAxis.setUpperMargin(0.15); // // 设置最低的一个 Item 与图片底端的距离 // numberAxis.setLowerMargin(0.15); plot.setRangeAxis(numberAxis); // Font font00 = new Font("宋体",Font.BOLD,18); // LegendTitle legend = chart.getLegend(); // legend.setItemFont(font00);//设置注释字体 return chart; }
源码说明:
public static CategoryDataset createCategoryDataset(Comparable rowKeys[], Comparable columnKeys[], double data[][])
其中,rowKeys为柱状图上显示的指标字符串的数组(只显示一个指标的时候就是一个数组长度为1的数组呀);columnKeys为x轴上的针对每一个指标的一批比较对象,data为一个二维数组,外维是指标下标,内维是每一对象在某一指标上的取值
打个比方,有A.B.C.D.E 5个对象,在柱状图上要绘制他们在 甲、乙两个指标上的值——则rowKeys为甲和乙组成的数组,columnKeys为A-E这5个对象,一个data[2][5]的数组则描述了这5个对象分别在这2个指标上的取值~~~
折线图:
/** * 根据数据源绘制3D折线(走势)图 * @param list * @return */ public static JFreeChart createLineChart(List<Map<String, Object>> list) { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for(Map<String, Object> map : list) { //源码:public void setValue(Number value, Comparable rowKey, Comparable columnKey); dataset.setValue((Long.valueOf((String)map.get("total_sum"))), (String) map.get("app_id"), map.get("snap_date").toString()); } //如果把createLineChart改为createLineChart3D就变为了3D效果的折线图 JFreeChart chart = ChartFactory.createLineChart3D("交易量走势图", "时间", "总交易量", dataset, PlotOrientation.VERTICAL, // 绘制方向 true, // 显示图例 true, // 采用标准生成器 false // 是否生成超链接 ); chart.getTitle().setFont(new Font("黑体", Font.ITALIC , 22)); // 设置标题字体 chart.getLegend().setItemLabelPadding(new RectangleInsets(2,2,2,2)); chart.getLegend().setItemFont(new Font("宋体" , Font.BOLD , 18));// 设置图例类别字体 chart.setBackgroundPaint(new Color(Integer.parseInt(("C0E46A"), 16)));// 设置背景色 //获取绘图区对象 CategoryPlot plot = chart.getCategoryPlot(); plot.setBackgroundPaint(Color.LIGHT_GRAY); // 设置绘图区背景色 plot.setRangeGridlinePaint(Color.WHITE); // 设置水平方向背景线颜色 plot.setRangeGridlinesVisible(true);// 设置是否显示水平方向背景线,默认值为true plot.setDomainGridlinePaint(Color.WHITE); // 设置垂直方向背景线颜色 plot.setDomainGridlinesVisible(true); // 设置是否显示垂直方向背景线,默认值为false CategoryAxis domainAxis = plot.getDomainAxis(); domainAxis.setLabelFont(new Font("宋体" , Font.BOLD , 18)); // 设置横轴字体 domainAxis.setTickLabelFont(new Font("宋体" , Font.ITALIC , 15));// 设置坐标轴标尺值字体 domainAxis.setLowerMargin(0.01);// 左边距 边框距离 domainAxis.setUpperMargin(0.06);// 右边距 边框距离,防止最后边的一个数据靠近了坐标轴。 domainAxis.setMaximumCategoryLabelLines(2); domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45);//横轴上的Label 45度倾斜 ValueAxis rangeAxis = plot.getRangeAxis(); rangeAxis.setLabelFont(new Font("宋体" , Font.BOLD , 18)); rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());//Y轴显示整数 rangeAxis.setAutoRangeMinimumSize(1); //最小跨度 rangeAxis.setUpperMargin(0.18);//上边距,防止最大的一个数据靠近了坐标轴。 rangeAxis.setLowerBound(0); //最小值显示0 rangeAxis.setAutoRange(false); //不自动分配Y轴数据 rangeAxis.setTickMarkStroke(new BasicStroke(1.6f)); // 设置坐标标记大小 rangeAxis.setTickMarkPaint(Color.BLACK); // 设置坐标标记颜色 // 获取折线对象 LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer(); BasicStroke realLine = new BasicStroke(1.8f); // 设置实线 // 设置虚线 // float dashes[] = { 5.0f }; // BasicStroke brokenLine = new BasicStroke(2.2f, // 线条粗细 // BasicStroke.CAP_ROUND, // 端点风格 // BasicStroke.JOIN_ROUND, // 折点风格 // 8f, dashes, 0.6f); // for (int i = 0; i < dataset.getRowCount(); i++) { // if (i % 2 == 0) // renderer.setSeriesStroke(i, realLine); // 利用实线绘制 // else // renderer.setSeriesStroke(i, brokenLine); // 利用虚线绘制 // } // plot.setNoDataMessage("无对应的数据,请重新查询。"); // plot.setNoDataMessageFont(titleFont);//字体的大小 // plot.setNoDataMessagePaint(Color.RED);//字体颜色 return chart; }
代码说明:
dataset.setValue((Long.valueOf((String)map.get("total_sum"))),(String) map.get("app_id"), map.get("snap_date").toString());对应源码:
public void setValue(Number value, Comparable rowKey, Comparable columnKey)其中value为折线图上每一个点对应的值,Comparable rowKey为Y轴方向的比较对象, Comparable columnKey则是X轴方向上点的对象。举一个小例子,有A/B/C/D/E 5个对象,要在折线图上反映他们10个时间点的取值情况,则这10个时间点为columnKey, 这5个对象即为rowKey。
一般而言,反映在sql查询得出数据集中,columnKey和rowKey为group by的字段。
在前台的写法很简单,即(以刚才配置了的饼图为例):
<img src="xxxChart/pie?参数="+xxx />
即可查看到效果。
注:后台代码还需要JFreeChart的相关jar包支持:jcommon-1.x.x.jar和jfreechart-1.x.x.jar
以下效果仅供参考!
柱状图: