使用JfreeChart生成统计图
在项目中遇到按年度/月份销量生成柱装图的要求,记录下来。 这里有很详细的例子
做的过程中遇到了两个问题
- 当所有的数据为0的时候,会在图片的中心显示一条横线
解决办法:rangeAxis.setLowerBound(0.0);
- 当按月份查询时候X轴的数据过多导致x轴的下标显示不出来
解决办法:domainAxis.setMaximumCategoryLabelWidthRatio(xx);//xx的值稍微设大一点就好了
效果图:
- 依赖jar包:jcommon-1.0.23.jar jfreechart-1.0.19.jar
工具类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package com.hangage.util; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.text.DecimalFormat; 6 import org.jfree.chart.ChartFactory; 7 import org.jfree.chart.JFreeChart; 8 import org.jfree.chart.axis.CategoryAxis; 9 import org.jfree.chart.axis.NumberAxis; 10 import org.jfree.chart.axis.ValueAxis; 11 import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; 12 import org.jfree.chart.plot.CategoryPlot; 13 import org.jfree.chart.plot.PlotOrientation; 14 import org.jfree.chart.renderer.category.BarRenderer; 15 import org.jfree.data.category.CategoryDataset; 16 import org.jfree.data.general.DatasetUtilities; 17 18 19 public class ChartUtil { 20 21 private static ChartUtil charUtil=null; 22 public static ChartUtil getInstance(){ 23 if(charUtil==null){ 24 return new ChartUtil(); 25 }else{ 26 return charUtil; 27 } 28 } 29 30 /** 31 *生成柱状统计图 32 * @param srcData 33 * @param imgName 34 * @param xData 35 * @param xMark 36 * @param yMark 37 * @param yFoamt 38 * @return JFreeChart 39 */ 40 public JFreeChart makeBarChart(double[] srcData,String imgName,String[] xData,String xMark,String yMark,String yFoamt) { 41 double[][] data = new double[][]{srcData }; 42 String[] rowKeys = {imgName}; 43 44 CategoryDataset dataset = getBarData(data, rowKeys, xData); 45 46 return createBarChart(dataset, xMark, yMark, null, yFoamt); 47 } 48 49 // 柱状图,折线图 数据集 50 private CategoryDataset getBarData(double[][] data, String[] rowKeys, 51 String[] columnKeys) { 52 return DatasetUtilities.createCategoryDataset(rowKeys, columnKeys, data); 53 54 } 55 56 57 /** 58 * 柱状图 59 * 60 *@param dataset 数据集 61 * @param xName x轴的说明(如种类,时间等) 62 * @param yName y轴的说明(如速度,时间等) 63 * @param chartTitle 图标题 64 * @param yFormat y坐标数字显示格式(#0.00) 65 * @return 66 */ 67 private JFreeChart createBarChart(CategoryDataset dataset, String xName, 68 String yName, String chartTitle,String yFormat) { 69 JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题 70 xName, // 目录轴的显示标签 71 yName, // 数值轴的显示标签 72 dataset, // 数据集 73 PlotOrientation.VERTICAL, // 图表方向:水平、垂直 74 true, // 是否显示图例(对于简单的柱状图必须是false) 75 false, // 是否生成工具 76 false // 是否生成URL链接 77 ); 78 Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12); 79 80 /* 81 * VALUE_TEXT_ANTIALIAS_OFF表示将文字的抗锯齿关闭, 82 * 使用的关闭抗锯齿后,字体尽量选择12到14号的宋体字,这样文字最清晰好看 83 */ 84 // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); 85 chart.setTextAntiAlias(false); 86 chart.setBackgroundPaint(Color.white); 87 // create plot 88 CategoryPlot plot = chart.getCategoryPlot(); 89 // 设置横虚线可见 90 plot.setRangeGridlinesVisible(true); 91 // 虚线色彩 92 plot.setRangeGridlinePaint(Color.gray); 93 94 // 数据轴精度 95 NumberAxis vn = (NumberAxis) plot.getRangeAxis(); 96 vn.setStandardTickUnits(NumberAxis.createIntegerTickUnits());//控制y轴不会因为数据太小导致出现好几个0.00 97 // vn.setAutoRangeIncludesZero(true); 98 DecimalFormat df = new DecimalFormat(yFormat); 99 vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式 100 // x轴设置 101 102 CategoryAxis domainAxis = plot.getDomainAxis(); 103 domainAxis.setLabelFont(labelFont);// 轴标题 104 105 domainAxis.setTickLabelFont(labelFont);// 轴数值 106 107 chart.getLegend().setItemFont(labelFont);//底部 108 // Lable(Math.PI/3.0)度倾斜 109 // domainAxis.setCategoryLabelPositions(CategoryLabelPositions 110 // .createUpRotationLabelPositions(Math.PI / 3.0)); 111 112 domainAxis.setMaximumCategoryLabelWidthRatio(5.0f);// 横轴上的 Lable 是否完整显示 113 114 // 设置距离图片左端距离 115 domainAxis.setLowerMargin(0.02); 116 // 设置距离图片右端距离 117 domainAxis.setUpperMargin(0.02); 118 // 设置 columnKey 是否间隔显示 119 // domainAxis.setSkipCategoryLabelsToFit(true); 120 121 plot.setDomainAxis(domainAxis); 122 // 设置柱图背景色(注意,系统取色的时候要使用16位的模式来查看颜色编码,这样比较准确) 123 plot.setBackgroundPaint(new Color(255, 255, 204)); 124 125 // y轴设置 126 ValueAxis rangeAxis = plot.getRangeAxis(); 127 rangeAxis.setLabelFont(labelFont); 128 rangeAxis.setTickLabelFont(labelFont); 129 rangeAxis.setLowerBound(0.0); 130 // 设置最高的一个 Item 与图片顶端的距离 131 rangeAxis.setUpperMargin(0.15); 132 // 设置最低的一个 Item 与图片底端的距离 133 rangeAxis.setLowerMargin(0.15); 134 plot.setRangeAxis(rangeAxis); 135 136 BarRenderer renderer = new BarRenderer(); 137 // 设置柱子宽度 138 renderer.setMaximumBarWidth(0.08); 139 // 设置柱子高度 140 renderer.setMinimumBarLength(0.2); 141 // 设置柱子边框颜色 142 renderer.setBaseOutlinePaint(Color.BLACK); 143 // 设置柱子边框可见 144 renderer.setDrawBarOutline(true); 145 146 147 // // 设置柱的颜色 148 renderer.setSeriesPaint(0, new Color(204, 255, 255)); 149 renderer.setSeriesPaint(1, new Color(153, 204, 255)); 150 renderer.setSeriesPaint(2, new Color(51, 204, 204)); 151 152 // 设置每个地区所包含的平行柱的之间距离 153 renderer.setItemMargin(0.0); 154 155 // 显示每个柱的数值,并修改该数值的字体属性 156 renderer.setIncludeBaseInRange(true); 157 renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator()); 158 renderer.setBaseItemLabelsVisible(true); 159 160 plot.setRenderer(renderer); 161 // 设置柱的透明度 162 plot.setForegroundAlpha(1.0f); 163 164 return chart; 165 } 166 }
Controller
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package com.hangage.controller; 2 3 import java.util.Calendar; 4 import java.util.List; 5 6 import javax.servlet.http.HttpServletRequest; 7 import org.jfree.chart.JFreeChart; 8 import org.jfree.chart.servlet.ServletUtilities; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.stereotype.Controller; 11 import org.springframework.ui.ModelMap; 12 import org.springframework.util.StringUtils; 13 import org.springframework.web.bind.annotation.RequestMapping; 14 import org.springframework.web.servlet.ModelAndView; 15 16 import com.hangage.bean.YearCount; 17 import com.hangage.dao.BookDao; 18 import com.hangage.util.ChartUtil; 19 20 @Controller 21 public class ChartController { 22 23 @Autowired 24 private BookDao bookDao; 25 private final static String years[]={"01","02","03","04","05","06","07","08","09","10","11","12"}; 26 27 @RequestMapping("showChart.do") 28 public ModelAndView showChart(String year,String month,ModelMap model,HttpServletRequest request){ 29 int flag=getRequest(year,month); 30 ChartUtil chartUtil=ChartUtil.getInstance(); 31 JFreeChart jfreeChart=null; 32 switch (flag) { 33 case 1: 34 List<YearCount> yearCount=bookDao.getCountListByYear(year); 35 String filename=""; 36 double [] data=new double[12] ; 37 for (int i = 0; i < years.length; i++) { 38 data[i]=yearCount.get(i).getCount(); 39 } 40 41 jfreeChart=chartUtil.makeBarChart(data, year+"年销量", years, "月", "件", "#0.00"); 42 try { 43 44 filename=ServletUtilities.saveChartAsPNG(jfreeChart,900,500,request.getSession()); 45 model.put("filename", filename); 46 } catch (Exception e) { 47 48 e.printStackTrace(); 49 } 50 model.put("year", year); 51 52 break; 53 case 2: 54 Calendar calendar=Calendar.getInstance(); 55 calendar.set(Integer.valueOf(year), Integer.valueOf(month)-1, Calendar.DAY_OF_MONTH); 56 int maxDay=calendar.getActualMaximum(Calendar.DATE); 57 String parm=year+"-"+month; 58 double [] datas=new double [maxDay]; 59 String [] days=new String[maxDay]; 60 for (int i = 0; i < datas.length; i++) { 61 days[i]=addZero(i+1); 62 datas[i]=bookDao.getCountByDay(parm+"-"+addZero(i+1)); 63 } 64 65 jfreeChart=chartUtil.makeBarChart(datas, year+"年"+month+"月销量", days, "日", "件", "#0"); 66 try { 67 68 filename=ServletUtilities.saveChartAsPNG(jfreeChart,800,500,request.getSession()); 69 model.put("filename", filename); 70 } catch (Exception e) { 71 72 e.printStackTrace(); 73 } 74 model.put("year", year); 75 model.put("month", month); 76 77 break; 78 79 default: 80 break; 81 } 82 83 return new ModelAndView("showChart",model); 84 } 85 86 private int getRequest(String year,String month){ 87 if(!StringUtils.isEmpty(month)){ 88 return 2; 89 }else{ 90 return 1; 91 } 92 } 93 94 private String addZero(int num){ 95 if(num<10){ 96 return "0"+num; 97 }else{ 98 return String.valueOf(num); 99 } 100 } 101 }
SQL语句
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <select id="getCountListByYear" resultMap="yearCount"> 2 SELECT MON,SUM(CNT) AS CNT 3 FROM 4 ( 5 SELECT 6 SUBSTRING(CREATE_TIME, 6, 2) AS MON, 7 COUNT(ID) AS CNT 8 FROM BOOK 9 WHERE SUBSTRING(CREATE_TIME, 1, 4)=#{year} 10 GROUP BY SUBSTRING(CREATE_TIME, 6, 2) 11 UNION 12 SELECT '01'AS MON, '0' AS CNT 13 UNION 14 SELECT '02'AS MON, '0' AS CNT 15 UNION 16 SELECT '03'AS MON, '0' AS CNT 17 UNION 18 SELECT '04'AS MON, '0' AS CNT 19 UNION 20 SELECT '05'AS MON, '0' AS CNT 21 UNION 22 SELECT '06'AS MON, '0' AS CNT 23 UNION 24 SELECT '07'AS MON, '0' AS CNT 25 UNION 26 SELECT '08'AS MON, '0' AS CNT 27 UNION 28 SELECT '09'AS MON, '0' AS CNT 29 UNION 30 SELECT '10'AS MON, '0' AS CNT 31 UNION 32 SELECT '11'AS MON, '0' AS CNT 33 UNION 34 SELECT '12'AS MON ,'0' AS CNT 35 )AS TEMP 36 GROUP BY TEMP.MON 37 ORDER BY TEMP.MON 38 </select> 39 40 41 <select id="getCountByDay" parameterType="java.lang.String" resultType="java.lang.Integer" > 42 SELECT 43 COUNT(ID) AS CNT 44 FROM BOOK 45 WHERE SUBSTRING(CREATE_TIME, 1, 10)=#{parm} 46 47 </select>
- JSP
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@ page import="org.jfree.data.general.DefaultPieDataset,org.jfree.chart.ChartFactory 4 ,org.jfree.chart.JFreeChart,org.jfree.chart.servlet.DisplayChart" %> 5 6 <% 7 String path=request.getServletContext().getContextPath(); 8 String fileName=(String)request.getAttribute("filename"); 9 String url = request.getContextPath() + "/DisplayChart?filename=" + fileName; 10 %> 11 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 12 <html> 13 <head> 14 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 15 <title>Insert title here </title> 16 </head> 17 <body> 18 <div> 19 <form action="<%=path %>/showChart.do" method="post"> 20 选择年份:<select name="year"> 21 <option value="2013" ${year=='2013'? 'selected':'' }>2013年</option> 22 <option value="2014" ${year=='2014'? 'selected':'' }>2014年</option> 23 <option value="2015" ${year=='2015'? 'selected':'' }>2015年</option> 24 </select> 25 <input type="submit" value="查询"> 26 </form> 27 </div> 28 <div align="center"> 29 <img src="<%=url%>"> 30 </div> 31 </body> 32 </html>
在jsp页面中从model取得JFreeChart生成图片的名字,通过JFreeChart提供的工具DisplayChart取得生成临时图片的路径,要使用DisplayChart这个Servlet提供的service方法 必须在web.xml中做如下配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <servlet> 2 <servlet-name>DisplayChart</servlet-name> 3 <servlet-class> 4 org.jfree.chart.servlet.DisplayChart 5 </servlet-class> 6 </servlet> 7 <servlet-mapping> 8 <servlet-name>DisplayChart</servlet-name> 9 <url-pattern>/DisplayChart</url-pattern> 10 </servlet-mapping>