Redis高级数据类型-HyperLogLogBitmap以及使用两种数据类型完成网站数据统计

在这里插入图片描述

网站数据统计

在这里插入图片描述

定义相关的Redis Key

    /*** 单日UV*/public static String getUVKey(String date) {return PREFIX_UV+SPLIT+date;}/*** 记录区间UV* @param startData 开始日期* @param endDate 结束日期* @return*/public static String getUVkey(String startData,String endDate){return PREFIX_UV+SPLIT+startData+SPLIT+endDate;}/*** 单日活跃用户* @param date* @return*/public static String getDAUkey(String date){return PREFIX_DAU+SPLIT+date;}/*** 区间活跃用户* @param startDate 开始日期* @param endDate 结束日期* @return*/public static String getDAUKey(String startDate,String endDate){return PREFIX_DAU+SPLIT+startDate+SPLIT+endDate;}

定义DataService

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;@Service
public class DataService {@Autowiredprivate RedisTemplate redisTemplate;//定义日期格式private SimpleDateFormat df=new SimpleDateFormat("yyyyMMdd");//将指定的IP计入UVpublic void recordUV(String ip){//获取redisKeyString redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));//存入ipredisTemplate.opsForHyperLogLog().add(redisKey,ip);}//统计指定日期范围内的UVpublic long calculateUV(Date start,Date end){//参数判空if(start ==null || end == null){throw new IllegalArgumentException("参数不能为空");}/*** 整理改时间范围内的key*/List<String> keyList =new ArrayList<>();//可以进行日期计算Calendar calendar = Calendar.getInstance();calendar.setTime(start);//当前日期小于结束日期while (!calendar.getTime().after(end)){String key=RedisKeyUtil.getUVKey(df.format(calendar.getTime()));keyList.add(key);calendar.add(Calendar.DATE,1);//对日期进行递加}/*** 合并数据*/String redisKey =RedisKeyUtil.getUVkey(df.format(start),df.format(end));redisTemplate.opsForHyperLogLog().union(redisKey,keyList.toArray());//返回统计结果 访问数量return redisTemplate.opsForHyperLogLog().size(redisKey);}//将指定用户计入DAUpublic void recordDAU(int userId){String redisKey =RedisKeyUtil.getDAUkey(df.format(new Date()));redisTemplate.opsForValue().setBit(redisKey,userId,true);}//统计指定日期范围内的DAU//每一天的统计结果做一个或运算public long calculateDAU(Date start,Date end){//参数判空if(start ==null || end == null){throw new IllegalArgumentException("参数不能为空");}/*** 整理改时间范围内的key*/List<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运算* 使用redis底层的链接调用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,redisKey.getBytes(),keyList.toArray(new byte[0][0]));return connection.bitCount(redisKey.getBytes());}});}
}

定义拦截器


@Component
public class DataInterceptor implements HandlerInterceptor {@Autowiredprivate DataService dataService;@Autowiredprivate HostHolder hostHolder;//在请求之初统计数据@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception{//统计UVString ip= request.getRemoteHost();dataService.recordUV(ip);//统计DAUUser user = hostHolder.getUser();if(user!=null){dataService.recordDAU(user.getId());}return true;}
}

定义Controller

@Controller
public class DataController {@Autowiredprivate DataService dataService;/*** 统计页面的函数* @return*/@RequestMapping(path = "/data",method = {RequestMethod.GET,RequestMethod.POST})public String getDataPage(){return "/site/admin/data";}/*** 统计网站UV* @param start* @param end* @param model* @return*/@RequestMapping(path = "/data/uv",method = RequestMethod.POST)public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start , @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);//将处理结果发给/data进行另一半的处理return "forward:/data";
//        return "/site/admin/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);//将处理结果发给/data进行另一半的处理return "forward:/data";
//        return "/site/admin/data";}
}

添加权限

.antMatchers("/discuss/delete","/data/**")

页面示例

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/162305.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git同时配置Gitee和GitHub

Git同时配置Gitee和GitHub 一、删除原先ssh密钥二、生成密钥 这里的同时配置是针对于之前配置过单个gitee或者github而言的&#xff0c;如果需要看git从安装开始的配置&#xff0c;则可以看这一篇文章 git安装配置教程 一、删除原先ssh密钥 在C盘下用户/用户名/.ssh文件下找到…

KaiOS APN配置文件apn.json调试验证方法(无需项目全编)

1、KaiOS 的应用就类似web应用&#xff0c;结合文件夹路径webapp字面意思理解。 2、KaiOS APN配置文件源代码在apn.json&#xff0c; &#xff08;1&#xff09;apn.json可以自定义路径&#xff0c;通过配置脚本实现拷贝APN在编译时动态选择路径在机器中生效。 &#xff08;…

MyBatis 分页插件 PageHelper 6.0.0 发布

6.0.0 - 2023-11-05 基于jdk8适配&#xff0c;6.0开始不支持jdk6和7&#xff0c;如果有需要可以使用5.x版本增加异步count支持&#xff0c;全局配置asyncCount&#xff0c;默认false&#xff0c;单次设置&#xff1a;PageHelper.startPage(1, 10).enableAsyncCount(); 异步使用…

Crypto(8) BUUCTF-bbbbbbrsa1

题目描述&#xff1a; from base64 import b64encode as b32encode from gmpy2 import invert,gcd,iroot from Crypto.Util.number import * from binascii import a2b_hex,b2a_hex import randomflag "******************************"nbit 128p getPrime(nbit)…

HarmonyOS ArkTS基础知识

概述 上一节&#xff0c;学习了TypeScript的基础语法&#xff0c;而在鸿蒙开发当中&#xff0c;有基于自己的编程语言&#xff0c;便是ArkTS。它是一种声明式UI的编程范式的语言&#xff0c;开发框架如下图所示&#xff1a; 根据框架图&#xff0c;分析&#xff0c;我将它大致…

吸引人的标题公式-爆款标题

有的朋友图文或视频质量明明很不错 但数据有时候却不尽人意 这个时候就可以考虑一下是不是标题的原因 这篇总结出万能公式以供参考

unity【动画】脚本_角色动画控制器 c#

首先创建一个代码文件夹Scripts 从人物角色Player的基类开始 创建IPlayer类 首先我们考虑到如果不挂载MonoBehaviour需要将角色设置成预制体实例化到场景上十分麻烦&#xff0c; 所以我们采用继承MonoBehaviour类的角色基类方法写代码 也就是说这个脚本直接绑定在角色物体…

第21期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

LangChain+LLM实战---Midjourney高级技巧的极简教程

原文&#xff1a;An advanced guide to writing prompts for Midjourney ( text-to-image) 作者&#xff1a;Lars Nielsen Midjourney生成的图像&#xff0c;文本Prompt&#xff1a;beautiful, fantasy city unreal engine 一句话介绍midjourney ? 对于那些还没有听说过Mid…

【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…

AD7792/AD7793 备忘

AD7792/AD7793 是一款 ∑-Δ ADC&#xff0c;3 通道、低噪声&#xff0c;内部集成仪表放大器和参考源。AD7792 为 16 位&#xff0c;AD7793为 24 位。 供电电压&#xff1a;2.7 ~ 5.25 V&#xff0c;并不支持负电压。转换速率&#xff1a;4.17 Hz ~ 470 Hz内置参考基准&#x…

虚拟机备份中的CBT技术

虚拟机备份的CBT&#xff08; Changed Block Tracking&#xff09;模式是一种备份模式&#xff0c;它能够识别和跟踪自上次备份后虚拟机中被修改过的块&#xff0c;这些修改会被存放到日志文件中。在启用CBT模式之后&#xff0c;备份软件会利用这个功能进行增量备份。 启用CBT…