在最近写统计后台的时候,接口传过来包含主渠道,子渠道,平台的json,获取并解析
1.解析json获得主渠道子渠道
传过来的值是类似t=wg_1
int j = t.indexOf("_"); String channel = t.substring(0, j); Integer subChannel = Integer.valueOf(t.substring(j + 1));
2.从http的请求中获取访问的来源
这里pr是访问来源,如果接口中没有传输访问来源的话就从http请求中解析
获取请求头部的"user-agent"并将其转化为小写,如果其中存在"micromessenger"就是从微信访问,存在"qq"就是从qq访问
Integer source; if (pr==null){ String ua = request.getHeader("user-agent").toLowerCase(); if (ua.contains("micromessenger")) { source = 1; } else if (ua.contains("qq")) { source = 2; } else { source = 3; } }else{ source = pr; }
3.将每一条访问数据都存储数据库后,每小时统计一次,通过前端的查询反馈数据库的数据并计算
前端的界面如下:
业务逻辑层代码如下:
public void getStatistics(LocalDate localDate,Integer hour, Integer platform) { ZonedDateTime starTime = DateUtil.getStartDayTime(localDate,hour); ZonedDateTime endTime = DateUtil.getEndDayTime(localDate,hour); List<ChannelStatisticsRecord> list = channelStatisticsRecordDAO.findAllByCreateTimeBetweenAndPlatform(starTime,endTime, platform); Map<String, List<ChannelStatisticsRecord>> map1 = list.stream().collect(Collectors.groupingBy(ChannelStatisticsRecord::groupChannel)); for (Map.Entry<String, List<ChannelStatisticsRecord>> entry1 : map1.entrySet()) { ChannelStatistics channelStatistics = new ChannelStatistics(); String[] ch = entry1.getKey().split("_"); String channel = ch[0]; Integer subChannel = Integer.valueOf(ch[1]); channelStatistics.setChannel(channel); channelStatistics.setSubChannel(subChannel); channelStatistics.setPlatform(platform); channelStatistics.setDate(localDate); channelStatistics.setHour(hour); Integer qqNum = 0; Integer wxNum = 0; Integer wapNum = 0; for (ChannelStatisticsRecord channelStatisticsRecord : entry1.getValue()) { if (channelStatisticsRecord.getSource() == 1) { wxNum++; } else if (channelStatisticsRecord.getSource() == 2) { qqNum++; } else { wapNum++; } } channelStatistics.setQqNum(qqNum); channelStatistics.setWxNum(wxNum); channelStatistics.setWapNum(wapNum); channnelStatisticsDAO.save(channelStatistics); } }
在这过程中遇到几个问题:
(1)首先是如何按小时统计:
解决办法:写了一个TaskStics的统计类
@Component public class TaskStics { @Autowired private ChannelStatisticsRecordService channelStatisticsRecordService; /** * 每小时零一分 */ @Scheduled(cron = "0 1 * * * ?") public void getStatistics() { channelStatisticsRecordService.getStatistics(LocalDate.now(),DateUtil.getHour(),1); channelStatisticsRecordService.getStatistics(LocalDate.now(),DateUtil.getHour(),2); channelStatisticsRecordService.getStatistics(LocalDate.now(),DateUtil.getHour(),3); }
在每个小时零一分的时候调用统计的方法并将当前的日期和当前的小时还有平台参数传过去
(2)其次是传了当前的日期和小时过去了,但是数据库中记录表里是createTime,也就是是年月日时分秒的格式,怎么获取在上一个小时中的所有记录
解决方法:在DateUtil里面增加几个方法
public static ZonedDateTime getStartDayTime(LocalDate localDate,Integer hour){ return localDate.atTime(hour,0,0).atZone(ZoneId.systemDefault()); } public static Integer getHour() { String str = LocalDateTime.now().minusDays(1).minusHours(1).format(DateTimeFormatter.ofPattern("HH")); return Integer.valueOf(str); } public static ZonedDateTime getEndDayTime(LocalDate localDate,Integer hour){ return localDate.atTime(hour,59,59).atZone(ZoneId.systemDefault()); }
第一个方法是通过日期和小时数得到该时间的起始,如传进来2018-10-08和12,那么通过这个方法得到的是2018-10-08 12:00:00
同理第三个方法得到的是该时间的结束值2018-10-08 12:59:59
第二个方法是获取前一个小时,如现在是12点则得到11点,因为统计的是前一个小时的数据
(3)解决上面两个问题后通过传入的时间和平台已经可以得到一个list,那么怎么把这个list根据主渠道,子渠道,访问来源去多级分组
解决办法:想了很多办法也在网上查阅了很多,觉得都很麻烦,后来尝试了自定义一个分组的方法,方便了许多
Map<String, List<ChannelStatisticsRecord>> map1 = list.stream().collect(Collectors.groupingBy(ChannelStatisticsRecord::groupChannel));
groupChannel是自己自定义在实体类中的一个方法,将主渠道和子渠道拼合起来
public String groupChannel() { return getChannel() + "_" + getSubChannel(); }
看了项目中别人写的代码后发现还有一种方法
Map<String, List<Instance>> collect = list.stream() .collect(Collectors.groupingBy(instance -> instance.getChannel()+"_"+instance.getSubChannel() +"_"+instance.getSource()+"_"+(instance.getTime().getHours())));