13-2- 统计分析--线索统计--新增线索数量折线图(实现)
13-2- 统计分析--线索统计--新增线索数量折线图(实现)
统计分析--线索统计--新增线索数量折线图
需求: 统计出一段时间内的 新增的线索数量,通过每天新增的线索数量和线索总数量,分析线上线下活动的执行情况
⚠️ 注意 :如果这一天没有数据,需要

- 接口名
/report/cluesStatistics
- 请求方式 get请求
- 参数列表
- 传入参数:
/report/cluesStatistics/2022-03-06/2022-03-13
- beginCreateTime 开始时间
- endCreateTime 结束时间
- 传入参数:
- 返回值:
{
"xAxis":[
"2021-03-11",
"2021-03-12",
"2021-03-13",
"2021-03-14",
"2021-03-15"
],
"series":[
{
"name":"新增线索数量",
"data":[
0, //对应2021-03-11的线索量
0, //对应2021-03-12的线索量
0, //对应2021-03-13的线索量
0, //对应2021-03-14的线索量
0 //对应2021-03-14的线索量
]
},
{
"name":"线索总数量",
"data":[
0, //对应2021-03-11以来累加的总线索量
0, //对应2021-03-12以来累加的总线索量
0, //对应2021-03-13以来累加的总线索量
0, //对应2021-03-14以来累加的总线索量
0 //对应2021-03-15以来累加的总线索量
]
}
]
}
思路步骤:
思路步骤:
- 阅读产品文档(接口名,请求方式,参数列表)
- 根据产品的返回值和接收参数构建VO类
- 编写mapper层操作数据库
- 编写service层操作数据
- 编写controller层接收参数和返回数据
1️⃣ 1.首先阅读接口文档
同上,确定接口的返回参数
2️⃣ 2.根据产品的返回值和接收参数构建VO类 (第一个难点)
1.首先我们来看返回的json
首先看到最外层是一个大括号{}
包裹了整个数据,证明这是一个大对象
,如果最外层是一个[]
包裹则证明是一个数组
好的现在来看这个对象里的属性
第一个属性的属性名是xAxis,对应的类型怎么判断呢?看到对应的值上有""表示这是一个字符串
所以我们可以判断出第一个属性是
List<String> xAxis = new ArrayList<String>();
2.继续来看里面的属性series:[xxx] 那么证明series也是一个数组
我们来看series里每一项的内容
是用{}
来包裹的,证明什么?--->里面的每一个属性
都是一个对象
{
"name":"新增线索数量",
"data":[
0,
0,
0,
0,
0
]
}
name是一个字符串 data也是一个数组因为是[]包裹的,而data里的属性是一个数组,里面的属性是数字,因为没有被""包裹
那么我们应该建立一个对象用来包裹整内部的对象
3.建立一个新的对象用来封装series里的属性
package com.huike.report.domain.vo;
@Data
public class LineSeriesVo {
private String name;
private List<Integer> data =new ArrayList<>();
}
4.最外层的对象也需要构建一个对象
package com.huike.report.domain.vo;
/**
* 折线图
*/
@Data
public class LineChartVo {
private List<String> xAxis = new ArrayList<>();
private List<LineSeriesVo> series = new ArrayList<>();
}
⚠️上述主要考验的是大家对于数据封装的理解,基于json来封装对象的能力 🎉
3️⃣ 3.SQL的编写
基于需求来编写业务
我们先看页面

可以看到需要按照查询出每天的
共计两部分数据,第一部分是新增线索数,第二部分是线索总数量
1)先查询新增线索数
查询线索应该要查询线索表
select * from tb_clue
然后需要确定哪些线索是具体哪天添加的需要使用group by 进行分组
SELECT * from tb_clue group by create_time
这样的sql看起来似乎没有问题,但是由于数据中存储的create_time是带有时分秒的所以这样分组还是不可取
由于需求需要按天来进行统计,所以还需要按天来进行统计
SELECT * FROM tb_clue GROUP BY DATE_FORMAT(create_time,'%y-%m-%d')
但是这样依然有问题,我们在查询的结果集里应该统计的是数量,并且最好是直接把日期也返回了
我们修改一下sql
SELECT count(1) as num,DATE_FORMAT(create_time,'%Y-%m-%d') dd from tb_clue GROUP BY dd
这样基本上就能满足需求了统计出了每天的创建的线索的数量,剩下的就是把时间范围的判断加上
SELECT count(1) AS num, DATE_FORMAT(create_time, '%Y-%m-%d') AS dd
FROM tb_clue
WHERE
date_format(create_time, '%y-%m-%d') >= date_format('2019-05-05', '%y-%m-%d')
AND
date_format(create_time, '%y-%m-%d') <= date_format('2022-05-05', '%y-%m-%d')
GROUP BY dd
sql语句确定了以后编写对应的xml 🎉 🎉
4️⃣ 4.编写mapper层操作数据库
TbClueMapper.xml
<select id="cluesStatistics" resultType="java.util.Map">
SELECT count(1) as num,DATE_FORMAT(create_time,'%Y-%m-%d') dd from tb_clue
<where>
<if test="beginCreateTime != null and beginCreateTime != ''"><!-- 开始创建时间 -->
and date_format(create_time,'%y-%m-%d') >= date_format(#{beginCreateTime},'%y-%m-%d')
</if>
<if test="endCreateTime != null and endCreateTime != ''"><!-- -->
and date_format(create_time,'%y-%m-%d') <= date_format(#{endCreateTime},'%y-%m-%d')
</if>
</where>
GROUP BY dd;
</select>
完成了第一部分的sql查询,剩下的就是了,但是其实所有的线索已经都查询出来了,封装线索的总数放在service中完成,并且假如某天没有数据,我们的sql通过group by来进行分组,但是由于没有数据这一天的数据应该补0,这部分的操作应该在service层中完成
5️⃣ 5.编写service层操作数据
1)首先需要获取时间范围内的每一天
提供一个方法
public static List<String> findDates(String beginTime, String endTime) throws ParseException {
List<String> allDate = new ArrayList();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dBegin = sdf.parse(beginTime);
Date dEnd = sdf.parse(endTime);
allDate.add(sdf.format(dBegin));
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime())) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
allDate.add(sdf.format(calBegin.getTime()));
}
System.out.println("时间==" + allDate);
return allDate;
}
这个方法能获取到时间范围内的每一天并返回一个数组,对应的包装类里的里的属性就拿到了
对应的剩下里的属性还需要进行封装,而series里的属性需要和每一天的数据进行比对,如果有则表示为新增线索数,如果没有则补0,将每之前每一天的结果求和作为总线索总数
这里用到的是stream流的方式进行操作

如果获取的的数据里有值
ReportServiceImpl
@Override
public LineChartVo cluesStatistics(String beginCreateTime, String endCreateTime) {
LineChartVo lineChartVo =new LineChartVo();
try {
List<String> timeList= findDates(beginCreateTime,endCreateTime);
lineChartVo.setxAxis(timeList);
List<LineSeriesVo> series = new ArrayList<>();
List<Map<String,Object>> statistics = clueMapper.cluesStatistics(beginCreateTime,endCreateTime);
LineSeriesVo lineSeriesVo1=new LineSeriesVo();
lineSeriesVo1.setName("新增线索数量");
LineSeriesVo lineSeriesVo2=new LineSeriesVo();
lineSeriesVo2.setName("线索总数量");
int sum = 0;
for (String s : timeList) {
Optional optional= statistics.stream().filter(d->d.get("dd").equals(s)).findFirst();
if(optional.isPresent()){
Map<String,Object> cuurentData= (Map<String,Object>)optional.get();
lineSeriesVo1.getData().add(cuurentData.get("num"));
sum += Integer.parseInt(cuurentData.get("num").toString());
}else{
lineSeriesVo1.getData().add(0);
}
lineSeriesVo2.getData().add(sum);
}
series.add(lineSeriesVo1);
series.add(lineSeriesVo2);
lineChartVo.setSeries(series);
} catch (ParseException e) {
// e.printStackTrace();
}
return lineChartVo;
}
public static List<String> findDates(String beginTime, String endTime)
throws ParseException {
List<String> allDate = new ArrayList();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dBegin = sdf.parse(beginTime);
Date dEnd = sdf.parse(endTime);
allDate.add(sdf.format(dBegin));
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime())) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
allDate.add(sdf.format(calBegin.getTime()));
}
System.out.println("时间==" + allDate);
return allDate;
}
IReportService
/**
* 线索统计
* @param beginCreateTime
* @param endCreateTime
* @return
*/
public LineChartVo cluesStatistics(String beginCreateTime, String endCreateTime);
6️⃣ 6.编写controller层接收参数和返回数据
ReportController
/**
* 线索统计
* @param beginCreateTime
* @param endCreateTime
* @return
*/
@GetMapping("/cluesStatistics/{beginCreateTime}/{endCreateTime}")
public LineChartVo cluesStatistics(@PathVariable String beginCreateTime, @PathVariable String endCreateTime){
return reportService.cluesStatistics(beginCreateTime,endCreateTime);
}