用户统计开发思路

news2024/12/29 16:24:06

1. 需求分析

所谓用户统计,实际上统计的是用户的数量。通过折线图来展示,上面这根蓝色线代表的是用户总量,下边这根绿色线代表的是新增用户数量,是具体到每一天。所以说用户统计主要统计两个数据,一个是总的用户数量,另外一个是新增用户数量

  • 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数

  • 根据时间选择区间,展示每天的用户总量和新增用户量数据

2. 开发思路

Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。

官网地址:Apache ECharts

前端开发,可以基于Apache ECharts,展示各种各样的图表。

不管是哪种形式的图形,最本质的东西实际上是数据,它其实是对数据的一种可视化展示。

所以后端需要提供符合格式要求的动态数据,然后响应给前端来展示图表。

3. 代码开发

3.1 VO设计

/**
 * 用户数据报告视图对象 (UserReportVO)。
 * 用于封装在指定时间范围内用户数据统计的输出结果,
 * 包含日期列表、用户总量列表、新增用户列表等信息。
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserReportVO implements Serializable {

    /**
     * 日期列表,以逗号分隔的字符串格式表示。
     * 每个日期对应一天的用户统计数据,如"2024-10-01,2024-10-10,2024-10-29"。
     * 在前端展示时可以使用此字段来标识统计数据的时间范围。
     */
    private String dateList;

    /**
     * 用户总量列表,以逗号分隔的字符串格式表示。
     * 对应日期列表中每个日期的累计用户总数,如"200,210,220"。
     * 可以用于分析用户数量的增长趋势。
     */
    private String totalUserList;

    /**
     * 新增用户数量列表,以逗号分隔的字符串格式表示。
     * 对应日期列表中每个日期的新增用户数量,如"20,21,10"。
     * 可以用于分析每日的用户增长情况。
     */
    private String newUserList;

}

3.2 Controller层

/**
 * 用户数据统计接口,提供给前端用于获取在指定时间范围内的用户统计数据。
 *
 * @param begin 开始日期,查询统计数据的起始时间,格式为"yyyy-MM-dd"。
 *              使用 @DateTimeFormat 注解确保请求参数格式正确。
 * @param end   结束日期,查询统计数据的结束时间,格式为"yyyy-MM-dd"。
 *              使用 @DateTimeFormat 注解确保请求参数格式正确。
 * @return 返回封装在 Result 对象中的 UserReportVO 数据,
 *         包含统计信息,如用户增长数量、活跃用户数等。
 */
@GetMapping("/userStatistics")
@ApiOperation("用户数据统计")  // 描述接口功能,便于生成 API 文档
public Result<UserReportVO> userStatistics(
        @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,  // 确保接收参数的格式正确
        @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {  // 确保接收参数的格式正确

    // 调用 reportService 的 getUserStatistics 方法,
    // 使用传入的 begin 和 end 时间段获取用户统计数据
    UserReportVO reportData = reportService.getUserStatistics(begin, end);

    // 将统计数据封装在 Result 对象中并返回,表示调用成功和所请求的统计数据
    return Result.success(reportData);
}

3.3 Service层

reportService层方法实现思路如下:

@Service
public class ReportServiceImpl implements ReportService {

    /**
     * 根据时间区间统计用户数量
     * @param begin 开始日期
     * @param end   结束日期
     * @return 用户统计结果的封装对象 UserReportVO
     */
    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        // 创建一个日期列表,用于存放从开始日期到结束日期的每一天
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);  // 将起始日期加入日期列表

        // 循环遍历,将每一天依次加入日期列表,直到达到结束日期
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);  // 将日期加一天
            dateList.add(begin);  // 加入列表
        }

        // 初始化新增用户数量列表和总用户数量列表
        List<Integer> newUserList = new ArrayList<>(); // 存放每一天的新增用户数量
        List<Integer> totalUserList = new ArrayList<>(); // 存放每一天的累计用户总数

        // 遍历日期列表,逐日统计用户数据
        for (LocalDate date : dateList) {
            // 创建当日的开始时间(beginTime)和结束时间(endTime)
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);  // 当日0点
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);  // 当日23:59:59

            // 查询新增用户数量: 从数据库中统计在beginTime和endTime之间创建的用户数量
            Integer newUser = getUserCount(beginTime, endTime);
            
            // 查询总用户数量: 从数据库中统计在endTime之前创建的所有用户数量
            Integer totalUser = getUserCount(null, endTime);

            // 将统计结果加入相应的列表
            newUserList.add(newUser);
            totalUserList.add(totalUser);
        }

        // 构建并返回 UserReportVO 对象,使用逗号分隔的字符串来格式化各个列表
        return UserReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))  // 日期列表
                .newUserList(StringUtils.join(newUserList, ","))  // 新增用户数量列表
                .totalUserList(StringUtils.join(totalUserList, ","))  // 用户总量列表
                .build();
    }

    /**
     * 根据给定的时间区间统计用户数量
     * @param beginTime 起始时间,用于限定查询的开始范围;传入null表示不限定开始时间
     * @param endTime   结束时间,用于限定查询的结束范围;传入null表示不限定结束时间
     * @return Integer  用户数量,表示在指定时间区间内创建的用户数量
     */
    private Integer getUserCount(LocalDateTime beginTime, LocalDateTime endTime) {
        // 创建一个参数映射,用于传递到查询方法中
        Map<String, LocalDateTime> map = new HashMap<>();
        map.put("begin", beginTime);  // 将起始时间放入映射,键为"begin"
        map.put("end", endTime);      // 将结束时间放入映射,键为"end"
        
        // 调用 userMapper 的方法,传入参数映射以执行数据库查询
        // 返回查询到的用户数量
        return userMapper.countByMap(map);
    }
}

3.4 Mapper层

在UserMapper接口中声明countByMap方法:

/**
     * 根据动态条件统计用户数量
     * @param map
     * @return
     */
    Integer countByMap(Map map);

在UserMapper.xml文件中编写动态SQL:

<!--
    根据指定的时间区间统计用户数量的查询语句。
    该查询语句通过 `begin` 和 `end` 参数的值确定统计范围:
    - 若 `begin` 有值,则统计范围从 `begin` 开始;
    - 若 `end` 有值,则统计范围到 `end` 结束。
    该方法返回在此时间区间内创建的用户数量。
-->
<select id="countByMap" resultType="java.lang.Integer">
    <!-- 执行统计用户数量的查询 -->
    select count(id) from user
    <where>
        <!-- 若参数 `begin` 非空,则增加时间范围条件 -->
        <if test="begin != null">
            and create_time &gt;= #{begin} <!-- 查询用户创建时间在 `begin` 之后或等于 `begin` 的记录 -->
        </if>
        
        <!-- 若参数 `end` 非空,则增加结束时间条件 -->
        <if test="end != null">
            and create_time &lt;= #{end} <!-- 查询用户创建时间在 `end` 之前或等于 `end` 的记录 -->
        </if>
    </where>
</select>

4. 总结

对于图表统计的场景,前端开发,可以基于Apache ECharts,展示各种各样的图表。

不管是哪种形式的图形,最本质的东西实际上是数据,它其实是对数据的一种可视化展示。

所以后端只需要提供符合格式要求的动态数据,然后响应给前端来展示图表。

  • 日期生成

    • getUserStatistics 方法中,使用开始和结束日期生成一个完整的日期列表。通过逐日增加的方式,从 beginend 遍历每一天,以便逐日统计数据。
  • 数据统计

    • 通过循环遍历日期列表,生成每一天的起始时间(beginTime)和结束时间(endTime)。
    • 对于每一天,调用 getUserCount 方法分别获取:
      • 新增用户数:在 beginTimeendTime 之间创建的用户数。
      • 累计用户数:在 endTime 之前创建的所有用户数。
  • 查询逻辑

    • getUserCount 方法中,构造一个 Map 将起始时间和结束时间作为参数传递给 countByMap 查询方法。
    • SQL 查询 countByMap 根据提供的 beginend 参数动态生成 SQL 语句,通过条件判断确保查询范围正确。
  • 结果构建

    • 收集各天的日期、新增用户数和累计用户数列表,构建 UserReportVO 返回结果,将这些列表以逗号分隔的字符串格式化返回,便于前端展示。

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

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

相关文章

我开源了一个短视频应用(Go+React)|DouTok2.0 项目介绍

前言 大家好&#xff0c;这里是白泽&#xff0c;拖更了一段时间&#xff0c;抱歉。在 DouTok2.0 可以初步允许大家接入开发之后&#xff0c;这篇文章才得以出炉。 DouTok&#xff1a;一个开源的 web 端的短视频应用&#xff0c;采用微服务架构&#xff0c;包含前后端&#xff…

JavaEE初阶---网络原理之TCP篇(二)

文章目录 1.断开连接--四次挥手1.1 TCP状态1.2四次挥手的过程1.3time_wait等待1.4三次四次的总结 2.前段时间总结3.滑动窗口---传输效率机制3.1原理分析3.2丢包的处理3.3快速重传 4.流量控制---接收方安全机制4.1流量控制思路4.2剩余空间大小4.3探测包的机制 5.拥塞控制---考虑…

玩转HF/魔搭/魔乐社区

下载依赖 下载指定文件 玩转HF/魔搭/魔乐社区 1. 闯关任务 &#x1f600;Hello大家好&#xff0c;这节课为大家带来“玩转HF/魔搭/魔乐社区”的课程&#xff0c;课程任务请访问闯关任务 2. 课程内容 &#x1f600;Hello大家好&#xff0c;欢迎来到书生大模型实战营第四期…

ReactNative Fabric渲染器和组件(5)

ReactNative Fabric渲染器和组件 简述 Fabric是ReactNative中新架构最核心的模块&#xff0c;本章我们会来了解一下自定义一个Fabric组件&#xff0c;然后在JS文件中声明之后如何&#xff0c;是怎么映射到原生构建一个View的。 关于Fabric架构理念官网已经有说明了&#xff0…

DataSophon集成ApacheImpala的过程

注意: 本次安装操作系统环境为Anolis8.9(Centos7和Centos8应该也一样) DataSophon版本为DDP-1.2.1 整合的安装包我放网盘了: 通过网盘分享的文件&#xff1a;impala-4.4.1.tar.gz等2个文件 链接: https://pan.baidu.com/s/18KfkO_BEFa5gVcc16I-Yew?pwdza4k 提取码: za4k 1…

计算机网络-MSTP概述

一、RSTP/STP的缺陷与不足 前面我们学习了RSTP对于STP的一些优化与快速收敛机制。但在划分VLAN的网络中运行RSTP/STP&#xff0c;局域网内所有的VLAN共享一棵生成树&#xff0c;被阻塞后的链路将不承载任何流量&#xff0c;无法在VLAN间实现数据流量的负载均衡&#xff0c;导致…

字节青训-兔群繁殖之谜

问题描述 生物学家小 R 正在研究一种特殊的兔子品种的繁殖模式。这种兔子的繁殖遵循以下规律&#xff1a; 每对成年兔子每个月会生育一对新的小兔子&#xff08;一雌一雄&#xff09;。新生的小兔子需要一个月成长&#xff0c;到第二个月才能开始繁殖。兔子永远不会死亡。 小 R…

uniapp写移动端,适配苹果手机底部导航栏,ios安全区问题,苹果手机遮挡底部信息,uview的u-action-sheet组件

手机上有很多组件&#xff0c;需要手机底部弹窗来做选择,picker选择器&#xff0c;select列选择器呀这些&#xff0c;在苹果手机上会被底部nav遮住 采用了好几种配置的方式&#xff0c;多多少少都不太行&#xff0c;还是采用css来做吧&#xff0c;但是css来写想让它生效&#x…

从零开始使用Surya-OCR最新版本0.6.1——最强文本检测模型:新添表单表格检测识别

目录 一、更新概述 二、环境安装 1.基础环境配置 2.模型参数下载 3.参数地址配置——settings.py 三、指令使用 1.命令指令运行 一、更新概述 surya项目Github地址&#xff1a;https://github.com/VikParuchuri/surya 号称今年最强OCR的surya近期迎来新的更新&#xff0c;Vik…

深入理解C++ Lambda表达式:语法、用法与原理及其包装器的使用

深入理解C Lambda表达式&#xff1a;语法、用法与原理及其包装器的使用 lambda表达式C98中的一个例子lambda表达式语法lambda表达式各部分说明捕获列表说明 函数对象与lambda表达式 包装器function包装器 bind &#x1f30f;个人博客主页&#xff1a; 个人主页 本文深入介绍了…

nacos介绍

Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它致力于提供发现、配置和管理微服务的统一解决方案&#xff0c;以支持构建云原生应用。 服务发现&#xff08;Service Discovery&#xff09;&#xff1a; Nacos 支持服务的动态注册与发现&#xff…

【操作系统实验课】Git操作基础

1. Windows系统 1.1. Git下载安装 下载 Git 访问 Git 官方网站:https://git-scm.com/。 在页面中找到适合 Windows 系统的下载链接,一般会有 “Windows” 字样的按钮,点击下载安装程序。 安装 Git 运行下载的安装程序。 在安装向导中,一般可以选择默认设置,也可以根…

搜维尔科技:Xsens动作捕捉、Manus数据手套和Faceware面部捕捉技术集成,应用于元宇宙数字人制作解决方案

Xsens动作捕捉、Manus数据手套和Faceware面部捕捉技术集成&#xff0c;能够实现非常逼真且高效的数字人动作和表情捕捉&#xff01; 硬件连接与数据传输方面&#xff1a; 1.Xsens与Manus的集成&#xff1a;Xsens惯性动作捕捉系统通常可以与Manus的数据手套直接集成。Xsens主要…

MQTTnet4.3.x服务端+客户端实例测试(服务端和客户端方法及参数)

一、示例 目的&#xff1a;学习MQTTnet4.x使用方法&#xff0c;网上很多方法都是3.x版本介绍 二、方法调用 2.1 服务端 2.2 客户端 结合上篇博文&#xff0c;实现与多客户端进行交流&#xff08;实现在线客服功能&#xff09; 当然还有其他方法。之前曾写过相关MQTT文章&#…

【WebDriver】浏览器驱动下载及其配置

一、Windows电脑环境搭建-Chrome浏览器 行业内&#xff0c;Chrome (谷歌) 浏览器对于自动化程序来讲是比较稳定的. 自动化程序推荐使用 Chrome 浏览器的原因有几个&#xff1a; 开发者工具&#xff1a;Chrome 提供强大的开发者工具&#xff0c;方便调试和测试自动化脚本。 稳…

用jest做单元测试不得不知道的起手式配置,闭坑指南

做单元测试有很多的工具&#xff0c;今天在一个老项目中看到的用的工具是用的jest做的单元测试&#xff0c;特尝试更新下&#xff0c;遇到不少的问题。 相关依赖配置文件 npm install --save-dev jestpackage.json {"name": "jest-app","version&qu…

【Android】多渠道打包配置

目录 简介打包配置签名配置渠道配置配置打包出来的App名称正式包与测试包配置 打包方式开发工具打包命令行打包 优缺点 简介 多渠道打包 是指在打包一个 Android 应用时&#xff0c;一次编译生成多个 APK 文件&#xff0c;每个 APK 文件针对一个特定的渠道。不同的渠道可能代表…

Linux初学者导引:掌握主要命令与操作系统基础(第一天)

本文使用的工具&#xff1a;CentOS。 1.打开终端&#xff1a; 鼠标单击右键&#xff0c;选择“在终端打开(E)”选项。 2.命令行基础 常用命令&#xff1a; &#xff08;1&#xff09;ls:列出目录内容 列出当前目录或指定目录中的文件和文件夹。 基本用法&#xff1a;ls常…

块设备驱动的基本概念

块设备与字符设备 块设备只能以块为单位接收输入和返回输出&#xff0c;而字符设备则以字节为单位。大多数设备是字符设备&#xff0c;因为它们不需要缓冲而且不以固定块大小进行操作&#xff1b;字符设备只能被顺序读写&#xff0c;而块设备可以随机访问。 块设备对于I/O请求…

【力扣 + 牛客 | SQL题 | 每日4题】牛客大厂面试真题W3,W10

1. 牛客大厂面试真题SQLW3&#xff1a;分析客户逾期情况 1.1 题目&#xff1a; 描述 有贷款信息表&#xff1a;loan_tb&#xff08;agreement_id&#xff1a;合同id&#xff0c;customer_id&#xff1a;客户id&#xff0c;loan_amount&#xff1a;贷款金额&#xff0c;pay_a…