完整版见https://jadyer.github.io/ 这里使用的是jfreechart-1.0.9和struts-2.0.11 首先是JSP页面 <%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <h2>请选择您喜欢的运动项目</h2> <s:form action="viewResult"> <s:checkbox name="interest" label="篮球" fieldValue="basketball"/> <s:checkbox name="interest" label="气球" fieldValue="balloon"/> <s:checkbox name="interest" label="排球" fieldValue="volleyball"/> <s:checkbox name="interest" label="足球" fieldValue="football"/> <s:submit value="提交"/> </s:form> 然后是用到的struts.xml文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="struts2" extends="struts-default, jfreechart-default"> <action name="viewResult" class="com.jadyer.action.ViewResultAction"> <result type="chart"> <param name="height">600</param> <param name="width">800</param> </result> </action> </package> </struts> <!-- *******************【概述Struts2的插件机制】******************************************* --> <!-- Struts2同Eclipse一样也提供了插件集成机制,它的插件集成机制与Struts1.X的Plugin是有较大区别的 --> <!-- 而且它的配置方式非常非常简单,而且具有通用性。目前为止适合于Struts2的插件大概有40多种 --> <!-- 任何插件跟Struts2整合的方式与JFreeChart跟Struts2整合的方式都是非常非常类似的,没有太大的差异 --> <!-- 在Struts2中使用JFreeChart插件时,一般需要以下三个JAR文件 --> <!-- struts2-jfreechart-plugin-2.0.11.jar和jfreechart-1.0.9.jar和jcommon-1.0.12.jar文件 --> <!-- *******************【JFreeChart插件的一个BUG】***************************************** --> <!-- 根据Struts2网站上对使用JFreeChart插件的说明中得知,这里的result的type应该定义成chart --> <!-- 但是当前package继承于struts-default包,而struts-default包中并没有名为chart的result-type --> <!-- 那么如果我们将result的type定义成chart的话,由于Struts2不认识该类型,所以服务器启动时就会报错 --> <!-- 实际上该类型是被定义在struts2-jfreechart-plugin-2.0.11.jar中的struts-plugin.xml里面了 --> <!-- 尽管插件被加载进来了,但Struts2不会把插件里面的result-type自动与我们定义的result的tpye关联 --> <!-- 有一个办法可以解决问题,那就是让我们的包继承jfreechart-default,而不再继承struts-default包 --> <!-- 这个时候就相当于我们把jfreechart-defaul包中的result-type也继承过来了,所以就可以使用了 --> <!-- 但随之而来的还有个问题,如果直接继承jfreechart-defaul包的话,就等于不再继承struts-default了 --> <!-- 那么struts-default里面的拦截器和其它的结果类型就都无法使用了,最后就会导致整个应用的瘫痪 --> <!-- *******************【修改JFreeChart插件并重新打包】**************************************** --> <!-- 唯一办法就是令jfreechart-default继承struts-default包,然后我们再继承jfreechart-default --> <!-- 这样一来,也就相当于我们间接的继承了struts-default包。这就是Struts2的包继承所带来的好处 --> <!-- 这也算是struts2-jfreechart-plugin-2.0.11.jar插件的一个很小的BUG。这时就需要我们手工修改它 --> <!-- 首先解压缩插件,在struts-plugin.xml中增添jfreechart-default继承struts-default包的代码 --> <!-- 注意:在将文件重新打包的时候,应该在struts2-jfreechart-plugin-2.0.11文件夹里面打包 --> <!-- 步骤:在命令提示符中进入到F:/Javalib/Struts2/struts2-jfreechart-plugin-2.0.11>里面 --> <!-- 命令:使用【jar cvf struts2-jfreechart-plugin-2.0.11.jar -C *】命令打包文件 --> <!-- 当我们将result的type指定为chart之后,就没有必要再去指定视图了 --> <!-- 因为chart本身就是一种输出,没有必要再去指定JSP了,它会自动为我们生成出来 --> <!-- *******************【继承多个包】******************************************************** --> <!-- Struts2的包支持多个继承,所以我们也可以不必对其重新打包 --> <!-- 也就是说<package name="struts2" extends="struts-default, jfreechart-default">即可 --> <!-- ************************************************************************************** --> 最后是核心的Action处理类 package com.jadyer.action; import java.awt.Font; import java.util.List; import java.util.Map; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.title.TextTitle; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; /** * 使用JFreeChart绘制用户投票结果的柱状3D图 */ public class ViewResultAction extends ActionSupport { private static final long serialVersionUID = 1935592746823978475L; private List<String> interest; //如果想要使用JFreeChart插件的话,这里就必须声明一个private JFreeChart chart //而且声明的属性名必须是chart,返回值也必须是JFreeChart类型,这是暂时被硬性规定的 //也就是说,这个chart必须硬编码到我们的程序里面,即HardCoded。这也是当前不太完善的地方 //我们只需生成JFreeChart对象即可,具体输出到视图或响应里面,是由JFreeChart插件来完成的 private JFreeChart chart; /** * 将用户选择的运动项目的票数加壹 * @see 在真正开发中,绝对绝对不能将这样的方法放到Action中 * @see 一定要放在相应的Model里面,因为这是一个业务处理方法 */ private void increaseResult(List<String> list) { ActionContext context = ActionContext.getContext(); Map map = context.getApplication(); //使用Application模拟数据库。只要不关闭浏览器,数据一直存在 for (String str : list) { if (null == map.get(str)) { //如果该选项被第一次投票,就将当前选项的票数设为壹 map.put(str, 1); //JDK5.0提供的自动装箱 } else { //如果该选项已经被投过票了,就将它的票数加壹 map.put(str, (Integer) map.get(str) + 1); //由于没有用到泛型,故须强制类型转换成Integer。此即不使用泛型的弊端 } } } /** * 创建柱状图数据集 * @see 这也是一个业务处理方法,实际开发中同样也不要放到Action里面 */ private CategoryDataset getDataset() { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); //将当前的投票结果反映到ServletContext中,表示数据已更新为最新票数了 //这一步执行完毕之后,就会将最新的投票结果的数据放到Application中了 this.increaseResult(this.getInterest()); ActionContext context = ActionContext.getContext(); Map map = context.getApplication(); //得到Application之后,将里面的数据放到数据集中 dataset.setValue((Integer) map.get("basketball"), "basketball", "篮球"); dataset.setValue((Integer) map.get("balloon"), "balloon", "气球"); dataset.setValue((Integer) map.get("volleyball"), "volleyball", "排球"); dataset.setValue((Integer) map.get("football"), "football", "足球"); return dataset; } /** * JFreeChart插件对象将自动调用该方法 * @return 返回已经生成好的JFreeChart类型的chart对象 * @see 这里JFreeChart对象的生成依然需要我们手工来完成,这一点实际上是不太好的 * @see 也就是说Struts2对JFreeChart的整合并不是很完善的,并不是很到位,我们还需要自己编代码来生成JFreeChart对象 */ public JFreeChart getChart() { chart = ChartFactory.createBarChart3D("体育兴趣投票结果", "运动项目", "投票结果", this.getDataset(), PlotOrientation.VERTICAL, false, false, false); //重新设置标题 chart.setTitle(new TextTitle("体育兴趣投票结果柱状3D图", new Font("黑体", Font.BOLD, 28))); CategoryPlot plot = (CategoryPlot) chart.getPlot(); CategoryAxis categoryAxis = plot.getDomainAxis(); //设置水平轴字体的显示样式 categoryAxis.setLabelFont(new Font("宋体", Font.BOLD, 24)); //设置水平轴字体的倾斜角度 categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); NumberAxis numberAxis = (NumberAxis) plot.getRangeAxis(); //设置纵轴字体的显示样式 numberAxis.setLabelFont(new Font("宋体", Font.BOLD, 22)); return chart; } @Override public String execute() throws Exception { return SUCCESS; } public List<String> getInterest() { return interest; } public void setInterest(List<String> interest) { this.interest = interest; } }