当前位置: 首页 > news >正文

二刷 苍穹外卖day11

Apache ECharts

基于Javascript的数据库可视化图表库,提供直观、生动、可交互、可个性化定制的数据可视化图表
在这里插入图片描述

营业额统计

service

  public TurnoverReportVO getTurnover(LocalDate begin, LocalDate end) {List<LocalDate> dateList = new ArrayList<>();dateList.add(begin);while (!begin.equals(end)){begin = begin.plusDays(1);//日期计算,获得指定日期后1天的日期dateList.add(begin);}List<Double> turnoverList = 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("status", Orders.COMPLETED);map.put("begin",beginTime);map.put("end", endTime);Double turnover = orderMapper.sumByMap(map); turnover = turnover == null ? 0.0 : turnover;turnoverList.add(turnover);}//数据封装return TurnoverReportVO.builder().dateList(StringUtils.join(dateList,",")).turnoverList(StringUtils.join(turnoverList,",")).build();}

先拿到从begin到end之间的所有天数,然后对每一天,将LocalDate转化成LocalDateTime,也就是通过LocalTime.MIN和LocalTime.MAX拿到这一天的最小值和最大值复制给date,然后创建一个hashmap,将状态、当天的开始时间(0:0:0)和当天的结束时间(23:59:59)放入,用orderMapper的sumByMap方法进行查询,将查询到的结果放入一个新的数组,最后将数据封装好后返回给controller层

用户统计

service

@Overridepublic 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) {LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);//新增用户数量 select count(id) from user where create_time > ? and create_time < ?Integer newUser = getUserCount(beginTime, endTime);//总用户数量 select count(id) from user where  create_time < ?Integer totalUser = getUserCount(null, endTime);newUserList.add(newUser);totalUserList.add(totalUser);}return UserReportVO.builder().dateList(StringUtils.join(dateList,",")).newUserList(StringUtils.join(newUserList,",")).totalUserList(StringUtils.join(totalUserList,",")).build();}

这里也是同理,新增用户就是从当天最早的时间(MIN)到当天的最晚时间(MAX)内用户的新增量,而总用户数就是从null开始到当天的最晚时间内用户数量

mapper

	/*** 根据动态条件统计用户数量* @param map* @return*/Integer countByMap(Map map);
<select id="countByMap" resultType="java.lang.Integer">select count(id) from user<where><if test="begin != null">and create_time &gt;= #{begin}</if><if test="end != null">and create_time &lt;= #{end}</if></where>
</select>

MyBatis 允许直接通过Map的键名访问其值,这是一种简洁的参数传递方式,特别适合动态条件查询。在 XML 中使用#{key}test表达式时,MyBatis 会自动从传入的Map中获取对应的值,无需额外声明。

订单统计

service

public OrderReportVO getOrderStatistics(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<>();//每天有效订单数集合List<Integer> validOrderCountList = new ArrayList<>();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 count(id) from orders where order_time > ? and order_time < ? and status = ?Integer validOrderCount = getOrderCount(beginTime, endTime, Orders.COMPLETED);orderCountList.add(orderCount);validOrderCountList.add(validOrderCount);}//时间区间内的总订单数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();}

stream()将列表转换为流,reduce(Integer::sum)通过对每个元素执行求和操作来归约流,用get()获取归约操作的结果

销量排名Top10

service

    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end){LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getSalesTop10(beginTime, endTime);String nameList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList()),",");String numberList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList()),",");return SalesTop10ReportVO.builder().nameList(nameList).numberList(numberList).build();}

StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList()),",");

  • goodsSalesDTOList.stream():将goodsSalesDTOList转换为流,以便进行后续的操作。
  • .map(GoodsSalesDTO::getName):对流中的每个GoodsSalesDTO对象调用getName方法,提取出每个对象的名称。
  • .collect(Collectors.toList()):将提取出的名称收集到一个列表中。
  • StringUtils.join(...,","):使用StringUtils工具类的join方法,将收集到的名称列表用逗号连接成一个字符串,最后赋值给nameList

mapper

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

where子句:
- od.order_id = o.id ,建立order_detail表和orders表之间的关联关系,通过order_idid字段。
- o.status = 5 ,表示只筛选出orders表中状态为 5 的订单。
- <if>标签:这是 MyBatis 的动态 SQL 部分。当begin参数不为null时,and order_time &gt;= #{begin} 会被添加到 SQL 语句中,用于筛选order_time大于等于begin参数值的记录;当end参数不为null时,and order_time &lt;= #{end} 会被添加到 SQL 语句中,用于筛选order_time小于等于end参数值的记录。这里&gt;代表大于,&lt;代表小于,#{begin}#{end}是 MyBatis 的占位符,在执行时会被实际传入的参数值替换。

总结

1. 在营业额统计中,为什么需要将 LocalDate 转换为 LocalDateTime?

解答:
LocalDate 仅表示日期(如 2025-07-02),而数据库中订单时间通常存储为带时分秒的 LocalDateTime。转换时通过 LocalTime.MIN(00:00:00)和 LocalTime.MAX(23:59:59)生成当天的时间范围,确保查询条件能准确匹配当天所有订单,避免时间精度不足导致的数据遗漏。

2. MyBatis 中如何通过 Map 传递动态查询条件?有什么优势?

解答:
MyBatis 支持直接通过 Map 的键名访问参数(如 #{begin} 对应 map.put(“begin”, value)),无需定义实体类。优势在于:
灵活性高:适用于条件不确定的动态查询(如可选的开始 / 结束时间)。
减少代码量:避免为每个查询场景创建专用实体类,简化开发。
动态 SQL 适配:配合 标签,可按需拼接 SQL 条件,提升查询效率。

3. 订单统计中,Stream 的 reduce 操作如何实现数据汇总?

解答:
reduce(Integer::sum) 通过归约操作将流中的元素按加法累积:
Integer::sum 是方法引用,等价于 (a, b) -> a + b。
示例:[10, 20, 30].reduce(Integer::sum) 会依次计算 10+20=30,再 30+30=60,最终得到总和 60。
这种方式比传统循环更简洁,且支持并行计算(通过 parallelStream()),提升大数据量下的性能。

4. 销量排名 Top10 的 SQL 中,为什么使用多表关联和分组聚合?

解答:
多表关联:order_detail 存储商品明细,orders 存储订单状态,通过 order_id 关联可筛选有效订单(status=5)。
分组聚合:group by name 按商品名称分组,sum(od.number) 统计各商品总销量,order by number desc 降序排列后取前 10 条(limit 0,10)。
此方案通过一次查询完成关联、过滤、聚合和排序,效率优于多次单表查询。

5. 前端 ECharts 如何解析后端返回的字符串数据(如 dateList=“2025-07-01,2025-07-02”)?

解答:
后端通过 StringUtils.join 将列表转为逗号分隔的字符串,前端需:
使用 split(“,”) 解析为数组(如 dates = dateList.split(“,”))。
按图表类型绑定数据:
柱状图 / 折线图:xAxis.data = dates,series.data = turnoverList.split(“,”)。
饼图:需先转换为 [{name: ‘日期1’, value: 数据}, …] 格式。
此方式减少数据传输量,前端解析效率高。

6. 用户统计中,新增用户和总用户的查询条件有何本质区别?

解答:
新增用户:create_time > beginTime && create_time < endTime,统计当天注册的用户数。
总用户:create_time < endTime,统计从系统创建到当天所有注册的用户数(beginTime=null 时不限制起始时间)。
两者通过控制时间范围的边界,实现 “单日新增” 和 “累计总量” 的统计逻辑。

http://www.dtcms.com/a/265198.html

相关文章:

  • 讲解视频:分布滞后非线性模型DLNM​​专题:从基础到进阶学习路径
  • 记录一个QT中pro文件换行需要注意的问题
  • 第29篇:Linux审计系统深度解析:基于OpenEuler 24.03的实践指南
  • 【中文核心期刊推荐】《电子测量技术》
  • RabbitMQ使用topic Exchange实现微服务分组订阅
  • 基于SEP3203微处理器的嵌入式最小硬件系统设计
  • VBA初学习记录
  • OneCode表单架构设计:注解驱动与组件化的完美结合
  • 腾讯云认证考试报名 - TDSQL数据库交付运维专家(TCCE PostgreSQL版)
  • windows的vscode无法通过ssh连接ubuntu的解决办法
  • 网站面临爬虫攻击waf能防护住吗
  • docker拉取redis并使用
  • 《导引系统原理》-西北工业大学-周军
  • CppCon 2018 学习:Fast Conversion From UTF-8 with C++, DFAs, and SSE Intrinsics
  • 部署 KVM 虚拟化平台
  • 关于网络协议
  • 第四篇:面试官:SpringBoot 场景化实战 10 问(第四弹·附图解)
  • C语言笔记(鹏哥)上课板书+课件汇总 (编译和链接+linux讲解)
  • 【实战】CRMEB Pro 企业版安装教程(附 Nginx 反向代理配置 + 常见问题解决)
  • 深入理解C++11原子操作:从内存模型到无锁编程
  • Docker Dify安装 完整版本
  • Pytorch中torch.where()函数详解和实战示例
  • AIGC自我介绍笔记
  • Redis基础(1):NoSQL认识
  • sqlmap学习笔记ing(3.[MoeCTF 2022]Sqlmap_boy,cookie的作用)
  • UniApp完美对接RuoYi框架开发企业级应用
  • 基于 ethers.js 的区块链事件处理与钱包管理
  • UI前端大数据可视化实战技巧:动态数据加载与刷新策略
  • 【AI智能体】Coze 搭建个人旅游规划助手实战详解
  • 【Rancher Server + Kubernets】- Nginx-ingress日志持久化至宿主机