统计数据收集与Echarts报表

确认报表统计方案

  • 统计维度
  • 数据收集
  • 数据展示

复杂SQL的编写、Echarts报表的使用

报表统计方案的探讨

统计维度:

  • 统计数值:
  • 总阅读数、总点赞数、今日阅读数、今日点赞数、今日预计阅读数、今日预计阅读增长

统计报表:

  • 30天阅读/点赞趋势图
  • 文档阅读量排名(热门文章)、文档点赞量排名(优质文章)

电子书快照表设计

  • 概念:快照
  • 电子书快照表:一天存储一次快照
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 电子书快照表
drop table if exists `ebook_snapshot`;
create table `ebook_snapshot` (
`id` bigint auto_increment not null comment 'id',
`ebook_id` bigint not null default 0 comment '电子书id',
`date` date not null comment '快照日期',
`view_count` int not null default 0 comment '阅读数',
`vote_count` int not null default 0 comment '点赞数',
`view_increase` int not null default 0 comment '阅读增长',
`vote_increase` int not null default 0 comment '点赞增长',
primary key (`id`)
unique key `ebook_id_date_unique` (`ebook_id`, `date`)
) engine=innodb default charset=utf8mb4 comment='电子书快照表';

电子书快照收集脚本编写

  • 从业务表收集数据的SQL尽量简单,不要影响业务表性能

  • 快照分成两部分
    总量:总阅读数、总点赞数
    增量:今日阅读数、今日点赞数

  • 加唯一键不需要重新执行Mybatis生成器,生成Java代码,Java代码没变化
  • mysql当前日期函数:curdate()
  • mysql日期计算函数:curdate()interval关键字
  • mysql判空函数:ifnull
  • mysql左关联:A left join B on xxx,就看A表,不管B表有没有匹配记录
  • 阿里Java开发规范:SQL 语句中表的别名前加 as,并且以 t1、t2、t3、…的顺序依次命名。

完成电子书快照功能

要在xml里一次执行多个SQL的话,需要为数据库连接增加参数:allowMultiQueries=true

1
2
# 增加数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/wiki?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai&allowMultiQueries=true

生成定时脚本任务

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
@Component
public class EbookSnapshotJob {

private static final Logger LOG = LoggerFactory.getLogger(EbookSnapshotJob.class);

@Resource
private EbookSnapshotService ebookSnapshotService;

@Resource
private SnowFlake snowFlake;

/**
* 自定义cron表达式跑批
* 只有等上一次执行完成,下一次才会在下一个时间点执行,错过就错过
*/
@Scheduled(cron = "0/5 * * * * ?")
public void doSnapshot() {
// 增加日志流水号
MDC.put("LOG_ID", String.valueOf(snowFlake.nextId()));
LOG.info("生成今日电子书快照开始");
Long start = System.currentTimeMillis();
ebookSnapshotService.genSnapshot();
LOG.info("生成今日电子书快照结束,耗时:{}毫秒", System.currentTimeMillis() - start);
}

}

mapper/EbookSnapshotMapperCust.xml

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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.javami.wiki.mapper.EbookSnapshotMapperCust" >

<!--
# 方案一(ID不连续):
# 删除今天的数据
# 为所有的电子书生成一条今天的记录
# 更新总阅读数、总点赞数
# 更新今日阅读数、今日点赞数
# 方案二(ID连续):
# 为所有的电子书生成一条今天的记录,如果还没有
# 更新总阅读数、总点赞数
# 更新今日阅读数、今日点赞数
-->
<update id="genSnapshot">
insert into ebook_snapshot(ebook_id, `date`, view_count, vote_count, view_increase, vote_increase)
select t1.id, curdate(), 0, 0, 0, 0
from ebook t1
where not exists(select 1
from ebook_snapshot t2
where t1.id = t2.ebook_id
and t2.`date` = curdate());

update ebook_snapshot t1, ebook t2
set t1.view_count = t2.view_count,
t1.vote_count = t2.vote_count
where t1.`date` = curdate()
and t1.ebook_id = t2.id;

update ebook_snapshot t1 left join (select ebook_id, view_count, vote_count
from ebook_snapshot
where `date` = date_sub(curdate(), interval 1 day)) t2
on t1.ebook_id = t2.ebook_id
set t1.view_increase = (t1.view_count - ifnull(t2.view_count, 0)),
t1.vote_increase = (t1.vote_count - ifnull(t2.vote_count, 0))
where t1.`date` = curdate();
</update>

</mapper>
  • ebook_snapshot表中插入(ebook_id, date, view_count, vote_count, view_increase, vote_increase),插入得数据查询ebook表获取它的t1.id, curdate(), 0, 0, 0, 0。但是插入到ebook_snapshot的时候有个条件,ebook_snapshot表的id必须要与ebook里面的id一致,并且日期是要当天的。

  • 更新ebook_snapshot这个表格,命名为t1,t1的vote_count和view_count都设置为表ebook的vote_count和view_count。并且要求t1的日期等于当天。t1的ebook_id也等于t2的id。

  • 更新ebook_snapshot表,左连接表示,不管你左边有没有,没用我就设置成0。

首页统计数值功能开发

  • 统计数值:总阅读数、总点赞数、今日阅读数、今日点赞数、今日预计阅读数、今日预计阅读增长
  • 后端获取统计数值接口开发开始
  • 前端统计数值组件展示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 获取首页数值数据:总阅读数、总点赞数、今日阅读数、今日点赞数、今日预计阅读数、今日预计阅读增长 -->
<select id="getStatistic" resultType="com.javami.wiki.resp.StatisticResp">
select
t1.`date` as `date`,
sum(t1.view_count) as viewCount,
sum(t1.vote_count) as voteCount,
sum(t1.view_increase) as viewIncrease,
sum(t1.vote_increase) as voteIncrease
from
ebook_snapshot t1
where
t1.`date` >= date_sub(curdate(), interval 1 day)
group by
t1.`date`
order by
t1.`date` asc;
</select>

集成Echarts

echarts官网
https://echarts.apache.org/zh/index.html

echarts使用示例:
https://echarts.apache.org/zh/tutorial.html#5 分钟上手 ECharts

  • 引入js
  • 定义一块div用于显示报表
  • 初始化echarts实例
  • 准备报表options数据(不同的报表就这块数据不一样)
  • 将options数据放入echarts实例中,显示出报表

30天趋势图功能开发

  • 获取30天前到昨日(不是今日)之间的快照数据
  • 30天趋势图展示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="get30Statistic" resultType="com.javami.wiki.resp.StatisticResp">
select
t1.`date` as `date`,
sum(t1.view_increase) as viewIncrease,
sum(t1.vote_increase) as voteIncrease
from
ebook_snapshot t1
where
t1.`date` between date_sub(curdate(), interval 30 day) and date_sub(curdate(), interval 1 day)
group by
t1.`date`
order by
t1.`date` asc;
</select>

网站优化

首次加载,给出等待提示

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<div style="width: 400px;
height: 100px;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -200px;font-family: YouYuan;
color: rgba(0, 0, 0, 1) !important;
font-size: 20px !important;
font-weight: 400;">
首次加载会较慢,精彩内容马上呈现...
</div>

富文本框图片自适应

1
2
3
4
5
/* 图片自适应 */
.wangeditor img {
max-width: 100%;
height: auto;
}

BUG修复,如果一个电子书初始没有文档,则父文档选择框无法选中“无”

1
2
3
4
5
6
7
8
9

treeSelectData.value = Tool.copy(level1.value);//去掉
//改为:
treeSelectData.value = Tool.copy(level1.value) || [];


treeSelectData.value = Tool.copy(level1.value);
//改为:
treeSelectData.value = Tool.copy(level1.value) || [];

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!