多个字段排序业务处理

写业务当中感觉最开始就是新建实体类和表,然后看需求,然后分析怎么去CUID操作,然后就开始去写SQL语句,使用Mybatis可以比较灵活的去解决ORM。这次挑战是对小时粒度的处理,解决方案是采用了部分的重构,提取方法和清晰的数据结构定义。
- 首先看一张表的结构:
describe [tableName];
多个字段排序业务处理_第1张图片
已经存在表中的数据如下:
多个字段排序业务处理_第2张图片
按照两个粒度,分别是日和小时。
日就是统计每天的人口数,返回1-24小时的人数,虽然大数据组可以提供24小时的数据,但是为了保证测试,我在业务里添加了该时间可能存在null的情况默认添0.因此返回给前端的总是24个横坐标。
order by 字段1,字段2.这样先按日排序在小时排序,这样方便处理。

select * from t_mon_data_pass_person_hour WHERE area_id = 7000 and date_time >= '2014-01-01' and date_time <= '2015-09-01' order by date_time,hour_time;

首先获取参数startTime,endTime,areaId和粒度:

//获取参数
        String areaId = ParamUtil.getFilteredParameter(request, "areaId", 0, "7000");
        String startTime = ParamUtil.getFilteredParameter(request, "startDate", 0, "2013-01-01");
        String endTime = ParamUtil.getFilteredParameter(request, "endDate", 0, "2016-01-01");
        Integer kpiCycle = Integer.valueOf(ParamUtil.getFilteredParameter(request, "kpiCycle", 0, "3"));

由于从timestamp时间戳的格式不便于处理,我需要去定义个我想要的格式,去转换,使用到了SimpleDateFormat类:

//定义查询map
        HashMap<String,String> queryMap = new HashMap<String,String>();
        queryMap.put("areaId", areaId);
        queryMap.put("startTime", startTime);
        queryMap.put("endTime", endTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//定义格式

然后判断是否为精确到时:

if(kpiCycle == Constants.VISITOR_COUNT_UNIT_HOUR)

这里dao层接口的方法定义了两个:

getHourPassPersonList(queryMap) getDayPassPersonList(queryMap)

第一个会查询出所有的记录,第二个会采用聚合函数,合并同一天的人口数。
对应sqlmap分别为:

<select id="getHourPassPersonList" parameterType="java.util.Map" resultMap="BaseResultMap">
        select * from t_mon_data_pass_person_hour
        <where>
            <if test="areaId != null">
                area_id = #{areaId}
            </if>
            <if test="startTime != null">
        <![CDATA[and date_time >= #{startTime}]]>
            </if>
            <if test="endTime != null">
        <![CDATA[and date_time <= #{endTime}]]>
            </if>
        </where>
        order by date_time,hour_time
    </select>

注意时间和小时的排序。

<select id="getDayPassPersonList" parameterType="java.util.Map" resultMap="BaseResultMap">
        select date_time,sum(population) as population
        from t_mon_data_pass_person_hour
        <where>
            <if test="areaId != null">
                area_id = #{areaId}
            </if>
            <if test="startTime != null">
        <![CDATA[and date_time >= #{startTime}]]>
            </if>
            <if test="endTime != null">
        <![CDATA[and date_time <= #{endTime}]]>
            </if>
            group by date_time
            order by date_time
        </where>
    </select>

再回到action里:
我们获取所有记录并得到所有日期。

List<PassPerson> passPersonList = passPersonManager.getHourPassPersonList(queryMap);
            List<Date> daysList = getDateTimeList(passPersonList);

但是因为表里可能存在重复的日期数,因此有必要提取不重复的顺序排列的日期,我这里的getDateTimeList就是这个方法,如下定义:

//取出所有日期
        private List<Date> getDateTimeList(List<PassPerson> list)
        {
            List<Date> dateList = new ArrayList<Date>();
            for(PassPerson p : list)
            {
                if(!dateList.contains(p.getDateTime()))
                {
                    dateList.add(p.getDateTime());
                }
            }
            return dateList;
        }

图标是显示多天24时,key-value分别存储日期和对应的人数。

//定义结果
            Map<String,List<Integer>> hourGraphMap = new TreeMap<String,List<Integer>>();

接下来去遍历所有日期,然后将对应日期所对应的24小时人数放到一个列表里,如果改小时没记录(测试可能用到,实际业务中会用记录为0),会用0去补齐:

for(Date date : daysList)
            {
                List<Integer> hoursList = new ArrayList<Integer>();
                int time = 1;//初始化时间
                for(PassPerson p : passPersonList)
                {
                    if(sdf.format(p.getDateTime()).equals(sdf.format(date)))
                    {
                        //如果该小时存在记录
                        if(time == p.getHourTime())
                        {
                            hoursList.add(p.getPopulation());
                        }
                        //如果没时间记录,填0
                        else
                        {
                            for(int i = time;i < p.getHourTime();i ++)
                            {
                                hoursList.add(0);
                            }
                            hoursList.add(p.getPopulation());
                            time = p.getHourTime() + 1;
                        }
                    }

                }
                //0补齐
                while(time < 24)
                {
                    hoursList.add(0);
                    time ++;
                }
                //格式转换

                String datetime = sdf.format(date);
                hourGraphMap.put(datetime, hoursList);
            }

然后还需要获取小时中的最大人数:

//小时最大人数峰值
            Integer hourMaxPopulation = getMaxPopulation(passPersonList);

因为在日的粒度下也需要使用,因此方法采用了重构。

//获得查出列表峰值
        private Integer getMaxPopulation(List<PassPerson> list)
        {
            int max = 0;
            for(PassPerson p : list)
            {
                max = p.getPopulation() > max ? p.getPopulation() : max;
            }
            return max;
        }

峰值的时间可能是多个,因此定义列表去保存:

//获得最大峰值时的格式:yyyy-MM-dd H时
            List<String> maxPopulationTimeList = new ArrayList<String>();
            for(PassPerson p : passPersonList)
            {
                if(p.getPopulation().equals(hourMaxPopulation))
                {
                    Date date = p.getDateTime();
                    //格式转换
                    String dateOfString = sdf.format(date);
                    maxPopulationTimeList.add(dateOfString + " " + p.getHourTime().toString()+"时");
                }
            }

后面的最小值,总人数,平均人口都采用了重构去解决,这样在日的粒度下去直接调用方法,简化了代码。在求平均的时候注意类型转换。

//平均每小时的人口
            Integer avgPopulationOfHour = 0;
            if(sumPopulation != 0)
            {
                Float f = (float)sumPopulation;
                Float f2 = (float)getDaysNumber(passPersonList) * 24;
                avgPopulationOfHour = (int) (f / f2);
            }

最后测试用例:

pass-person!display.action?areaId=7000&startDate=2014-01-01&endDate=2015-10-01&kpiCycle=0

返回:

{"hourMaxPopulation":400,"minPopulationTime":["2015-08-01 3时"],"maxPopulationTime":["2015-09-02 4时"],"avgPopulationOfHour":8,"hourMinPopulation":22,"topPopulation":400,"hourGraphMap":{"2015-08-01":[0,200,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"2015-08-02":[0,0,0,0,0,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"2015-09-01":[200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"2015-09-02":[0,0,0,400,33,0,0,0,0,0,0,44,0,0,0,0,0,0,0,0,0,0,0,0],"2015-09-10":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,123]}}

最开始tomcat一直报错无法注入,后来发现是服务层的注解没写。填上注解问题解决。

你可能感兴趣的:(排序,mybatis)