• 纳税服务系统【统计图Fusionchart】


    需求

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

    统计:根据年度将相应年度的每个月的投诉数进行统计,并以图表的形式展示在页面中;在页面中可以选择查看当前年度及其前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("统计投诉数失败!");
                    }
                });
            }

  • 相关阅读:
    一些有用的正则
    UNION ALL合表查询
    远程桌面连接:出现身份验证错误,要求的函数不受支持,可能是由于CredSSP加密Oracle修正的解决方法
    Ubuntu20.04安装、配置openvas
    awvs13破解安装、批量扫描脚本
    剑指05题
    时间复杂度o(1), o(n), o(logn), o(nlogn)
    Intellij IDEA 注释模板
    Explain详解
    Hibernate中get()和load()的区别
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7202902.html
Copyright © 2020-2023  润新知