尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot + ECharts 后台数据统计报表模块实战

SpringBoot + ECharts 后台数据统计报表模块实战 前言在后台管理系统中数据可视化报表是运营人员的核心工具。前端使用 ECharts 绘制折线图、柱状图后端的核心工作就是按照 ECharts 要求的格式封装时间区间内的统计数据。 本文基于一套 B 端管理后台实现 4 大类统计报表营业额统计、用户统计、订单统计、商品销量 TOP10完整讲解需求、接口设计、代码实现、踩坑点。一、核心思路ECharts 绘图需要后端返回两组核心数据X 轴日期列表datelist作为图表横坐标Y 轴对应指标数值列表和日期一一对应。⚠️重点难点时间区间内没有数据的日期也要填充 0保证日期数组和数值数组长度完全一致否则 ECharts 图表会错位。 解决方案循环遍历起止日期生成完整日期序列再去数据库查询有数据的记录最后合并补 0。二、营业额统计折线图2.1 需求分析业务规则统计已完成订单的总金额作为当日营业额支持自定义时间区间查询前端 ECharts 折线图展示X 轴为日期Y 轴为营业额。2.2 接口设计项目内容请求路径/admin/report/turnoverStatistics请求方式GET请求参数begin开始日期end结束日期返回 VO日期字符串数组、营业额数组2.3 后端代码实现VO 实体Data Builder public class TurnoverReportVO { //日期列表逗号分隔 private String dateList; //营业额列表逗号分隔 private String turnoverList; }Controller 层RestController RequestMapping(/admin/report) Slf4j public class ReportController { Autowired private ReportService reportService; GetMapping(/turnoverStatistics) ApiOperation(营业额统计) public ResultTurnoverReportVO 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)); } }Service 核心逻辑Override public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) { //1. 生成begin ~ end之间完整的日期集合 ListLocalDate dateList new ArrayList(); dateList.add(begin); while (!begin.equals(end)){ begin begin.plusDays(1); dateList.add(begin); } //2. 遍历每一天查询当日营业额无数据则为0 ListDouble turnoverList new ArrayList(); for (LocalDate date : dateList) { LocalDateTime beginTime LocalDateTime.of(date, LocalTime.MIN); LocalDateTime endTime LocalDateTime.of(date, LocalTime.MAX); MapString,Object map new HashMap(); map.put(begin,beginTime); map.put(end,endTime); map.put(status, Orders.COMPLETED); Double turnover orderMapper.sumByMap(map); turnover turnover null ? 0.0 : turnover; turnoverList.add(turnover); } //3. 拼接成逗号分隔字符串返回前端 return TurnoverReportVO.builder() .dateList(StringUtils.join(dateList, ,)) .turnoverList(StringUtils.join(turnoverList, ,)) .build(); }Mapper XMLselect idsumByMap resultTypejava.lang.Double select sum(amount) from orders where if testbegin ! null and order_time gt; #{begin} /if if testend ! null and order_time lt; #{end} /if if teststatus ! null and status #{status} /if /where /select三、用户统计折线图3.1 需求分析统计时间区间内总用户量、新增用户量X 轴为日期两条折线累计总用户、当日新增用户。3.2 接口设计路径/admin/report/userStatisticsGET 请求参数begin、end3.3 核心代码Override public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) { //生成完整日期序列 ListLocalDate dateList new ArrayList(); dateList.add(begin); while (!begin.equals(end)){ begin begin.plusDays(1); dateList.add(begin); } ListInteger newUserList new ArrayList(); ListInteger totalUserList new ArrayList(); for (LocalDate date : dateList) { LocalDateTime beginTime LocalDateTime.of(date, LocalTime.MIN); LocalDateTime endTime LocalDateTime.of(date, LocalTime.MAX); MapString,Object map new HashMap(); map.put(end,endTime); //总用户数截止到当天结束 Integer totalUser userMapper.countByMap(map); map.put(begin,beginTime); //新增用户当天新增 Integer newUser userMapper.countByMap(map); newUserList.add(newUser); totalUserList.add(totalUser); } return UserReportVO.builder() .dateList(StringUtils.join(dateList, ,)) .totalUserList(StringUtils.join(totalUserList, ,)) .newUserList(StringUtils.join(newUserList, ,)) .build(); }要点Mapper 使用 Map 传参动态拼接 SQL 条件统计用户创建时间。四、订单统计双折线图4.1 需求统计区间内订单总数、有效订单数计算订单完成率 有效订单 / 总订单。核心逻辑Override public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) { ListLocalDate dateList getDateList(begin, end); ListInteger orderCountList new ArrayList(); ListInteger validOrderCountList new ArrayList(); for (LocalDate date : dateList) { LocalDateTime beginTime LocalDateTime.of(date, LocalTime.MIN); LocalDateTime endTime LocalDateTime.of(date, LocalTime.MAX); MapString,Object map new HashMap(); map.put(begin,beginTime); map.put(end,endTime); //当日全部订单 Integer total orderMapper.countByMap(map); map.put(status,Orders.COMPLETED); //当日有效完成订单 Integer valid orderMapper.countByMap(map); orderCountList.add(total); validOrderCountList.add(valid); } //计算区间内总订单、有效订单、完成率 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累加集合快速求和。五、商品销量 TOP10柱状图需求查询时间段内销量排名前 10 的商品ECharts 柱状图展示。返回商品名称列表、销量列表。Override public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) { LocalDateTime beginTime LocalDateTime.of(begin, LocalTime.MIN); LocalDateTime endTime LocalDateTime.of(end, LocalTime.MAX); ListGoodsSalesDTO salesTop10 orderMapper.getSalesTop10(beginTime, endTime); //拆分名称、销量两个集合 ListString names salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList()); ListInteger values salesTop10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList()); return SalesTop10ReportVO.builder() .nameList(StringUtils.join(names, ,)) .numberList(StringUtils.join(values, ,)) .build(); }Mapper SQL 核心关联订单明细表按商品分组统计销量排序取前 10。六、开发踩坑总结日期补 0如果跳过无数据日期X 轴和 Y 轴数据长度不一致ECharts 图表渲染错乱必须循环生成完整日期序列LocalDateTime 时间边界LocalTime.MIN是 00:00:00LocalTime.MAX是 23:59:59.999999防止跨天数据丢失null 值判断数据库查询 sum 聚合函数无数据返回 null不做判断直接赋值会空指针前端 ECharts 格式约定后端统一返回逗号分隔字符串前端 split 切割成数组前后端约定好数据格式Map 传参动态 SQL使用 MyBatis 动态标签if灵活拼接查询条件复用 Mapper。七、拓展与面试考点如果数据量很大每次查询数据库压力高可以定时任务预统计存入 Redis报表直接读缓存可以增加导出 Excel 功能把报表数据导出给运营面试常问时间区间统计某天没有数据怎么处理答先预生成起止时间内全部日期遍历日期逐个查询查询结果为空则填充 0保证坐标数组长度一致。
返回列表