苍穹外卖 Day05:数据统计、定时任务与 JWT 拦截器
内容分三块:数据统计模块(报表 + 工作台)、基于 @Scheduled 的订单超时清理定时任务、用户端 JWT 拦截器;前一天遗留的「/user/** 无拦截器」问题在此闭环。
报表统计(ReportController)
ReportController 映射 /admin/report,实现集中在 ReportServiceImpl。
营业额统计 getTurnoverStatistics(begin,end):
LocalDate从 begin 递增到 end 收集 dateList:while(!begin.equals(end)) begin = begin.plusDays(1)- 每天用
LocalDateTime.of(date, LocalTime.MIN/MAX)取日界,组装StatisticsQueryDTO(begin/end/status=COMPLETED)调orderMapper.sumByMap做 SUM(amount),null 兜底 0.0 - 返回
TurnoverReportVO,dateList / turnoverList 都用StringUtils.join(list, ",")拼成逗号串
用户统计 getUserStatistics:每天两查——totalUser 只设 end 条件(create_time < end 的累计总数),newUser 同时设 begin 和 end(当天新增);结果装进 UserReportVO(dateList/totalUserList/newUserList 逗号串)。
订单统计 getOrderStatistics(接口别名 /ordersStatistics):每天统计 orderCount(status 为 null)与 validOrderCount(COMPLETED),reduce 汇总 totalOrderCount / totalValidOrderCount,计算完成率时做除零保护;输出 OrderReportVO(总量/有效/完成率)。
销量 Top10 getTop10:orderMapper.getSalesTop10(begin,end) 返回 GoodsSalesDTO(name, number) 列表,拆成 nameList / numberList 逗号串装入 SalesTop10ReportVO。
Excel 导出 export(POI 模板填充):
- 取近 30 天(now-30 ~ now-1),调
workspaceService.getBusinessData拿概览数据 - 读模板
template/运营数据报表模板.xlsx得到XSSFWorkbook,按sheet.getRow(i).getCell(j)逐行填入:时间范围/营业额/有效订单/完成率/客单价/新增用户,Top10 从第 16 行起填排名/名称/销量 - 设置下载响应头:
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),文件名经URLEncoder.encode("运营数据报表.xlsx", UTF_8)编码防乱码,最终用ServletOutputStream写出
工作台数据(WorkspaceServiceImpl)
getBusinessData(begin,end):总订单数(countByMap 不带 status)→ 营业额(sumByMap,status=COMPLETED)→ 有效订单数 → 完成率 = 有效/总 → 客单价 = 营业额/有效订单 → 新增用户走UserMapper.countByMapgetOrderOverView:同一个查询 DTO 换 status 复用 countByMap,依次统计待接单(2)/待派送(3)/已完成(5)/已取消(6)/全部(null)getDishOverView/getSetmealOverView:status=ENABLE/DISABLE 分别用dishMapper/setmealMapper的 countByMap 统计起售/停售数量
定时任务处理超时订单
SkyApplication 加 @EnableScheduling 开启调度。
OrderTask.processTimeoutOrder:@Scheduled(cron = "0 * * * * ?")每分钟执行,查询 now-15min 之前仍处于 PENDING_PAYMENT 的订单(getByStatusAndOrderTimeLT,@Select 注解版),遍历置 CANCELLED 并写入 cancelTime、cancelReason(“订单超时未支付,系统自动取消”)→orderMapper.updateOrderTask.processDeliveryOrder:@Scheduled(cron = "0 0 1 * * ?")每天凌晨 1 点执行,把派送中超 1 小时的 DELIVERY_IN_PROGRESS 订单置 COMPLETEDMytask.executeTask:每 5 秒一次的练习示例,cron = "0/5 * * * * ?"
cron 表达式共六段:秒 分 时 日 月 周;日与周互斥,不需要的那段用 ? 占位。
用户端 JWT 拦截器
JwtTokenUserInterceptor.preHandle:非 Controller 请求直接放行 → 从 header 取userTokenName对应的 token →JwtUtil.parseJWT(userSecretKey, token)解析 → 从 claims 取出 USER_ID 执行BaseContext.setCurrentId;校验失败时response.setStatus(401)并返回 falseWebMvcConfiguration.addInterceptors注册双拦截器:/admin/**拦截(排除/admin/employee/login);/user/**拦截(排除/user/user/login、/user/shop/status)
统计 SQL 与通用查询 DTO
StatisticsQueryDTO以 begin/end/status/categoryId 作类型化查询条件,替代课程原版的Map map,类型安全增强OrderMapper.xml三条统计 SQL:sumByMap:select sum(amount) from orders配<where>内<if>判断 begin/end/status,动态聚合营业额countByMap:select count(id) from orders同样的动态条件计数,订单统计与工作台复用getSalesTop10:select od.name, sum(od.number) number from order_detail od, orders o where od.order_id=o.id and o.status=5 [时间过滤] group by od.name order by number desc limit 0,10
UserMapper.xml/DishMapper.xml/SetmealMapper.xml各自提供countByMap动态计数
可优化点
- 报表的营业额/用户/订单统计都按天循环查询,30 天区间即 30+ 次 SQL;数据量小时无碍,量大可改用
GROUP BY一次聚合。 getTop10与export内存在两段相同的getSalesTop10查询逻辑,可抽公用方法。RedisConfiguration.redisTemplate仍为原始类型,沿用前一天的建议改为RedisTemplate<String,Object>。
代码锚点
| 知识点 | 代码位置 |
|---|---|
| 按天遍历生成日期序列 | ReportServiceImpl.getTurnoverStatistics(while+plusDays) |
| 动态条件统计 SQL(sumByMap/countByMap) | OrderMapper.xml sumByMap/countByMap |
| 新增用户 vs 累计用户查询差异 | getUserStatistics(totalUser 只设 end / newUser 设 begin+end) |
| 订单完成率/客单价计算与除零保护 | getOrderStatistics、WorkspaceServiceImpl.getBusinessData |
| 联表聚合销量 Top10 | OrderMapper.xml getSalesTop10(GROUP BY + ORDER BY DESC + LIMIT) |
| 多状态复用 countByMap 概览 | WorkspaceServiceImpl.getOrderOverView |
| POI 模板填充导出 Excel | ReportServiceImpl.export + ReportController.export |
| @EnableScheduling + @Scheduled cron | SkyApplication + OrderTask |
| 超时订单自动取消(状态机) | OrderTask.processTimeoutOrder |
| 用户端 JWT 校验 + 放行逻辑 | JwtTokenUserInterceptor + WebMvcConfiguration |
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





















