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

news/2024/11/29 20:43:14/

在这里插入图片描述

网站数据统计

在这里插入图片描述

定义相关的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.ppmy.cn/news/1200318.html

相关文章

viple入门(一)

&#xff08;1&#xff09;数据活动 用于放置数据&#xff0c;可以是整数类型&#xff08;整型&#xff09;、双精度浮点类型、字符串类型、字符类型、布尔类型的数据。 特点&#xff1a;数据活动可自动识别数据对应的数据类型。 &#xff08;2&#xff09;变量活动 定义变量…

【Go 编程实践】从零到一:创建、测试并发布自己的 Go 库

为什么需要开发自己的 Go 库 在编程语言中&#xff0c;包&#xff08;Package&#xff09;和库&#xff08;Library&#xff09;是代码组织和复用的重要工具。在 Go 中&#xff0c;包是代码的基本组织单位&#xff0c;每个 Go 程序都由包构成。包的作用是帮助组织代码&#xf…

在Linux系统下部署Llama2(MetaAI)大模型教程

Llama2是Meta最新开源的语言大模型&#xff0c;训练数据集2万亿token&#xff0c;上下文长度是由Llama的2048扩展到4096&#xff0c;可以理解和生成更长的文本&#xff0c;包括7B、13B和70B三个模型&#xff0c;在各种基准集的测试上表现突出&#xff0c;最重要的是&#xff0c…

Pycharm的安装与基本使用

Pycharm的安装与基本使用 一、Pycharm介绍1.1 Pycharm简介1.2 Pycharm特点 二、Pycharm软件下载2.1 Pycharm官网2.2 下载Pycharm 三、安装Pycharm3.1 指定安装目录3.2 勾选安装选项3.3 选择菜单目录3.4 安装成功 四、Pycharm的初始配置4.1 新建工程4.2 选择Python解释器4.3 打开…

医学大模型开源项目: 医学大模型的局限性 + 改进思路

医学大模型开源项目&#xff1a; 医学大模型的局限性 改进思路 GPT在医学上的优势&#xff1a;专业性凸显&#xff0c;实用性兼备大模型在医学上的局限&#xff1a;问诊详细程度完全随机、推理和决策逻辑不完整、建议偏方向性实用性欠缺方案一&#xff1a;海量相关数据 GPT4 …

镭神智能C16的ROS1驱动的安装方法

github 代码链接 git clone -b C16_V4.0 https://github.com/Lslidar/Lslidar_ROS1_driver.gitroslaunch lslidar_driver lslidar_c16.launch

哈夫曼编码与解码,基于Python实现

from itertools import count from collections import Counter from heapq import heapify, heappush, heappopdef huffman_tree(s):# 统计每个字符出现的次数s Counter(s) # 计算可迭代序列中元素的数量&#xff0c;返回字典类型数据c…

分享一下订房小程序怎么做

随着科技的进步和互联网的普及&#xff0c;线上预订已经成为人们日常生活的一部分。无论是预订餐厅、购买电影票还是预定酒店&#xff0c;都可以通过手机或电脑轻松完成。而在这个数字化时代&#xff0c;制作一个订房小程序已经成为酒店行业的一种趋势。本文将详细介绍如何制作…