Spring Boot按状态及周一至周六分组统计线索并实现图表可视化
问题分析
原代码存在以下核心问题,导致无法实现按线索状态+创建日期所属周一至周六分组统计的需求:
- 完全未使用线索的创建日期字段,未实现按周几分组的核心逻辑
- 数组操作逻辑错误:
getAndIncrement()先返回当前值再自增,后续counter.get()会指向已自增后的索引,导致数组赋值位置错误,甚至触发索引越界 - 统计逻辑混乱:每遍历一条线索就创建
LeadsDashboard并添加到集合,最终得到的是逐条线索的记录,而非聚合后的统计结果 - 状态判断冗余:使用多个独立
if而非else if,可能导致同一条线索被重复处理
修复方案
1. 明确数据模型定义
确保LeadsDashboard包含统计所需的核心字段:
public class LeadsDashboard { private String status; private int dayOfWeek; // 0=周一,1=周二...5=周六 private long count; // 生成getter、setter、构造方法 }
2. 基于Java Stream的分组统计实现
利用Stream的分组聚合能力,先按状态+周几统计数量,再整理为前端图表适配的结构:
@Override public Response<Map<String, List<LeadsDashboard>>> getLeadsDashboards() { Response<Map<String, List<LeadsDashboard>>> response = new Response<>(); User user = userRepository.getById(auditorAware.getCurrentAuditor().get().getId()); List<Lead> leads = leadRepository.findAll(user.getCompany().getId()); // 按状态+周几分组统计数量 Map<String, Map<Integer, Long>> statusDayCountMap = leads.stream() .filter(lead -> lead.getCreateDate() != null) .collect(Collectors.groupingBy( Lead::getStatus, Collectors.groupingBy( lead -> { // 转换为周一=0到周六=5的索引(排除周日) int sqlServerWeekday = lead.getCreateDate().getDayOfWeek().getValue(); return sqlServerWeekday == 1 ? -1 : sqlServerWeekday - 2; }, Collectors.counting() ) )); // 转换为前端需要的结构:补全周一到周六的空统计(数量为0) Map<String, List<LeadsDashboard>> resMap = new HashMap<>(); Arrays.stream(Statuses.values()) .map(Statuses::getStatus) .forEach(status -> { List<LeadsDashboard> dashboardList = new ArrayList<>(); for (int day = 0; day < 6; day++) { LeadsDashboard dashboard = new LeadsDashboard(); dashboard.setStatus(status); dashboard.setDayOfWeek(day); dashboard.setCount(statusDayCountMap.getOrDefault(status, new HashMap<>()).getOrDefault(day, 0L)); dashboardList.add(dashboard); } resMap.put(status.toLowerCase() + "Leads", dashboardList); }); response.setBody(resMap); return response; }
3. 推荐:SQL层面直接统计(性能更优)
若数据量较大,直接在数据库完成分组统计效率更高,修改Repository接口:
// LeadRepository接口 @Query(value = """ SELECT l.status, DATEPART(weekday, l.create_date) - 2 AS day_of_week, COUNT(*) AS count FROM lead l WHERE l.company_id = :companyId AND DATEPART(weekday, l.create_date) BETWEEN 2 AND 7 -- 仅统计周一到周六(SQL Server中周日=1,周一=2...周六=7) GROUP BY l.status, DATEPART(weekday, l.create_date) """, nativeQuery = true) List<Object[]> countLeadsByStatusAndDayOfWeek(@Param("companyId") Long companyId);
后续在Service中处理查询结果,转换为LeadsDashboard结构即可。
关键说明
- 周几转换适配:SQL Server中
DATEPART(weekday, date)返回1(周日)到7(周六),需转换为0-5对应周一到周六 - 空值补全:确保每个状态下周一到周六都有统计数据(无数据则为0),保证前端图表横轴连续
- 分组逻辑:先按状态分组,再按周几聚合,精准匹配需求的统计维度
内容的提问来源于stack exchange,提问作者Christian jire
相关产品推荐
相关产品推荐

