苍穹外卖项目笔记(11)— 数据统计-图形报表

 前言

代码链接:

Echo0701/take-out⁤ (github.com)

1 Apache ECharts

基于 Javascript 的数据可视化图标库,提供直观生动可交互可个性定制的数据可视化图表

  • 柱形图
  • 饼形图
  • 折线图

【核心】通过直观的图表来展示数据。使用 Echarts ,重点在于研究当前图表所需的数据格式,通常是需要后端提供符合格式要求的动态数据,然后响应给前端来展示图表。

2 营业额统计

2.1 需求分析和设计

产品原型

接口设计

【注】这里的 data 数据格式需要适应前端 ,前端需要什么格式数据就返回什么格式数据

设计 VO 

2.2 代码开发

ReportController.java

@RestController
@RequestMapping("/admin/report")
@Api(tags = "数据统计相关接口")
@Slf4j
public class ReportController {@Autowiredprivate ReportService reportService;/*** 营业额统计* @param begin* @param end* @return*/@GetMapping("/turnoverStatistics")@ApiOperation("营业额统计")public Result<TurnoverReportVO> turnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("在这个时间区间的营业额数据统计:{}, {}", begin, end);return Result.success(reportService.getTurnoverStatistics(begin, end));}
}

ReportServiceImpl.java

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrderMapper orderMapper;/*** 统计指定时间区间内的营业额数据* @param begin* @param end* @return*/public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {//1、计算日期,把开始日期到结束日期放到一个集合里面,再把这个集合的每个元素取出来中间添加“,”放入到 dataList 里面去List<LocalDate> dateList = new ArrayList<>();  // 用于存放begin-end范围内的每天的日期dateList.add(begin);while (!begin.equals(end)) {//日期计算,计算指定日期的后一天对应的日期begin = begin.plusDays(1);dateList.add(begin);}//2、查询 datalist 里面的每天的营业额数据,最后替换为字符串并加“,”List<Double> turnoverList = new ArrayList<>();for (LocalDate date : dateList) {//查询data 日期对应的营业额数据,营业额是指状态为“已完成”的订单金额合计(查询订单表,每个订单都含有金额字段)//date: LocalData ,只有年月日, order_time: LocalDataTime ,既有年月日又有时分秒//order_time 应该是大于当天的最小时间,小于当天的最大时间LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN); //LocalTime.MIN: '00:00' ,对应的就是零点零分LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);   //'23:59:59.999999999'//select sum(amount) from orders where order_time > ? and order_time < ? and status = 5 (已完成)Map map = new HashMap();map.put("beginTime", beginTime);map.put("endTime", endTime);map.put("status", Orders.COMPLETED);  // 状态 5Double turnover = orderMapper.sumByMap(map);//这里的营业额如果为0的话,实际上返回的是空,但是我们需要数据0,所以这里需要判断turnover =  turnover == null ? 0.0 :turnover;turnoverList.add(turnover);}return TurnoverReportVO.builder().dateList(StringUtils.join(dateList,",")).turnoverList(StringUtils.join(turnoverList, ",")).build();}
}

 OrderMapper.xml

    <select id="sumByMap" resultType="java.lang.Double">select sum(amount) from orders <where><!--  > 的转义字符 :&gt;  < 的转义字符:   --><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>

3 用户统计 

3.1 需求分析和设计

用户统计包括两部分内容:① 当日新增用户数量; ② 截止到当日的用户总量

产品原型

接口设计 

3.2 代码开发

ReportController.java

@RestController
@RequestMapping("/admin/report")
@Api(tags = "数据统计相关接口")
@Slf4j
public class ReportController {@Autowiredprivate ReportService reportService;/*** 用户数据统计* @param begin* @param end* @return*/@ApiOperation("用户数据统计")@GetMapping("/userStatistics")public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("在这个时间区间的用户数据统计:{}, {}", begin, end);return Result.success(reportService.getuserStatistics(begin, end));}
}

ReportServiceImpl.java

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {@Autowiredprivate UserMapper userMapper;/*** 统计指定时间区间内的用户数据* @param begin* @param end* @return*/public UserReportVO getuserStatistics(LocalDate begin, LocalDate end) {//1、计算日期,把开始日期到结束日期放到一个集合里面,再把这个集合的每个元素取出来中间添加“,”放入到 dataList 里面去List<LocalDate> dateList = new ArrayList<>();  // 用于存放begin-end范围内的每天的日期dateList.add(begin);while (!begin.equals(end)) {//日期计算,计算指定日期的后一天对应的日期begin = begin.plusDays(1);dateList.add(begin);}//2、存放每天的新用户集合 select count(id) from user where create_time < ? and create_time > ?List<Integer> newUserList = new ArrayList<>();//3、存放每天的总用户集合 select count(id) from user where create_time < ?//写一个动态sql兼容这两种情况就可以了List<Integer> totalUserList = 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 totalUser = userMapper.countByMap(map);totalUserList.add(totalUser);//新增用户数量map.put("beginTime", beginTime);Integer newUser = userMapper.countByMap(map);newUserList.add(newUser);}return UserReportVO.builder().dateList(StringUtils.join(dateList,",")).newUserList(StringUtils.join(totalUserList,",")).totalUserList(StringUtils.join(newUserList, ",")).build();}
}

  UserMapper.xml

    <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="endTime != null">and create_time &lt; #{endTime}</if></where></select>

4 订单统计

4.1 需求分析和设计

订单统计包括两部分内容:① 总的订单数; ② 有效订单数(状态为已完成)

产品原型

接口设计 

设计 VO

4.2 代码开发

ReportController.java

@RestController
@RequestMapping("/admin/report")
@Api(tags = "数据统计相关接口")
@Slf4j
public class ReportController {@Autowiredprivate ReportService reportService;/*** 订单统计* @param begin* @param end* @return*/@ApiOperation("订单统计")@GetMapping("/ordersStatistics")public Result<OrderReportVO> ordersStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("在这个时间区间的订单数据统计:{}, {}", begin, end);return Result.success(reportService.getOrderStatistics(begin, end));}
}

ReportServiceImpl.java

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrderMapper orderMapper;/*** 统计指定时间区间内的订单数据* @param begin* @param end* @return*/public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) {//准备日期列表List<LocalDate> dateList = new ArrayList<>();  // 用于存放begin-end范围内的每天的日期dateList.add(begin);while (!begin.equals(end)) {//日期计算,计算指定日期的后一天对应的日期begin = begin.plusDays(1);dateList.add(begin);}//存放每天的订单总数List<Integer> orderCountList = new ArrayList<>();//存放每天的有效订单总数List<Integer> validOrderCountList = new ArrayList<>();//遍历 dateList 集合,查询每天的有效订单数和订单总数for (LocalDate date : dateList) {//时间格式转换LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);//查询每天的订单总数 select count(id) from orders where order_time < ? and order_time > ?Integer orderCount = getOrderCount(beginTime, endTime, null);//查询每天的有效订单数  select sum(id) from orders where order_time < ? and order_time > ? and status = ? (Orders.COMPLETED)Integer validOrderCount = getOrderCount(beginTime, endTime, Orders.COMPLETED);//存放数据orderCountList.add(orderCount);validOrderCountList.add(validOrderCount);}//计算时间区间内的订单总数量,可以通过 for 循环遍历上面两个集合,进行累加,也可以利用 stream 流来进行累加Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();//计算时间区间内的有效订单数量Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();//计算订单完成率Double orderCompletionRate = 0.0;if (totalOrderCount != 0){orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;}return OrderReportVO.builder().dateList(StringUtils.join(dateList,",")).orderCountList(StringUtils.join(orderCountList, ",")).validOrderCountList(StringUtils.join(validOrderCountList, ",")).totalOrderCount(totalOrderCount).validOrderCount(validOrderCount).orderCompletionRate(orderCompletionRate).build();}/*** 根据条件统计订单数量* @param beginTime* @param endTime* @param status* @return*/private Integer getOrderCount(LocalDateTime beginTime, LocalDateTime endTime, Integer status) {Map map = new HashMap();map.put("beginTime", beginTime);map.put("endTime",endTime);map.put("status", status);Integer count = orderMapper.countByMap(map);return count;}
}

 OrderMapper.xml

    <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 销量排名 Top10

5.1 需求分析和设计

产品原型

接口设计 

VO 设计 

5.2 代码开发

ReportController.java

@RestController
@RequestMapping("/admin/report")
@Api(tags = "数据统计相关接口")
@Slf4j
public class ReportController {@Autowiredprivate ReportService reportService;/*** 销量排名前10菜品统计* @param begin* @param end* @return*/@ApiOperation("销量排名前10菜品统计")@GetMapping("/top10")public Result<SalesTop10ReportVO> top10(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("在这个时间区间的销量排名前10菜品统计:{}, {}", begin, end);return Result.success(reportService.getSalesTop10(begin, end));}}

ReportServiceImpl.java

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrderMapper orderMapper;/*** 销量排名前10菜品统计* @param begin* @param end* @return*/public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);List<GoodsSalesDTO> salesTop10 = orderMapper.getSalesTop10(beginTime, endTime);List<String> names= salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());String nameList = StringUtils.join(names, ",");List<Integer> numbers = salesTop10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());String numberList = StringUtils.join(numbers, ",");return SalesTop10ReportVO.builder().nameList(nameList).numberList(numberList).build();}
}

 OrderMapper.xml

    <select id="getSalesTop10" resultType="com.sky.dto.GoodsSalesDTO">select od.name,sum(od.number) numberfrom order_detail od, orders owhere od.order_id = o.id and o.status = 5<if test="begin != null">and o.order_time &gt; #{begin}</if><if test="end != null">and o.order_time &lt; #{end}</if>group by od.nameorder by number desclimit 0, 10</select>

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

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

相关文章

算法——位运算

常见位运算总结 基础位运算 << >> ~与&&#xff1a;有0就是0或|&#xff1a;有1就是1异或^&#xff1a;相同为0&#xff0c;相异为1 / 无进位相加 给一个数n&#xff0c;确定他的二进制表示中的第x位是0还是1 让第x位与上1即可先让n右移x位&上一个1&#…

java反序列化数据过滤

前言&#xff1a; 反序列化漏洞的危害稍微了解一点的都知道&#xff0c;如果能找到前端某处存在反序列化漏洞&#xff0c;那基本上距离拿下服务器仅一步之遥&#xff0c;这个时候我们可以通过继承ObjectInputFilter添加tFilter实现对所有反序列化类的校验&#xff0c;当然这个需…

嵌入式行业是否会面临中年危机?

今日话题&#xff1a;嵌入式行业是否会面临中年危机&#xff1f;事实上&#xff0c;无论你在哪个行业工作&#xff0c;都可能面临下岗风险。因此&#xff0c;我的建议是选择一个有前景、发展空间大的行业和方向&#xff0c;并不断提升自己的技能价值。为了帮助你在嵌入式领域取…

perl处理json的序列化和反序列化

perl可以使用JSON模块很方便的处理json的序列化和反序列化。先来一段简单的例子&#xff1a; #! /usr/bin/perl use v5.14; use JSON; use IO::File;my $info {id > 1024,desc > hello world,arry > [1, 2, 3, 4, 5],obj > {char > [ A, B, C ]} };say to_jso…

个人介绍以及毕业去向

CSDN陪伴我从大一到大四&#xff0c;后面也会接着用 写一点大学四年的总结 #总结#理工科#留学 211大学 弃保出国 智能科学与技术 均分88.9 EI论文一篇 数学竞赛和数学建模均为省二 大创评为国家级 全国大学生计算机设计大赛国家三等奖 百度Paddle、大疆RoboMaster、Phytium Te…

2 mysql主从复制配置

1、节点以及网络配置 前置条件&#xff1a; 已经在linux上安装好了一主一从或者一主多从的mysql 2、具体配置 主服务器 172.20.0.2 从服务器 172.20.0.3 首先主机mysql配置&#xff1a; 打开mysqld.cnf&#xff1a; 添加如下配置&#xff1a; # 主服务器ID 必须唯一 serve…

硕士论文写的重复率 PaperBERT

大家好&#xff0c;今天来聊聊硕士论文写的重复率&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 硕士论文写的重复率 1. 硕士论文的重要性 硕士论文是硕士阶段最重要的学术成果之一&#xff0c;它不仅…

基于ssm四六级报名与成绩查询系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对四六级报名信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性…

UE4 图片环形轮播 蓝图

【需求】 图片环形轮播 任意图片之间相互切换 切换图片所需时间均为1s 两个图片之间切换使用就近原则 播放丝滑无闪跳 【Actor的组成】 每个图片的轴心都在原点 【蓝图节点】

记录 | linux安装Manim

linux 安装 Manim sudo apt update sudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev ffmpeg sudo apt install xdg-utilsconda create manim_py39 python3.9 conda activate manim_py39pip install manim安装好环境后来测试一个例程&#xff0c;…

ECS省钱指南来啦!万字长文教你如何选择与业务形态最匹配的付费方式

为了更好的帮助用户在使用DevOps缩短开发周期、提升业务效率的同时&#xff0c;也能让业务保持稳定、安全、可靠&#xff0c;且低成本的持续运营&#xff0c;阿里云弹性计算团队独家出品的【弹性计算技术公开课_CloudOps云上运维季】正式启动。阿里云弹性计算内部13位产品&…

接口测试 — 1.接口和接口文档概念

1、接口的概念 接口又叫API&#xff0c;全称application programming interface&#xff1a;应用程序接口&#xff08;规范&#xff09;&#xff0c;也就是我们经常会听说Web接口&#xff0c;APP接口。 详细说明&#xff1a; APP是一种基于C/S架构的应用程序&#xff0c;如抖音…

MYSQL练题笔记-子查询-电影评分

一、题目相关内容 1&#xff09;相关的表 2&#xff09;题目 3&#xff09;帮助理解题目的示例&#xff0c;提供返回结果的格式 二、自己初步的理解 1.字典序是指从前到后比较两个字符串大小的方法。 首先比较第1个字符&#xff0c;如果不同则第1个字符较小的字符串更小&…

Retrofit嵌套请求与适配器

一、前言&#xff1a; 1. retrofit嵌套请求 在实际开发中&#xff0c;可能会存在&#xff1a;需要先请求A接口&#xff0c;在请求B接口的情况&#xff0c;比如进入“玩android”网页请求获取收藏文章列表&#xff0c;但是需要先登录拿到Cookie才能请求搜藏文章几口&am…

day01、什么是数据库系统?

数据库系统介绍 1.实例化与抽象化数据库系统2.从用户角度看数据库管理系统的功能2.1 数据库定义功能2.2 数据库操纵2.3 数据库控制2.4 数据库维护功能2.5 数据库语言与高级语言 3.从系统&#xff1a;数据库管理系统应具有什么功能 来源于战德臣的B站网课 1.实例化与抽象化数据库…

Node.js 事件循环简单介绍

1.简介 Node.js 事件循环是 Node.js 运行时环境中的一个核心机制&#xff0c;用于管理异步操作和回调函数的执行顺序。它基于事件驱动模型&#xff0c;通过事件循环来处理和派发事件&#xff0c;以及执行相应的回调函数。 Node.js 是单进程单线程应用程序&#xff0c;但是因为…

QT QIFW Windows下制作安装包(一)

一、概述 1、QIFW是一款基于QT框架开发的跨平台安装框架。QIFW是QT Installer FrameWork的缩写&#xff0c;支持Windows、Linux和macos等多种平台。QIFW可以帮助开发者创建自己的安装程序&#xff0c;将它们打包到通用的安装包中&#xff0c;并提供可视化的界面进行安装。 2…

mysql:用SHOW CREATE TABLE tbl_name查看创建表的SQL语句

https://dev.mysql.com/doc/refman/8.2/en/show-create-table.html 可以用SHOW CREATE TABLE tbl_name查看创建表的SQL语句。 例如&#xff0c;SHOW CREATE TABLE test_table;表示查询创建test_table表的SQL语句&#xff1a;

刘元昌:期待更多年轻人的第一杯精酿是失眠企鹅

12月7日下午&#xff0c;2023&#xff08;第十八届&#xff09;大河财富中国论坛盛大开启。作为先行论坛&#xff0c;2023新消费峰会火热开场。此次峰会以“提质新消费 释放新活力”为主题&#xff0c;集论坛、演绎、展示、互动为一体&#xff0c;把峰会变身“秀场”&#xff0…

腾讯-轻量应用服务器centos7中宝塔安装MySQL8.0出现内存不足

目录 前言 出现的问题: 解决方法&#xff1a; 编译安装&#xff1a; 极速安装 其他 我的其他博客 前言 说实话&#xff0c;本人也就是个穷学生买不起啥大的服务器啥的&#xff0c;整了个2核 2内存的服务器 用宝塔按mysql5.5是没问题的&#xff0c;一切换8.0就提醒内存不足…