需要统计的事项:

UV每次访问都要把用户的ip(不管该用户有无登录)存到某个数据结构里,方便进行统计

DAU只统计登录的用户(根据用户id),对于那些没有登录的游客不进行统计。1表示访问过,为活跃用户;0表示没有访问过,为不活跃用户;

DAU更关注用户用户有效性

1.在RedisKeyUtil中

private static final String PREFIX_UV = "uv";//统计uv相关数据的前缀
private static final String PREFIX_DAU = "dau";//统计dau相关数据的前缀
// 单日UV,记录UV是以天为单位的
public static String getUVKey(String date) {return PREFIX_UV + SPLIT + date;
}// 区间UV,查看一周的UV
public static String getUVKey(String startDate, String endDate) {return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;
}// 单日活跃用户
public static String getDAUKey(String date) {return PREFIX_DAU + SPLIT + date;
}// 区间活跃用户
public static String getDAUKey(String startDate, String endDate) {return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;
}

2.开发完key后,开发数据访问层,因为redis数据访问层可以直接写services

@Service
public class DataService {@Autowiredprivate RedisTemplate redisTemplate;private SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");// 将指定的IP计入UVpublic void recordUV(String ip) {String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));//df.format(new Date())表示把当前时间格式化redisTemplate.opsForHyperLogLog().add(redisKey, ip);}// 统计指定日期范围内的UVpublic long calculateUV(Date start, Date end) {//传入开始和截止日期if (start == null || end == null) {throw new IllegalArgumentException("参数不能为空!");}// 整理该日期范围内的keyList<String> keyList = new ArrayList<>();Calendar calendar = Calendar.getInstance();//实例化calendarcalendar.setTime(start);while (!calendar.getTime().after(end)) {//calendar.getTime()表明时间,after(end)表示 如果晚于end,有感叹号 表示 时间如果不晚于结束,则循环String key = RedisKeyUtil.getUVKey(df.format(calendar.getTime()));//每次遍历得到keykeyList.add(key);calendar.add(Calendar.DATE, 1);//加一天}// 合并这些数据String redisKey = RedisKeyUtil.getUVKey(df.format(start), df.format(end));//redisKey是合并以后数据的keyredisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());//keyList.toArray()表示把keyList 转换为数组// 返回统计的结果return redisTemplate.opsForHyperLogLog().size(redisKey);}// 将指定用户计入DAUpublic void recordDAU(int userId) {String redisKey = RedisKeyUtil.getDAUKey(df.format(new Date()));redisTemplate.opsForValue().setBit(redisKey, userId, true);}// 统计指定日期范围内的DAUpublic long calculateDAU(Date start, Date end) {if (start == null || end == null) {throw new IllegalArgumentException("参数不能为空!");}// 整理该日期范围内的keyList<byte[]> keyList = new ArrayList<>();Calendar calendar = Calendar.getInstance();calendar.setTime(start);//设置启示日期while (!calendar.getTime().after(end)) {String key = RedisKeyUtil.getDAUKey(df.format(calendar.getTime()));keyList.add(key.getBytes());calendar.add(Calendar.DATE, 1);}// 进行OR运算return (long) redisTemplate.execute(new RedisCallback() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {String redisKey = RedisKeyUtil.getDAUKey(df.format(start), df.format(end));connection.bitOp(RedisStringCommands.BitOperation.OR,//第一个参数是RedisStringCommands.BitOperation.OR 即进行什么样的运算redisKey.getBytes(), keyList.toArray(new byte[0][0]));//keyList.toArray()表示把keyList 转换为数组return connection.bitCount(redisKey.getBytes());}});}
}

3.在表现层中,新建拦截器

@Component
public class DataInterceptor implements HandlerInterceptor {@Autowiredprivate DataService dataService;@Autowiredprivate HostHolder hostHolder;//得到当前用户id@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//preHandle表示在请求之初统计,统计完后继续向下执行// 统计UVString ip = request.getRemoteHost();dataService.recordUV(ip);// 统计DAUUser user = hostHolder.getUser();if (user != null) {//user不为空,才进行统计dataService.recordDAU(user.getId());}return true;}
}

之后在WebMvcConfig中,

@Autowired
private DataInterceptor dataInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(dataInterceptor)//对于静态资源无需拦截.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
}

3.新建DataController

要新建这个样子的页面

@Controller
public class DataController {@Autowiredprivate DataService dataService;// 统计页面@RequestMapping(path = "/data", method = {RequestMethod.GET, RequestMethod.POST})// 统计页面的路径以及请求方式public String getDataPage() {return "/site/admin/data";}// 统计网站UV@RequestMapping(path = "/data/uv", method = RequestMethod.POST)public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,//@DateTimeFormat(pattern = "yyyy-MM-dd") 来告诉服务器的日期格式。传入三个参数start,end,model@DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {long uv = dataService.calculateUV(start, end);model.addAttribute("uvResult", uv);model.addAttribute("uvStartDate", start);model.addAttribute("uvEndDate", end);return "forward:/data";}// 统计活跃用户@RequestMapping(path = "/data/dau", method = RequestMethod.POST)public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,@DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {long dau = dataService.calculateDAU(start, end);model.addAttribute("dauResult", dau);model.addAttribute("dauStartDate", start);model.addAttribute("dauEndDate", end);return "forward:/data";}}

在data.html中,

<!-- 内容 -->
<div class="main"><!-- 网站UV --><div class="container pl-5 pr-5 pt-3 pb-3 mt-3"><h6 class="mt-3"><b class="square"></b> 网站 UV</h6><form class="form-inline mt-3" method="post" th:action="@{/data/uv}"><input type="date" class="form-control" required name="start" th:value="${#dates.format(uvStartDate,'yyyy-MM-dd')}"/><input type="date" class="form-control ml-3" required name="end" th:value="${#dates.format(uvEndDate,'yyyy-MM-dd')}"/><button type="submit" class="btn btn-primary ml-3">开始统计</button></form><ul class="list-group mt-3 mb-3"><li class="list-group-item d-flex justify-content-between align-items-center">统计结果<span class="badge badge-primary badge-danger font-size-14" th:text="${uvResult}">0</span><!-- 统计结果th:text="${uvResult}"--></li></ul></div><!-- 活跃用户 --><div class="container pl-5 pr-5 pt-3 pb-3 mt-4"><h6 class="mt-3"><b class="square"></b> 活跃用户</h6><form class="form-inline mt-3" method="post" th:action="@{/data/dau}"><input type="date" class="form-control" required name="start" th:value="${#dates.format(dauStartDate,'yyyy-MM-dd')}"/><input type="date" class="form-control ml-3" required name="end" th:value="${#dates.format(dauEndDate,'yyyy-MM-dd')}"/><button type="submit" class="btn btn-primary ml-3">开始统计</button></form><ul class="list-group mt-3 mb-3"><li class="list-group-item d-flex justify-content-between align-items-center">统计结果<span class="badge badge-primary badge-danger font-size-14" th:text="${dauResult}">0</span></li></ul></div>
</div>

测试:

只有管理员才能访问data


管理员登录后,直接敲这个路径访问data


UA只有一个,因为我们一直用自己的电脑

刚才我们用普通用户,版主,管理员三个账号进行了操作

7.10网站数据统计相关推荐

  1. 怎么统计是否内宿_白杨SEO:工具推荐第十期——网站数据统计工具之百度统计(二)...

    序言:为啥想到写这篇呢,上周我付费群里一个小伙伴单独微信我的,想起就补一篇吧,上一篇还是几个月前写的呢,哈哈哈. 因为刚写了一篇权重文章花了我两个多小时.这一篇,我就加快进度了哈.这是一篇下,那我先把 ...

  2. 网站数据统计常用指标(网站流量与性能分析指标)

    PV Page View,页面访问量,指页面浏览的次数,用以衡量网站用户访问的网页数量.也就是曝光量.一般来说,PV与来访者的数量成正比,但是PV并不直接决定页面的真实来访者数量,如同一个来访者通过不 ...

  3. NoJS的网站数据统计

    目前主流的网站分析工具都是通过JavaScript来实现数据的获取的,如Google Analytics就是通过在网页中嵌入一段JS代码,当该网页被浏览时,JS代码被加载,就会向Google Anal ...

  4. 一分钟为网站添加统计功能

    首先我们需要选择第三方平台,推荐使用腾讯分析或者百度统计 为什么使用这些平台呢? 1.首先省事高效,我们不需要自己去开发这些功能,只需要一行代码粘贴到自己的网站中,就可以生效使用了: 2.第二点大公司 ...

  5. 51LA网站访问统计使用【图文教程】

    目前对于网站访问信息的相关统计,还是有很多的办法,比如百度统计,友盟,51AL等,本站都有用过,对于百度统计比较单一,也没有前台数据挂载,不是很人性化.友盟相对还可以,不过目前因为一些原因是无法使用了 ...

  6. hexo博客加入51LA网站流量统计

    自建hexo博客xiejava.ishareread.com一直在用CNZZ的网站流量统计,每天登陆到CNZZ的网站流量统计后台看博客的访问量成了建站以来的习惯.3月23日以后突然发现CNZZ的统计没 ...

  7. seo提交工具_呼伦贝尔网站建设_5118站长数据分析平台非常适合SEO站长做数据统计...

    发布时间:2020-12-07 08:12:27 标准站长需要哪些工具?我相信许多站长没有考虑过这个问题.我一直认为,找到一个数据非常大的工具非常适合我们的站长.几天前,朋友们推荐了一个新的站长工具. ...

  8. 产品经理必备数据统计网站汇总

    原文链接:http://www.360doc.cn/article/26692725_645054648.html 如果:你想写一篇竞品分析报告时候苦于没有数据来源?想知道竞争对手在互联网市场的市场份 ...

  9. Worldometer网站实时统计新冠数据

    Worldometer网站实时统计数据显示,截至北京时间12月13日6时30分左右,全球累计确诊新冠肺炎病例72032650例,累计死亡病例1610312例,全球单日新增确诊病例700141例,新增死 ...

最新文章

  1. linux严谨的telnet搭建并用防火墙开通与禁行
  2. 基于MeanShift的目标跟踪算法及实现
  3. SQLite VC环境搭建
  4. PostgreSQL新手入门教程
  5. 华为鸿蒙内置,内置鸿蒙系统,华为生态产品海雀智能摄像头Pro体验
  6. 小程序成长之路(四)-- 深入腾讯云(环境搭建)
  7. C 标准库 limits.h
  8. python输出元组重复的元素_python – 从n个元素生成所有4元组对
  9. 【初赛】各种排序算法总结
  10. redis如何进行分库存储和选择模糊清除缓存
  11. 税务会计实务【14】
  12. python天天向上的力量实验报告_Python练习11:天天向上的力量
  13. (Animator详解一)mixamo动画导入Unity的一些配置
  14. 英语一大作文模板如何自己制作?
  15. Mybatis中如何实现一对一,一对多的关联查询?
  16. 三轴加速度传感器bma150驱动解析
  17. arduino+旋转编码器
  18. openlayers+vue 仿百度罗盘功能(指北针)
  19. JDK1.8(jdk8)的下载与安装
  20. Docker 拉取镜像及标签 pull | tag

热门文章

  1. Codeforces Round #695 (Div. 2)ABCD题解详析
  2. 机器学习:K近邻(KNN)
  3. easyExcel实现动态表头设置以及单元格样式设置
  4. 浙江大学工程师学院篇|2022年电子信息/通信工程夏令营保研/考研复试经验贴
  5. SSM+ckplayer.js实现web项目网页看视频
  6. ROS2+Qt5 开发问题汇总
  7. Java-----joddhttp使用
  8. 硬盘主分区、扩展分区和逻辑分区
  9. 万年历c语言打印年月,万年历(实现从键盘输入1900年之后的任意的某年、某月,输出该月的日历)...
  10. 算一下你来到这个世界多少天? java语言