javaweb网站访问量统计,本年、本月、今日网站访问量统计

1、概要

  • 关于java web 网站访问统计功能,翻阅了很多技术文档没有找到合适的功能需求,为了满足开源项目《RuoYi-fast-cms》集大众之所及,于是根据实际业务逻辑,按照自己的思路开发出来了
  • 网站统计是指通过对网站的访问情况、用户行为和其他相关数据进行收集、分析和报告,以便了解网站的运营情况和用户特征。它的作用和优点包括:
    • 了解用户行为:通过网站统计,可以知道用户在网站上的停留时间、浏览页面、点击链接和交互等行为,从而了解用户的兴趣和偏好,有效地进行用户行为分析。
    • 优化网站体验:通过对用户行为和反馈的统计分析,可以发现网站的问题和瓶颈,并根据数据做出优化改进,提升网站的用户体验和用户满意度。
    • 提高转化率:网站统计可以追踪用户的转化路径,包括注册、购买、留言等行为,并通过分析找出影响转化率的因素,从而优化网站的设计、内容和推广策略,提高转化率和销售额。
    • 评估营销效果:通过网站统计,可以了解到各种营销活动的效果,比如广告点击量、转化率、ROI等,从而为营销决策提供数据支持,优化营销策略,提高投资回报率。
    • 监控网站安全:网站统计可以监控恶意攻击、异常访问和网络安全事件等,及时发现并解决安全问题,保护网站和用户数据的安全。
  • 总之,网站统计可以帮助网站主了解用户行为、优化网站体验、提高转化率、评估营销效果和监控网站安全,从而提升网站的运营效果和用户满意度。

2、来源

  • 开源项目 RuoYi-fast-cms是一款 Java CMS 网站管理系统,项目基于 RuoYi-fast 二次开发,网站后台采用 SpringBoot + MyBatis,前端网站模版使用 thymeleaf+bootstrap 开发,多套风格模板,可自由飞翔。
  • 代码源自开源项目: https://github.com/huangxing2010/RuoYi-fast-cms

3、需求分析

  • 刷新或者访问页面获取访客 ip 地址,
  • 初次访问根据站点类型、ip 存储
  • 第二次访问根据 ip 如果存在累加 pv 量加 1否则新增
  • 每天记录一条数据,防止重复添加做了合并数据

4、数据库表

关于CRUD就不做阐述了,感兴趣的小伙伴请移步开源仓库

drop table if exists sys_portal_browse;
create table sys_portal_browse (
  browse_id        bigint(20)      not null auto_increment    comment '浏览id',
  browse_type      char(1)           default '0'         comment '类型(0网站A 1网站B ...)', 
  browse_json      json                                        comment '浏览统计(ip+次数)',
  remark           varchar(512)      default null        comment '备注',
  create_time      datetime                              comment '创建时间',
  primary key (browse_id)
) engine=innodb auto_increment=1 comment = '访问统计表';

5、代码分享

高端食材往往采用最朴素的烹饪方式,程序员的每一道菜都凝聚了辛勤的汗。大佬厌倦了屎山上堆屎,往往满足客户应急需求势在必得,若不够优雅请勿喷,欢迎高手指点!

5.1、控制器方法

//访问统计
 modelMap.put("browseCount", greenBrowseService.setBrowseCount("0"));

5.2、业务层

/**
     * 统计访问量
     * @param browseType
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> setBrowseCount(String browseType) {
        String ip = ShiroUtils.getIp();
        PortalBrowse portalBrowse = new PortalBrowse();
        Map<String, Object> params = portalBrowse.getParams();
        params.put("browseType", browseType);
        //当前日期开始时间
        LocalDate today = LocalDate.now();
        String todayDate = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String beginTime = todayDate + " 00:00:00";
        String endTime = todayDate + " 23:59:59";
        params.put("beginTime", beginTime);
        params.put("endTime", endTime);
        List<PortalBrowse> portalBrowses = portalBrowseMapper.selectPortalBrowseByParam(params);

        //每天统计只有一条数据,访问量大的时候可能会有多条数据出现,所以做了合并
        if (portalBrowses.size() > 0) {
            //防止当天统计条数多于1
            if (portalBrowses.size() > 1) {
                //便利出 id集合
                List<String> ids = new ArrayList<>();
                List<String> ips = new ArrayList<>();
                //遍历合并 ip+number集合
                List<Map<String, Object>> arrayBrowse = new ArrayList<>();
                portalBrowses.forEach(item -> {
                    ids.add(item.getBrowseId().toString());
                    String browseJson = item.getBrowseJson();  //字符串转json
                    JSONArray jsonArr = JSON.parseArray(browseJson);
                    //遍历 ip+ number集合
                    for (int i = 0; i < jsonArr.size(); i++) {
                        Map<String, Object> map1 = new HashMap<>();
                        JSONObject obj = jsonArr.getJSONObject(i);
                        map1.put("ip", (String) obj.get("ip"));
                        map1.put("number", (Integer) obj.get("number"));
                        ips.add((String) obj.get("ip"));
                        arrayBrowse.add(map1);
                    }
                });
                List<Map<String, Object>> browseList = getBrowseList(arrayBrowse, ip, ips);
                //插入新遍历数据,并删除旧数据
                PortalBrowse browseObjs = new PortalBrowse();
                browseObjs.setBrowseType(browseType);
                browseObjs.setBrowseJson(JSON.toJSONString(browseList));
                browseObjs.setCreateTime(DateUtils.getNowDate());
                if (portalBrowseMapper.insertPortalBrowse(browseObjs) > 0) {
                    portalBrowseMapper.deletePortalBrowseByBrowseIds(ids.toArray(new String[]{}));
                }
            } else { // 只有 1 条的时候修改该数据
                List<String> ips = new ArrayList<>();
                //遍历合并 ip+number集合
                List<Map<String, Object>> arrayBrowse1 = new ArrayList<>();
                PortalBrowse portalBrowse1 = portalBrowses.get(0);
                String browseJson = portalBrowse1.getBrowseJson();
                JSONArray jsonArr1 = JSON.parseArray(browseJson);
                //遍历 ip+ number集合
                for (int i = 0; i < jsonArr1.size(); i++) {
                    Map<String, Object> map1 = new HashMap<>();
                    JSONObject obj = jsonArr1.getJSONObject(i);
                    map1.put("ip", (String) obj.get("ip"));
                    map1.put("number", (Integer) obj.get("number"));
                    ips.add((String) obj.get("ip"));
                    arrayBrowse1.add(map1);
                }
                //封装 :ip重复的 number 值 累积相加
                List<Map<String, Object>> browseList = getBrowseList(arrayBrowse1, ip, ips);
                PortalBrowse portalBrowse3 = new PortalBrowse();
                portalBrowse3.setBrowseId(portalBrowse1.getBrowseId());
                portalBrowse3.setBrowseJson(JSON.toJSONString(browseList));
                portalBrowseMapper.updatePortalBrowse(portalBrowse3);
            }

        } else {  //为空的时候,新增一条数据
            PortalBrowse browse = new PortalBrowse();
            List<Object> objects = new ArrayList<>();
            Map<String, Object> obj = new HashMap<>();
            obj.put("ip", ip);
            obj.put("number", 1);
            objects.add(obj);
            browse.setBrowseType(browseType);
            browse.setBrowseJson(JSON.toJSONString(objects));
            browse.setCreateTime(DateUtils.getNowDate());
            portalBrowseMapper.insertPortalBrowse(browse);
        }
        //给模版赋值
        Map<String, Object> map = new HashMap<>();
        map.put("todayPv", getBrowseCount(browseType, "today").get("pv"));
        map.put("todayIp", getBrowseCount(browseType, "today").get("ip"));
        map.put("yesterdayPv", getBrowseCount(browseType, "yesterday").get("pv"));
        map.put("yesterdayIp", getBrowseCount(browseType, "yesterday").get("ip"));
        map.put("weekPv", getBrowseCount(browseType, "week").get("pv"));
        map.put("weekIp", getBrowseCount(browseType, "week").get("ip"));
        map.put("allPv", getBrowseCount(browseType, "all").get("pv"));
        map.put("allIp", getBrowseCount(browseType, "all").get("ip"));
        return map;
    }

5.3、业务层封装

    /**
     * 获取pv和ip
     * @param browseType 站点,dateType
     * @param  dateType today=今天 yesterday=昨天 week=本周 all=全部
     * @return
     */
    private Map<String, Object> getBrowseCount(String browseType, String dateType) {
            PortalBrowse portalBrowse = new PortalBrowse();
            Map<String, Object> params = portalBrowse.getParams();
            params.put("browseType", browseType);
            // 获取今天的日期
            LocalDate today = LocalDate.now();
            if(dateType == "today"){
                String todayDate = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                String beginTime = todayDate + " 00:00:00";
                String endTime = todayDate + " 23:59:59";
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);

            }else if(dateType == "yesterday"){
                // 获取昨天的日期
                LocalDate yesterday = today.minusDays(1);
//                System.out.println("昨天的日期: " + yesterday);
                String yesterdayStr = yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                String beginTime = yesterdayStr + " 00:00:00";
                String endTime = yesterdayStr + " 23:59:59";

                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
            }else if(dateType == "week"){
                // 获取本周的开始日期(周一)
                LocalDate startOfWeek = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                String format = startOfWeek.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                //今天
                String format1 = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                String beginTime = format + " 00:00:00";
                String endTime = format1 + " 23:59:59";
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
            } else if(dateType == "all"){
                //今天
                String format1 = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                //开始时间是开发之前的任意时间
                String beginTime ="2020-01-01 00:00:00";
                String endTime = format1 + " 23:59:59";
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
            }else {
                //开始时间是开发之前的任意时间
                String beginTime ="2020-01-01 00:00:00";
                String endTime = "2220-01-01 23:59:59";
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
            }
        List<PortalBrowse> portalBrowses = portalBrowseMapper.selectPortalBrowseByParam(params);
        Map<String, Object> map = new HashMap<>();
        if (portalBrowses.size() == 1) {
            JSONArray objects = JSON.parseArray(portalBrowses.get(0).getBrowseJson());
            List<Integer> numberAll = new ArrayList<>();
            for (int i = 0; i < objects.size(); i++) {
                numberAll.add(objects.getJSONObject(i).getInteger("number"));
            }
            int sum = numberAll.stream().mapToInt(Integer::intValue).sum();
            map.put("pv", sum);
            map.put("ip", objects.size());
        }else if(portalBrowses.size() > 1){
            List<String> ipValues = new ArrayList<>();
            List<Integer> num = new ArrayList<>();
            portalBrowses.forEach(item -> {
                JSONArray objects = JSON.parseArray(item.getBrowseJson());
                for (int i = 0; i < objects.size(); i++){
                    ipValues.add((String) objects.getJSONObject(i).get("ip"));
                    num.add(objects.getJSONObject(i).getInteger("number"));
                }
            });
            map.put("pv", num.stream().mapToInt(Integer::intValue).sum());
            map.put("ip", ipValues.size());
        }else {
            map.put("pv", 0);
            map.put("ip", 0);
        }
        return map;
    }

    /**
     * 封装:ip重复的 number 值 累积相加
     *
     * @param objects
     * @param ip
     * @param ips
     * @return
     */
    private List<Map<String, Object>> getBrowseList(List<Map<String, Object>> objects, String ip, List<String> ips) {
        //ip重复的 number 值 累积相加
        Map<String, Integer> collect1 = objects.stream().collect(Collectors.groupingBy(m -> (String) m.get("ip"), Collectors.summingInt(m -> (Integer) m.get("number"))));
        //得到新集合
        List<Map<String, Object>> arr = new ArrayList<>();
        //如果数据库有当前 ip 则累加1,否则新增一条
        if (ips.stream().anyMatch(ip::equals)) {
            collect1.forEach((k, v) -> {
                Map<String, Object> browseObj = new HashMap<>();
                browseObj.put("ip", k);
                browseObj.put("number", (k.equals(ip)) ? v + 1 : v);  //等于当前 ip + 1
                arr.add(browseObj);
            });
        } else {
            collect1.forEach((k, v) -> {
                Map<String, Object> browseObj = new HashMap<>();
                browseObj.put("ip", k);
                browseObj.put("number", v);
                arr.add(browseObj);
            });
            Map<String, Object> browseObj1 = new HashMap<>();
            browseObj1.put("ip", ip);
            browseObj1.put("number", 1);
            arr.add(browseObj1);
        }
        return arr;
    }

6、技术细节

场景中涉及诸多细节,比如:

  • 当日无人光顾,明日即为空
  • 本周、本月、本年
  • ip 量、pv 量
  • 站群中个站点访问统计
    在这里插入图片描述

7、小结

程序员的世界里,思路决定出路,曾经一味的追求优雅,到头来发现一直在优雅的路上却没有到达优雅的终点,在有限的时间空间里务实合作、解放思想、循序渐进,常态化发展才是正道。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值