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


    在这里插入图片描述

    网站数据统计

    在这里插入图片描述

    定义相关的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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    定义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 {
        @Autowired
        private RedisTemplate redisTemplate;
        //定义日期格式
        private SimpleDateFormat df=new SimpleDateFormat("yyyyMMdd");
        //将指定的IP计入UV
        public void recordUV(String ip){
            //获取redisKey
            String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));
            //存入ip
            redisTemplate.opsForHyperLogLog().add(redisKey,ip);
        }
        //统计指定日期范围内的UV
        public 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);
        }
        //将指定用户计入DAU
        public 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() {
                @Override
                public 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());
                }
            });
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    定义拦截器

    
    @Component
    public class DataInterceptor implements HandlerInterceptor {
        @Autowired
        private DataService dataService;
        @Autowired
        private HostHolder hostHolder;
        //在请求之初统计数据
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception{
            //统计UV
            String ip= request.getRemoteHost();
            dataService.recordUV(ip);
            //统计DAU
            User user = hostHolder.getUser();
            if(user!=null){
                dataService.recordDAU(user.getId());
            }
            return true;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    定义Controller

    @Controller
    public class DataController {
        @Autowired
        private 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";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    添加权限

    .antMatchers(
                            "/discuss/delete",
                            "/data/**"
                    )
    
    • 1
    • 2
    • 3
    • 4

    页面示例

    <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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    【零基础学QT】第九章 窗口美化QSS的使用
    JDBC-day07(Apache-DBUtils实现CRUD操作)
    linux编写shell脚本实现判断当端口被占用时杀死进程
    SpringMVC(五)【拦截器】
    Redis过期数据删除策略
    RobotFramework+Eclispe环境安装篇
    【网络安全】网站被攻击了怎么办?怎么防护DDOS、CC、XSS、ARP等攻击?
    springboot银行客户管理系统毕业设计源码250903
    SpringBoot 刷新上下文4--处理ComponentScan
    课堂练习13 网络编程
  • 原文地址:https://blog.csdn.net/weixin_44925329/article/details/134200302