欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > Day11-苍穹外卖(数据统计篇)

Day11-苍穹外卖(数据统计篇)

2025/5/19 13:54:54 来源:https://blog.csdn.net/a6543665/article/details/148014930  浏览:    关键词:Day11-苍穹外卖(数据统计篇)

前言:

今天写day11的内容,主要讲了四个统计接口的制作。看起来内容较多,其实代码逻辑都是相似的,这里我们过一遍。

今日所学:

  • Apache ECharts
  • 营业额统计
  • 用户统计
  • 订单统计
  • 销量排行统计

1. Apache ECharts

1.1 介绍

Apache ECharts 是一个功能强大、易于使用的数据可视化工具,适用于多种场景下的数据展示需求。通过简单的配置和灵活的定制,用户可以快速生成美观且交互性强的图表,提升数据分析和展示的效果。

总结:

Apache ECharts 是一个前端数据可视化库,适用于Web端的数据展示和分析

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

1.2 使用流程:

1.下载echarts.js

这边黑马的资料中给我们准备好了

2.在前端的代码中引用

打开echartsDemo.html文件代码,可以看到已成功引入了echarts.js

运行这个html文件

2.营业额统计

需求分析

业务规则:

1.营业额指的是订单状态为完成的订单金额合计

2.X轴表示日期,Y轴表示营业额

3. 根据时间选择区间,展示每天的营业额数据

请求参数是开始时间和结束时间,这里注意传给前端的dataList和turnoverList都要是String类型的数据

代码展示

Controller层:

这里注意begin,end是LocalData变量,传入的时候要指定时间格式

service层:

这里具体的代码逻辑是:

1.先是定义两个arrayList容器用于后续储存每日的日期还有相应的营业额

2.while循环储存从开始(begin)到结束(end)的每一天日期数据

3.将每一天的日期数据(LocalData变量)转换成(LocalDataTime变量),分别取极小值(00:00:00)和极大值(23:59:5999)

4.调用Ordermapper,执行如下SQL语句:

select sum(amount) from Orders where order_time > beginTime(一天的极小值) and order_time < endTime(一天的极大值) and status = 5(已完成)

注意下这里传给mapper的数据是由map储存的

/*** 指定时间内的营业额* @param begin* @param end* @return*/
@Override
public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {// 用于储存begin,end范围内每天的日期List<LocalDate> dateList = new ArrayList<>();List<Double> turnoverList = new ArrayList<>();dateList.add(begin);while(!begin.equals(end)) {// 指定日期的后一天begin = begin.plusDays(1);dateList.add(begin);}for (LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);Map map = new HashMap();map.put("beginTime", beginTime);map.put("endTime", endTime);map.put("status", Orders.COMPLETED);Double amount = orderMapper.getSumBymap(map);amount = amount == null ? 0.0 : amount;turnoverList.add(amount);}return TurnoverReportVO.builder().turnoverList(StringUtils.join(turnoverList, ",")).dateList(StringUtils.join(dateList, ",")).build();
}

mapper层

<select id="getSumBymap" resultType="java.lang.Double">select sum(amount) from orders<where><if test="begin != null">and order_time &gt; #{beginTime}</if><if test="end != null">and order_time &lt; #{endTime}</if><if test="status != null">and status = #{status}</if></where>
</select>

运行展示:

问题

这里我遇到的问题是几个:

1.路径写错了(写成另一个接口的了),导致前端图表一直展示不出来,改了挺久的

2.StringUtils包导错了

这里要注意导入的是我标注的那个包,而不是我最上面注释掉的那个

3.这里要注意要写的是Double,而不是double.Double是包装类,是一种类,存在null值,而double是一种基本数据类型,是不存在null值的

3.用户统计

需求分析

业务规则:

  • 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
  • 根据时间选择区间,展示每天的用户总量和新增用户量数据

这里的传入参数和返回数据跟营业额统计格式上基本是一致的:传入开始日期和结束日期,

返回数据也都是要String类型

代码展示:

Controller层

@ApiOperation("用户统计")
@GetMapping("/userStatistics")
public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){UserReportVO userReportVO = reportService.userStatistics(begin, end);return Result.success(userReportVO);
}

这里同样注意传入的LocalData类型的数据要用@DataTimeFormat规定时间格式

Service层

具体逻辑:

1.定义三个ArrayList格式的数据,分别用于储存每一天的时间,每一天的用户总量,每一天的用户增量

2.while循环得到开始日期到结束日期之间每天的日期

3..将每一天的日期数据(LocalData变量)转换成(LocalDataTime变量),分别取极小值(00:00:00)和极大值(23:59:5999)

4.调用mapper,执行相应的语句,得到每一天的用户总量和用户新增量

这里注意用户总量只要查询endTime就行了,用户新增量再查询beginTime和endTime之间创建的用户,具体SQL执行逻辑:

select count(id) from user where create_time < endTime and create_time > beginTime(求用户新增量的时间再传入相应参数)

mapper参数还是由map传入

/*** 用户统计* @param begin* @param end* @return*/
@Override
public UserReportVO userStatistics(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> totalUserList = new ArrayList<>();List<Integer> newUserList = new ArrayList<>();for(LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);Map map = new HashMap();map.put("endTime", endTime);Integer userNum = userMapper.countByMap(map);map.put("beginTime", beginTime);Integer newUserNum = userMapper.countByMap(map);userNum = userNum == null ? 0 : userNum;totalUserList.add(userNum);newUserList.add(newUserNum);}return UserReportVO.builder().dateList(StringUtils.join(dateList,",")).totalUserList(StringUtils.join(totalUserList, ",")).newUserList(StringUtils.join(newUserList, ",")).build();
}

mapper层

<select id="countByMap" resultType="java.lang.Integer">select count(id) from user<where><if test="beginTime != null">and create_time &gt; #{beginTime}</if><if test="beginTime != null">and create_time &lt; #{endTime}</if></where>
</select>

运行展示:

4.订单统计

需求分析

业务规则:

  • 有效订单指状态为 “已完成” 的订单
  • 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
  • 根据时间选择区间,展示每天的订单总数和有效订单数
  • 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%

跟上两个接口传入参数返回数据格式上是一致的,请求参数是开始时间和结束时间,传给前端的orderCountList和validOrderCountList都要是String类型的数据

代码展示

Controller层

/*** 订单统计接口* @param begin* @param end* @return*/
@ApiOperation("订单统计接口")
@GetMapping("/ordersStatistics")
public Result<OrderReportVO> orderStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end
){log.info("订单统计接口{},{}", begin, end);OrderReportVO orderReportVO = reportService.orderStatistics(begin, end);return Result.success(orderReportVO);
}

这里注意begin,end是LocalData变量,传入的时候要指定时间格式

service层

具体执行逻辑:

1.先是定义三个arrayList容器,分别用于储存每日的日期,每日的订单数,以及有效订单数

2.再定义两个total(Integer),用来统计订单总数和有效订单总数

3.while循环储存从开始(begin)到结束(end)的每一天日期数据

4.将每一天的日期数据(LocalData变量)转换成(LocalDataTime变量),分别取极小值(00:00:00)和极大值(23:59:5999)

4.调用Ordermapper,执行如下SQL语句:

select count(id) from Orders where order_time > beginTime(一天的极小值) and order_time < endTime(一天的极大值) and status = 5(已完成->当统计有效订单再传入相应参数)

每统计一天的,加入相应的容器和总数中

注意下这里传给mapper的数据是由map储存的

/*** 订单统计* @param begin* @param end* @return*/
@Override
public OrderReportVO orderStatistics(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> orderCountList = new ArrayList<>();Integer totalOrderCount = 0;List<Integer> vaildOrderCountList = new ArrayList<>();Integer VaildOrderCount = 0;for(LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);Map map = new HashMap();map.put("beginTime", beginTime);map.put("endTime", endTime);Integer orderCount = orderMapper.CountByMap(map);orderCountList.add(orderCount);totalOrderCount += orderCount;map.put("status",Orders.COMPLETED);Integer vaildCount = orderMapper.CountByMap(map);vaildOrderCountList.add(vaildCount);VaildOrderCount += vaildCount;}return OrderReportVO.builder().orderCountList(StringUtils.join(orderCountList, ",")).totalOrderCount(totalOrderCount).validOrderCount(VaildOrderCount).validOrderCountList(StringUtils.join(vaildOrderCountList, ",")).dateList(StringUtils.join(dateList,",")).build();
}

mapper层

<select id="CountByMap" resultType="java.lang.Integer">select count(id) from orders<where><if test="beginTime != null">and order_time &gt; #{beginTime}</if><if test="endTime != null">and order_time &lt; #{endTime}</if><if test="status != null">and status = #{status}</if></where>
</select>

运行展示:

5. 销量排行统计

需求分析:

业务规则:

  • 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
  • 基于可视化报表的柱状图降序展示商品销量
  • 此处的销量为商品销售的份数

请求参数是开始时间和结束时间,这里注意传给前端的nameList和numberList都要是String类型的数据

代码展示:

controller层

/*** 销量排行展示* @param begin* @param end* @return*/
@ApiOperation("销量排名展示")
@GetMapping("/top10")
public Result<SalesTop10ReportVO> salesTop10Statistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end
){log.info("销量排名展示{},{}", begin,end);SalesTop10ReportVO salesTop10ReportVO = reportService.top10(begin, end);return Result.success(salesTop10ReportVO);
}

这里注意begin,end是LocalData变量,传入的时候要指定时间格式

service层:

具体实现逻辑:

1.这里我们项目有一个专门封装了菜品名称和菜品销量的dto(GoodsSalesDTO),所以我们不用专门再创建容器去记录数据

2.因为销量统计是统计我们这一整段时间(从begin到end)的菜品销量,所以不用在遍历每一天的订单数据

3.将LocalDate变量数据转换成LocalDataTime,求得这一段时间的极小值和极大值

4.调用ordermapper,因为涉及到订单(orders)的下单时间和订单详情(order_detail)的菜品数据,所以这里我采用join进行连接查询,具体SQL语句为:

select od.name as name , coount(od.name) as number from orders o join order_detail od

on od.order_id = o.id

where status = 5(查看已下单的数据) and order_time > beginTime and order_time < endTime

group by name  order by name desc limit 0, 10(查询销量前十的菜品)

5.得到相应的数据后使用stream流进行遍历,最后用StringUtils.join连接起来

/*** 销量统计* @param begin* @param end* @return*/
@Override
public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getByNameNum(beginTime, endTime);String nameList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList()), ",");String numList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList()), ",");return SalesTop10ReportVO.builder().nameList(nameList).numberList(numList).build();
}

mapper层

<select id="getByNameNum" resultType="com.sky.dto.GoodsSalesDTO">select od.name as name, sum(od.name) as number from orders o join order_detail odon  o.id = od.order_idand o.status = 5<where><if test="beginTime != null">and order_time &gt; #{beginTime}</if><if test="endTime != null">and order_time &lt; #{endTime}</if></where>group by nameorder by number desclimit 0, 10
</select>

运行展示:

最后:

今天的分享就到这里。如果我的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!(๑`・ᴗ・´๑)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词