纳税服务系统七(投诉管理模块)【显示投诉信息、处理回复、我要投诉、Quartz自动受理、统计图FusionCharts】(四)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 接下来,就是来开发我们的投诉受理管理模块了…..我们来看看原型图与需求吧

统计图Fusionchart

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

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

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

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

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


FusionCharts使用

FusionCharts安装

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

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

引入Demo

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

需求分析

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

微信图片_20220412001845.png

根据不同的年份,就显示出不同的统计图数据…..这明显就用到了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>

下面是我们的效果:

微信图片_20220412001925.png


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

微信图片_20220412001929.jpg

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

<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)

微信图片_20220412001936.png


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

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

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

微信图片_20220412001950.png

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;

微信图片_20220412001954.png

上面的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("统计投诉数失败!");
                }
            });
        }

总结

  • 在条件查询的时候,尽量把like字段的数据放在后边,以提高我们的查询性能!
  • 使用DateUtils可以把字符串解析成对象
  • 只要页面上的数据没有的话,要么是通过域对象把数据带过去的。要么就在请求的时候我们手动设置的。
  • 在hbm配置文件中指定我们set集合的顺序:set集合也可以按照一定的顺序来展示
  • 在Struts2指定name为root的话,我们可以指定哪个属性是返回JSON格式的。很多情况下,我们并不需要把所有的属性都返回JSON格式的。
  • 得到更好的用户体验,我们可以先提示用户操作成功了,然后把页面刷新一下,最后关闭该页面。
  • 以一定频率来指定某段代码的话,我们第一时间是Timer对象,可是我们现在是每个月的前一天来执行某一段代码,现在就有点难度了。
  • 因此,我们想要了有什么其他的组件帮我们来完成这个任务。于是有了quartz
  • 我们使用它只要配置三样东西
  • 任务详情
  • 任务执行周期[频率]
  • 任务调度工厂
  • 我们要是使用到日历的话,我们应该使用Calendar这个日历类
  • 由于我们展示的是近五年的数据,我们不能写死的。因此我们可以在后台使用Calendar类来找到进五年的年份,返回给页面做展示。
  • 在Demo中我们就可以发现需要的JOSN类型是数组加每个对象。对应我们Java中的集合+Map。
  • 我们需要统计每个月的投诉数,第一反应想到的是分组函数。但是,分组函数仅仅会把我们存在投诉的月份展示出来。要想把整年的月份都展示出来,此时就用到我们的外连接查询了!
  • 但还有一个条件:如果还没到的月份我们应该设置为“”,而已经到的月份,如果没有投诉数,就设置为0
  • 因此,我们拿到dao返回的数据,还要我们进行对日历的判断。
目录
相关文章
|
7月前
|
存储 数据库 数据安全/隐私保护
针对纸质检验记录表单电子化搭建
【2月更文挑战第2天】针对纸质检验记录表单电子化搭建
47 2
|
5月前
|
前端开发
会员系统02--,后台管理系统,包含网站运营,统计分析,用户中心,财务管理,资金明细,系统管理,参数配置,后台管理系统可以观看配置资料,广告位的相关资料,客服工单最主要是客户反馈给我们的问题,登录统计
会员系统02--,后台管理系统,包含网站运营,统计分析,用户中心,财务管理,资金明细,系统管理,参数配置,后台管理系统可以观看配置资料,广告位的相关资料,客服工单最主要是客户反馈给我们的问题,登录统计
|
6月前
三分钟教会你!客户扫码预约活动后,如何快速核销记录?
我们可以通过“提交成功页设置获取核销凭证”,结合“标记处理进度”功能,对活动预约记录进行手动核销。
|
7月前
|
Java 数据库 数据安全/隐私保护
基于Servlet+Jsp实现的酒店客房预定管理系统分前后台
基于Servlet+Jsp实现的酒店客房预定管理系统分前后台
|
7月前
|
数据可视化 BI API
无纸化登记二维码应用方案:扫码填写表单,信息收集无纸化
日常生活中的申请表、签到表、报名表等纸质表格,收集到的信息常常不规范,可以搭建用于信息收集的二维码应用,通过扫码填写电子表单的方式,实现核销、业务申请、内部审批等场景的无纸化登记,并能将填写的信息导出为Excel表格存档。
214 0
|
安全 前端开发 Java
【开题报告】基于SpringBoot的演唱会门票在线预定系统的设计与实现
【开题报告】基于SpringBoot的演唱会门票在线预定系统的设计与实现
439 0
|
机器学习/深度学习 算法 数据挖掘
日内交易套利系统程式开发编写规则解析
日内交易套利系统程式开发编写规则解析
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(一)
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(一)
181 0
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(一)
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(二)
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(二)
145 0
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(二)
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(三)
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(三)
125 0
程序人生 - 征信报告怎么查?社保证明如何拉?无房证明去哪开?最新查询指引,欢迎收藏(三)