需求

我们在投诉模块中还有一个功能没有实现:

统计:根据年度将相应年度的每个月的投诉数进行统计,并以图表的形式展示在页面中;在页面中可以选择查看当前年度及其前4年的投诉数。在页面中可以选择不同的年度,然后页面展示该年度的曲线统计图。

我们到目前为止是没有学过任何的统计图的工具的,那么我们要怎么解决这个功能呢???我们有另外的组件来把统计图显示出来:FusionCharts

FusionCharts 是使用javascript 实现统计图表的js组件;其官网地址:http://www.fusioncharts.com。

具体的是怎么操作的可以看官方文档,我们以项目的需求来完成对应的功能就行了。


FusionCharts使用

FusionCharts安装

首先,我们要把对应的JS文档加入到我们的项目中:

  • “fusioncharts.js”
  • “fusioncharts.charts.js”
  • 和相关主题文件复制到项目的js/fusioncharts文件夹。

引入Demo

我们只要根据修改Demo的值就可以实现出我们想要的效果了。


<!DOCTYPE HTML>
<html>
<head>
<%@include file="/common/header.jsp" %>
<title>年度投诉统计图</title>
<script type="text/javascript" src="${basePath}js/fusioncharts.js"></script>
<script type="text/javascript" src="${basePath}js/fusioncharts.charts.js"></script>
<script type="text/javascript" src="${basePath}js/themes/fusioncharts.theme.fint.js"></script>
<script>
FusionCharts.ready(function () {
var revenueChart = new FusionCharts({
"type": "column2d",
"renderAt": "chartContainer",
"width": "500",
"height": "300",
"dataFormat": "json",
"dataSource": {
"chart": {
"caption": "Monthly revenue for last year",
"subCaption": "Harry's SuperMart",
"xAxisName": "Month",
"yAxisName": "Revenues (In USD)",
"theme": "fint"
},
"data": [
{
"label": "Jan",
"value": "420000"
},
{
"label": "Feb",
"value": "810000"
},
{
"label": "Mar",
"value": "720000"
},
{
"label": "Apr",
"value": "550000"
},
{
"label": "May",
"value": "910000"
},
{
"label": "Jun",
"value": "510000"
},
{
"label": "Jul",
"value": "680000"
},
{
"label": "Aug",
"value": "620000"
},
{
"label": "Sep",
"value": "610000"
},
{
"label": "Oct",
"value": "490000"
},
{
"label": "Nov",
"value": "900000"
},
{
"label": "Dec",
"value": "730000"
}
]
}
});
revenueChart.render();
})
</script>
</head> <body>
<br>
<s:select id="year" list="{2015}" onchange="doAnnualStatistic()"></s:select>
<br>
<div id="chartContainer"></div>
</body>
</html>

需求分析

再次回到我们的需求原型图,我们看看是怎么样的:

根据不同的年份,就显示出不同的统计图数据…..这明显就用到了ajax技术。 因此可以确定下来,我们的前端就是用ajax进行交互,渲染出对应的统计图的。

我们的后端就是根据不同的年份,去获取不同的年份每个月的数据,返回给浏览器

前端分析

我们的需求是得让我们显示近5年的统计图…于是下拉框是我们近5年的….

我们虽然是可以把option中的数据写死,但是呢,如果过了一年的话,那么我们的数据是不会同步的。当我在2017年写的时候,到2018年,页面显示还是2017年的数据….所以这明显是不合理的….

要想近5年是动态产生的,就不能够把数据写死….于是我们可以在JSP页面上得到当前年的值,根据当前年就非常容易推出近5年的数据了…

于是我们又可以使用到Calendar这个日历类了…

在JSP页面得到当前年的数据,并装载到list集合中

    Calendar calendar = Calendar.getInstance();

    //得到当前年的值
int year = calendar.get(Calendar.YEAR); //把年份用一个集合装载
List yearList = new ArrayList(); //获取近5年的值
for(int i =0; i<5; i++) {
yearList.add(i, year--);
}
request.setAttribute("yearList", yearList);
request.setAttribute("year", year);

在Struts的select标签中把这个集合迭代出来


<s:select id="year" list="#request.yearList" onchange="doAnnualStatistic()"></s:select>

下面是我们的效果:


接着,我们发现FusionCharts这个组件,想要把数据显示在统计图表中,我们的JSON数据的格式是需要这样的

还有值得注意的地方是,一进入页面中需要加载当前年度的投诉统计数


<script> //页面一加载就执行方法
$(function () {
doAnnualStatistic();
}); //根据年份获取投诉数
function doAnnualStatistic() {
//获取当前年份
var $year = $("#year option:selected").val(); //一进来,如果没有选择任何的年数,就显示当前年份的
if($year=="" || $year==undefined) {
$year = "${year}";
}
//2、统计年度投诉数据并展示图表
$.ajax({
url: "${basePath}complain/complain_getAnnualStatisticData.action",
type: "post",
dataType: "json",
data: {"year",$year},
success: function (backData) {
if(backData!=null && backData!=""){
var revenueChart = new FusionCharts({
"type": "line",
"renderAt": "chartContainer",
"width": "600",
"height": "400",
"dataFormat": "json",
"dataSource": {
"chart": {
"caption": "年度统计投诉数",
"xAxisName": "月 份",
"yAxisName": "投 诉 数",
"theme": "fint"
},
"data":backData.chartData
}
});
revenueChart.render();
}
},
error:function () {
alert("统计投诉数失败!");
}
});
}
</script>

后端分析

我们的后端就是根据年份,获取对应的值,返回一个JSON格式给浏览器,那就行了…

但是呢,我们还有其他的细节需要考虑:今年是2017年7月,但是在查询年度投诉数是要把整个年的信息查询出来,8-12月的投诉数肯定是没有的。那么我们会将还没到的时间设置成“”,如果在2016年的某月是没有投诉数的,我们应该将其替换成0,而不是“”….

在action中,我们得获取到用户传递过来的年份,我们调用service、dao层的方法获取该年度对应每个月的投诉数,转换成JSON格式输出就行了。

我们知道前端需要的JSON格式是一个对象数组,最终目的就是数组:Struts2框架在最后解析的时候,会把集合解析成是数组。对象数组在java编程语言就是List集合中嵌套着Map集合。

在后端中,还有一个难点,就是我们的SQL语句该怎么写????我们要从数据库查询的是该年份每个月的投诉数….

通过该年而查询每个月,我们可以很快地想到要用到分组查询。但是还有一个问题,我们在进行分组查询的时候,如果表中是没有1月或2月等数组的话,分组查询出来的数据是没有这些月份的。而我们的统计图是需要所有月份的数据的。咋看一下,我们是需要把查询出来的数据做循环判断,得看看有没有该月份,如果没有该月份还得把数据填充进去。。还得判断该月份是不是本年度的….这样想一下就觉得麻烦了……


select month(comp_time) as '月份',count(*) '总数'
from complain
where year(comp_time)=?
group by month(comp_time)


再次回到前面分析的,如果本年度的月份还没有到,那么将该月的数据设置为“”,如果是其他年份的的月份查出的数据为null,那么我们应该把这些月份的投诉数设置为0而不是”“…..

但是呢,我们现在有一个办法,可以在查询的时候,不管该月份有没有数据,都得显示出来….这就是左外连接

于是我们自己手动生成一张拥有12个月份的数据表,跟我们的投诉表进行左外连接…


select imonth, count(comp_id)
from t_month left join complain on imonth=month(comp_time)
and year(comp_time)=2017
group by imonth
order by imonth;

上面的sql语句的查询效率是有点低的,我们改造一下,改成是子查询:


select imonth,c2
from t_month left join (select month(comp_time) c1, count(comp_id) c2 from complain where year(comp_time)=? group by month(comp_time)) t
on imonth = c1
order by imonth;

代码实现

dao层根据年份查询出每个月份的投诉数据


/**
*
* @param year 根据年获取数据
* @return 返回的是一个列表数组
*/
@Override
public List<Object[]> getAnnualStatisticByYear(int year) { //拼接SQL语句
StringBuffer buffer = new StringBuffer();
buffer.append(" SELECT imonth,c2 ")
.append(" FROM t_month")
.append(" LEFT JOIN (SELECT month(comp_time) c1, count(comp_id) c2 FROM complain WHERE YEAR(comp_time)=? GROUP BY MONTH(comp_time)) t")
.append(" ON imonth = c1")
.append(" ORDER BY imonth;");
SQLQuery sqlQuery = getSession().createSQLQuery(buffer.toString());
sqlQuery.setParameter(0, year); List<Object[]> list = sqlQuery.list();
return list;
}

service层拿到Dao层的数据,判断是否是本年度的,如果是本年度的,那么还没有到的月份的数据就设置为”“,如果已经过的了月份,如果没有数据就设置为0.

返回一个List集合嵌套着Map集合,就可以给前台解析了。


@Override
public List getAnnualStatisticByYear(int year) { List<Object[]> annualStatisticByYear = complainDao.getAnnualStatisticByYear(year); List<Map> returnList = new ArrayList<>(); //得到本年度和本月份
int curYear = Calendar.getInstance().get(Calendar.YEAR);
//Calerdar月份从0开始,
int curMonth = Calendar.getInstance().get(Calendar.MONTH)+1; //使用Map集合装载着数据
Map<String,Object> map = null;
for (Object[] objects : annualStatisticByYear) {
map = new HashedMap();
//得到月份
Integer month = Integer.valueOf(objects[0] + "");
map.put("label", month + "月");
if (curYear == year) { //是本年度,那么看看月份是否大于本月份
if (month > curMonth) {
//将数据设置为""
map.put("value", "");
} else {
if (objects[1] != null) {
map.put("value", objects[1]);
} else {
map.put("value", "0");
}
}
}else {//不是本年度
if (objects[1] != null) {
map.put("value", objects[1]);
} else {
map.put("value", "0");
}
}
returnList.add(map);
}
return returnList;
}

action层把service层的数据封装到Map集合中,嵌套ajax解析Map集合,得到的就是对象数组了。


//返回JSON格式的数据,这里我们就直接用Struts2框架来返回对应的数据就行了。
public String getAnnualStatisticData() { //获取用户传递过来的年份
String str_year = ServletActionContext.getRequest().getParameter("year");
if (str_year != null) {
int year = Integer.valueOf(str_year);
//根据年份去获取每个月的投诉数
map.put("msg", "success");
map.put("chartData", complainServiceImpl.getAnnualStatisticByYear(year));
}
return "getAnnualStatisticData";
}

前台把年份提交给Action,解析出后台返回的数据,渲染成折线图….


function doAnnualStatistic() {
//获取当前年份
var $year = $("#year option:selected").val(); //一进来,如果没有选择任何的年数,就显示当前年份的
if($year=="" || $year==undefined) {
$year = "${year}";
}
//2、统计年度投诉数据并展示图表
$.ajax({
url: "${basePath}complain/complain_getAnnualStatisticData.action",
type: "post",
dataType: "json",
data: {"year":$year},
success: function (backData) {
if(backData!=null && backData!=""){
var revenueChart = new FusionCharts({
"type": "line",
"renderAt": "chartContainer",
"width": "600",
"height": "400",
"dataFormat": "json",
"dataSource": {
"chart": {
"caption": "年度统计投诉数",
"xAxisName": "月 份",
"yAxisName": "投 诉 数",
"theme": "fint"
},
"data":backData.chartData
}
});
revenueChart.render();
}
},
error:function () {
alert("统计投诉数失败!");
}
});
}

纳税服务系统【统计图Fusionchart】的更多相关文章

  1. 纳税服务系统【信息发布管理、Ueditor、异步信息交互】

    需求分析 我们现在来到了纳税服务系统的信息发布管理模块,首先我们跟着原型图来进行需求分析把: 一些普通的CRUD,值得一做的就是状态之间的切换了.停用和发布切换. 值得注意的是:在信息内容中,它可以带 ...

  2. 纳税服务系统【异常处理、抽取BaseAction】

    前言 本博文主要讲解在项目中异常是怎么处理的.一般我们都不会直接把后台异常信息返回给用户,用户是看不懂的.让用户看见一大串的错误代码,这是不合理的.因此我们需要对报错进行处理. 我们在开发的时候是使用 ...

  3. 纳税服务系统【自动受理,Quartz任务调度】

    需求 回到我们的需求: 自动投诉受理:在每个月月底最后一天对本月之前的投诉进行自动处理:将投诉信息的状态改为 已失效.在后台管理中不能对该类型投诉进行回复. 这个需求需求我们要怎么弄呢????要在每个 ...

  4. 纳税服务系统【抽取BaseService、条件查询】

    抽取BaseService 到目前为止,我们已经写了三个模块的开发了.我们已经抽取过了BaseAction.BaseDao,我们这次来看看我们的Service接口. UserService /** * ...

  5. 纳税服务系统【用户模块之使用POI导入excel、导出excel】

    前言 再次回到我们的用户模块上,我们发现还有两个功能没有完成: 对于将网页中的数据导入或导出到excel文件中,我们是完全没有学习过的.但是呢,在Java中操作excel是相对常用的,因此也有组件供我 ...

  6. IT服务系统组成

    软件+硬件+数据 + 运维人员 = IT服务系统 车 司机 乘客 修车 = 车模式 效率 系统 用户 业务 运维 = 信息化 效率 如果司机不会开车,没有人会修车就不会有车轮上的世界 同样没有人会运维 ...

  7. 01——Solr学习之全文检索服务系统的基础认识

    一.为什么要用Solr,Solr是个什么东西? 1.1.Solr是个开源的搜索服务器 1.2.我们用Solr主要实现搜索功能,一般的网站首页都会有一个大大的搜索框,用来搜索此网站上的商品啊什么的,如下 ...

  8. 基于Spring Boot、Spring Cloud、Docker的微服务系统架构实践

    由于最近公司业务需要,需要搭建基于Spring Cloud的微服务系统.遍访各大搜索引擎,发现国内资料少之又少,也难怪,国内Dubbo正统治着天下.但是,一个技术总有它的瓶颈,Dubbo也有它捉襟见肘 ...

  9. SpringCloud(9)使用Spring Cloud OAuth2保护微服务系统

    一.简介 OAth2是一个标准的授权协议. 在认证与授权的过程中,主要包含以下3种角色. 服务提供方 Authorization Server. 资源持有者 Resource Server. 客户端 ...

随机推荐

  1. asp.net core 运用 Redis 配置步骤

    Redis可以用来存储session或直接存储键值对 首先要有asp.net core的项目,可以是webapi 或者MVC项目,还有有本地的Redis或者在远程服务器上,具体的安装就不讲述了 以下是 ...

  2. 关于HttpSession

    HttpSession  使用Cookie有一个非常大的局限,就是如果Cookie很多,则无形的增加了客户端与服务端的数据传输量.而且由于浏览器对Cookie数量的限制,注定我们不能再Cookie中保 ...

  3. Web前端学习开篇

    首先想想自己喜欢干什么?想干什么?脑袋需要什么?什么对自己来说最重要?自己的规划? 本人数字媒体技术专业,想学Web前端开发有好长时间了,有一定的基础,所以就想进一步深入学习.谁料想,我怎么那么没有耐 ...

  4. JS中的函数、BOM和DOM操作

     一.JS中的函数 [关于注释] /** [文档注释]:开头两个*.写在函数上方,在调用函数时可以看到文档上方的描述信息. */   // 单行注释 /* 多行注释 */ 1.函数的声明及调用 (1) ...

  5. APUE 2 - 进程组(process group) 会话(session) job

    进程组(process group) 进程组顾名思义是指一个或多个进程的集合.他们通常与同一个job(可以从同一个终端接收信号)相关联.每个进程组拥有一个唯一的Process Group Id.可以使 ...

  6. JDBC的链接及封装

    导入 mysql 的jar包 jar包:可以直接拿来用,又不想我们看到源代码   sql语句 一定注意:当update,delete时 一定注意where 条件,一定要写!!! public stat ...

  7. Java自定义注解及使用

    本文通过一个简单的例子展示注解的工作原理. 1.声明注解类型 @Target(value = ElementType.METHOD) //声明该注解的运行目标: 方法 @Retention(value ...

  8. The C++ Programming Language 学习笔记 第四章 类型和声明

    1.关于main 函数中的 return 0 C99标准中,main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统).如果 main 函数的最后没有写 return ...

  9. 最近完成的AndroidStudio项目实现思路及应用技术

    主要内容: Android Studio的介绍 AS中个Gradle及Groovy介绍 AS中的依赖管理 Maven以及Nexus私库管理依赖 Gradle对变种代码的管理以及多渠道打包 eclips ...

  10. 几个常用EL表达式的用法

    转载至  http://yqsshr.blog.51cto.com/469059/131824 1,用来获取表单数据  param 和 paramValues 1.jsp 的有如下表单 <for ...