33.数据统计

news2024/12/23 2:23:22

数据统计

后台系统首页中,显示各种统计数据,比如:累计用户数、新增用户数、登录次数等内容。

解决方案

1667896549420

数据库表分析

1667896719523

1667896759988

一、数据采集

需求:

1、探花系统将用户操作日志写入RabbitMQ

2、管理后台获取最新消息,构造日志数据存入数据库

1.搭建RabbitMQ环境

添加依赖

<!--RabbitMQ-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

在nacos配置管理中添加RabbitMQ地址

spring:
 rabbitmq:
    host: 192.168.1.8
    port: 5672
    username: guest
    password: guest    

2.在探花app系统端发送日志消息到RabbitMQ

例如在登录时把用户登录这行为操作记录发送到RabbitMQ

@Autowired
private AmqpTemplate amqpTemplate;
public void login() {
    ………    
    //构造Map集合封装要发送的数据   
    Map<String, Object> msg = new HashMap<>();   
    msg.put(“userId”, UserHolder.getUserId().toString());  
    msg.put(“date",new SimpleDateFormat("yyyy-MM-dd").format(new Date()) );    
	msg.put("type", "0101",);   
    String message = JSON.toJSONString(msg);    
    //发送消息
 	try {      
		amqpTemplate.convertSendAndReceive("tanhua.log.exchange",
                                             "log.user",message);    
	}catch (Exception e) {
		e.printStackTrace();
	}  
	………
}

3.在后台系统admin端监听器处理消息,解析数据,存到数据库

package com.tanhua.admin.listener;

import com.alibaba.fastjson.JSON;
import com.tanhua.admin.mapper.LogMapper;
import com.tanhua.model.domain.Log;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class Loglistener {


    @Autowired
    private LogMapper logMapper;



    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(
                    value = "tanhua.log.queue",
                    durable = "true"
            ),
            exchange = @Exchange(
                    value = "tanhua.log.exchange",
                    type = ExchangeTypes.TOPIC),
            key = "log.*"
    ))
    public void listenerLog(String message){

        try {
            Map<String, Object> map = JSON.parseObject(message);
            //1、获取数据
            String userId = (String) map.get("userId");
            String date = (String) map.get("logTime");
            String type = (String) map.get("type");

            System.out.println(userId);
            System.out.println(date);
            System.out.println(type);


            //2.创建对象封装数据,保存到数据库
            Log log = new Log(Long.valueOf(userId),date,type);

            logMapper.insert(log);
        } catch (NumberFormatException e) {
            System.out.println("保存到数据库失败");
        }
    }
}

3.所用到的实体类

Log

package com.tanhua.model.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Log {
    /**
     * id
     */
    private Long id;
    /**
     * 用户id
     */
    private Long userId;
    /**
     * 操作时间
     */
    private String logTime;

    /**
     * 操作类型,
     * 0101为登录,0102为注册,
     * 0201为发动态,0202为浏览动态,0203为动态点赞,0204为动态喜欢,0205为评论,0206为动态取消点赞,0207为动态取消喜欢,
     * 0301为发小视频,0302为小视频点赞,0303为小视频取消点赞,0304为小视频评论
     */
    private String type;

    /**
     * 登陆地点
     */
    private String place;
    /**
     * 登陆设备
     */
    private String equipment;

    public Log(Long userId, String logTime, String type) {
        this.userId = userId;
        this.logTime = logTime;
        this.type = type;
    }
}

Analysis

package com.tanhua.model.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Analysis{

    private Long id;
    /**
     * 日期
     */
    private Date recordDate;
    /**
     * 新注册用户数
     */
    private Integer numRegistered = 0;
    /**
     * 活跃用户数
     */
    private Integer numActive = 0;
    /**
     * 登陆次数
     */
    private Integer numLogin = 0;
    /**
     * 次日留存用户数
     */
    private Integer numRetention1d = 0;

    private Date created;
}

4.消息发送工具类

package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class MqMessageService {

    @Autowired
    private AmqpTemplate amqpTemplate;

    //发送日志消息
    public void sendLogMessage(Long userId,String type,String key,String busId) {
        try {
            Map map = new HashMap();
            map.put("userId",userId.toString());
            map.put("type",type);
            map.put("logTime",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
            map.put("busId",busId);
            String message = JSON.toJSONString(map);
            amqpTemplate.convertAndSend("tanhua.log.exchange",
                    "log."+key,message);
        } catch (AmqpException e) {
            e.printStackTrace();
        }
    }

    //发送动态审核消息
    public void sendAudiService(String movementId) {
        try {
            amqpTemplate.convertAndSend("tanhua.audit.exchange",
                    "audit.movement",movementId);
        } catch (AmqpException e) {
            e.printStackTrace();
        }
    }
}

二、定时任务

在实际项目开发中,除了Web应用、SOA服务外,还有一类不可缺少的,那就是定时任务调度。定时任务的场景可以说非常广泛:

  • 某些网站会定时发送优惠邮件;
  • 银行系统还款日信用卡催收款;
  • 某些应用的生日祝福短信等。

那究竟何为定时任务调度,一句话概括就是:基于给定的时间点、给定的时间间隔、自动执行的任务

Spring 3.0以后自带了task 调度工具

入门案例:先在服务启动类用@EnableScheduling注解开启定时任务

package com.tanhua.admin;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;


@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@MapperScan("com.tanhua.admin.mapper")
@EnableScheduling//开启定时任务
public class AdminServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class,args);
    }
}

2…定义一个类交由容器管理,定义一个无参无返回值的方法做为定时任务

@Component
public class AnalysisTask {
    /**
     * 配置时间规则
     */
    @Scheduled( cron = "0/20 * * * * ? ")
    public void analysis() throws ParseException {
        //业务逻辑
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("当前时间:"+time);
    }
}

三、定时统计

1. LogMapper

package com.tanhua.admin.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanhua.model.domain.Log;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface LogMapper extends BaseMapper<Log> {


        //可以理解为统计当天注册或者登录的用户
        @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE TYPE=#{type} AND log_time=#{logTime}")
        Integer queryByTypeAndLogTime(@Param("type") String type, @Param("logTime") String logTime); //根据操作时间和类型



        @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE log_time=#{logTime}")
        Integer queryByLogTime(String logTime); //展示记录时间查询


        @Select("SELECT COUNT(DISTINCT user_id)  FROM tb_log WHERE log_time=#{today} AND user_id IN (\n " +
                " SELECT user_id FROM tb_log WHERE TYPE=\"0102\" AND log_time=#{yestoday} \n " +
                ")")
        Integer queryNumRetention1d(@Param("today")  String today,@Param("yestoday") String yestoday); //查询次日留存


}

2.AnalysisService

package com.tanhua.admin.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.admin.mapper.AnalysisMapper;
import com.tanhua.admin.mapper.LogMapper;
import com.tanhua.model.domain.Analysis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class AnalysisService {

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private AnalysisMapper analysisMapper;


    //这个是定时要执行的方法,也就是要定时统计tb_log中的数据
    public void analysisCount() throws ParseException {

        //1.构造查询日期
        String toDay = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String yesterDay = DateUtil.yesterday().toString();
        //2.统计今日登录人数
        Integer logCounts = logMapper.queryByTypeAndLogTime("0101", toDay);
        //3.统计今日注册人数
        Integer regCounts = logMapper.queryByTypeAndLogTime("0102", toDay);
        //4.统计活跃人数
        Integer activeCounts = logMapper.queryByLogTime(toDay);
        //5.统计次日留存人数,昨天注册、今日活跃的用户
        Integer count = logMapper.queryNumRetention1d(toDay, yesterDay);


        //6.先查询analysis表看当天是否已经统计过
        QueryWrapper<Analysis> qw = new QueryWrapper<>();
        qw.eq("record_date", new SimpleDateFormat().parse(toDay));
        Analysis analysis = analysisMapper.selectOne(qw);

        if(analysis != null){
            //此前已经统计过,修改数据
            analysis.setNumLogin(logCounts);
            analysis.setNumRegistered(regCounts);
            analysis.setNumActive(activeCounts);
            analysis.setNumRetention1d(count);

            analysisMapper.updateById(analysis);

        }else {
            //为空,保存数据
            analysis = new Analysis();
            analysis.setNumLogin(logCounts);
            analysis.setNumRegistered(regCounts);
            analysis.setNumActive(activeCounts);
            analysis.setNumRetention1d(count);


            analysis.setRecordDate(new SimpleDateFormat().parse(toDay));
            analysis.setCreated(new Date());

            analysisMapper.insert(analysis);
        }
    }



}

3.TimerCount

package com.tanhua.admin.task;

import com.tanhua.admin.service.AnalysisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class TimerCount {


    @Autowired
    private AnalysisService analysisService;



    /**
     * 每隔20秒钟查询tb_log表,统计数据;创建对象封装数据
     */
    @Scheduled( cron = "0/20 * * * * ? ")
    public void printTimer() throws ParseException {
        String currentTime =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("当前时间:"+currentTime);


        analysisService.analysisCount();
    }
}


import java.util.Date;

@Component
public class TimerCount {

@Autowired
private AnalysisService analysisService;



/**
 * 每隔20秒钟查询tb_log表,统计数据;创建对象封装数据
 */
@Scheduled( cron = "0/20 * * * * ? ")
public void printTimer() throws ParseException {
    String currentTime =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    System.out.println("当前时间:"+currentTime);


    analysisService.analysisCount();
}

}


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot+微信小程序实现的云音乐小程序系统 附带详细运行指导视频

文章目录一、项目演示二、项目介绍三、项目运行截图四、主要代码一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBoot微信小程序框架开发的云音乐微信小程序系统。首先&#xff0c;这是一个前后端分离的项目&#xff…

C语言百日刷题第十五天

前言 今天是刷题第15天&#xff0c;放弃不难&#xff0c;但坚持一定很酷~ 再刷一套模拟题 C语言百日刷题第十五天前言一、选择题二、判断题三、多选题四、填空题五、分析程序题一、选择题 1.下列选项中&#xff0c;不属于开发一个C语言应用程序的具体实现步骤的是&#xf…

为什么网络应用程序是今年的主要攻击媒介之一

网络犯罪分子在绕过最新的网络应用程序防火墙方面的独创性正在将互联网应用程序变成今年增长最快的攻击媒介。面向公众的 Web 应用程序现在是渗透组织边界的最广泛使用的攻击媒介。 根据卡巴斯基全球应急响应团队最近的一份报告&#xff0c;始于 Web 应用程序的攻击从 2020 年…

ocker高级篇1-dockeran安装mysql主从复制

大家好&#xff0c;咱们前面通过十篇的文章介绍了docker的基础篇&#xff0c;从本篇开始&#xff0c;咱们的《docker学习系列》将要进入到高级篇阶段(基础篇大家可以查看之前发布的文章)。 咱们先来介绍&#xff1a;docker复杂方式安装软件。通过按照mysql\redis两个案例来讲解…

XC6SLX100-3FGG484C规格、XC7A15T-2CPG236I产品概述及应用

Spartan-6系列提供领先的系统集成能力&#xff0c;为大批量应用提供最低的总成本。这个由13个成员组成的家族扩展了逻辑单元的密度&#xff0c;从3840个扩展到147443个&#xff0c;功耗仅为之前斯巴达家族的一半&#xff0c;并且具有更快、更全面的连接。 Spartan-6系列基于成熟…

拯救动画卡顿之FLIP

前置知识 什么是FPS FPS是浏览器的每秒的渲染帧数&#xff0c;也就是浏览器切换画面的次数&#xff0c;大多数设备的刷新率都是60FPS&#xff0c;一般来说FPS越低页面就会越卡顿。 什么是像素管道&#xff1f; 像素管道是浏览器单个帧的渲染流水线&#xff0c;如果其中有某…

vue数据双向绑定

5.Vue数据双向绑定 5.1.什么是双向数据绑定 Vue.js 是一个 MVVM 框架&#xff0c;即数据双向绑定&#xff0c;即当数据发生变化的时候&#xff0c;视图也就发生变化&#xff0c;当视图发生变化的时候&#xff0c;数据也会跟着同步变化。这也算是 Vue.js 的精髓之处了。 值得…

[ MessAuto ]: 短信验证码自动填充,理论支持所有浏览器或 APP, Only For Mac

MessAuto 开源地址&#xff1a;https://github.com/LeeeSe/MessAuto MessAuto 是一款 macOS 平台 自动提取 短信验证码并 粘贴回车 的软件&#xff0c;百分百由Rust开发&#xff0c;适用于任何APP。 特点&#xff1a; 轻量&#xff1a;程序占用存储 1.8 M&#xff0c;占用内…

NLP学习笔记(三) GRU基本介绍

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲门控循环单元 (Gated Recurrent Unit, GRU) 文章行文思路如下&#xff1a; 首先通过长短期记忆网络引出为什么需要门控循环单元然后介绍门控循环单元的核心思想与运作方式最后通过简洁的代码深入理解门控循环单元的运作方…

奇舞周刊 476 期:代码在内存中的 “形状”

记得点击文章末尾的“ 阅读原文 ”查看哟~下面先一起看下本期周刊 摘要 吧~奇舞推荐■ ■ ■代码在内存中的 “形状”众所周知&#xff0c;js 的基本数据类型有 number、string、boolean、null、undefined 等。那么问题来了 typeof null 和 typeof undefined 分别是什么呢&…

[附源码]Node.js计算机毕业设计果蔬预约种植管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

[内网渗透]—NTLM网络认证及NTLM-Relay攻击

NTML网络认证 Windows认证分为本地认证和网络认证,当我们开机登录用户账户时,就需要将lsass.exe进程转换的明文密码hash与 sam文件进行比对,这种方式即为——本地认证 而当我们访问同一局域网的一台主机上的SMB共享时,需要提供凭证通过验证才能访问,这个过程就会设计win…

【C++】list 的模拟实现

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;前言&…

Halcon条码和二维码质量评级

现在各行各业的人们都使用条码/二维码从生产阶段到销售点全程追踪他们 的产品。那么怎么验证生产出来的具有可读性&#xff0c;码的质量等级如何呢&#xff1f; 其实ISO行业标准已经给出了如何评估码的质量等级的标准&#xff0c;以下三种主要验证标准用于确定一维条码、二维码…

毕业设计 - 基于Java EE平台项目管理系统的设计与实现【源码+论文】

文章目录前言一、项目设计1. 模块设计2. 实现效果二、部分源码项目工程前言 今天学长向大家分享一个 java web项目: 基于Java EE平台项目管理系统的设计与实现 一、项目设计 1. 模块设计 从管理员角度看: 用户登入系统后&#xff0c;可以修改管理员的密码。同时具有以下功能…

最全的SpringMVC教程,终于让我找到了

1. 为啥要学 SpringMVC&#xff1f; 1.1 SpringMVC 简介 在学习 SpringMVC 之前我们先看看在使用 Servlet 的时候我们是如何处理用户请求的&#xff1a; 配置web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmln…

[附源码]Python计算机毕业设计国际美容会所管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

Jetpack Compose中的动画

Jetpack Compose中没有沿用Android原有的View动画和属性动画&#xff0c;而是新创建了一套全新的动画系统API&#xff0c;这是理所当然的&#xff0c;因为旧的动画系统主要是基于View体系的&#xff0c;而Compose中需要针对的是Composable可组合函数进行处理&#xff0c;那么势…

他文献查到凌晨两点,我用Python十分钟搞定!

大家好&#xff0c;我是爱学习的王饱饱。 对于应届毕业生来说&#xff0c;今年一定是难熬的一年。本来找工作、写论文就已经是两座大山了&#xff0c;还要面临论文无指导的额外压力。 这让我想到了去年毕业的表弟&#xff0c;当时他为了完成论文&#xff0c;摔烂了三个鼠标。…

Jsp服装商城包安装调试

(https://img-blog.csdnimg.cn/78351365dac24f6185cb69ee3a804ba1.png)jsp mysql新季服装商城 功能&#xff1a;前台会员中心后台 前台&#xff1a; 1.服装展示 图文列表 新闻列表 详情 2.注册登录 管理登陆 3.加入购物车 会员中心&#xff1a; 1.个人账户 查看 修改个人…