如何在Thymeleaf的th:each中按日期过滤集合?
解决Thymeleaf th:each嵌套迭代中的日期过滤问题
问题根源分析
你遇到的问题核心有两点:
- Date对象构造错误:Java的
java.util.Date(int year, int month, int date)构造器中,year需传入年份-1900,month是0~11的索引值。你写的new Date(2024,11,10)实际生成的是3924年12月10日,完全偏离预期日期。 - Date对象比较精度问题:直接用
eq比较两个Date对象会精确到毫秒,数据库返回的dateAppointment通常包含具体时间(如2024-11-10 14:30:00),但你构造的days是当天0点的日期,两者毫秒数不同导致匹配失败。
方案一:前端修正过滤逻辑(适合小数据量场景)
先修正后端Date对象的创建方式,再在Thymeleaf中通过日期格式化后比较年/月/日部分:
后端修正Date创建代码
import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.Arrays; // 生成正确的2024-11-10和2024-12-05的Date对象 LocalDate date1 = LocalDate.of(2024, 11, 10); Date day1 = Date.from(date1.atStartOfDay(ZoneId.systemDefault()).toInstant()); LocalDate date2 = LocalDate.of(2024, 12, 5); Date day2 = Date.from(date2.atStartOfDay(ZoneId.systemDefault()).toInstant()); List<Date> days = Arrays.asList(day1, day2); model.addAttribute("days", days); // 预约数据获取逻辑不变 List<oCalendar> calendaries = myRepository.findAppointmentBeginEnd(dateBegin, dateEnd); model.addAttribute("calendaries", calendaries);
前端Thymeleaf过滤代码
<tr th:each="day : ${days}"> <!-- 通过格式化日期为统一格式,只比较年/月/日部分 --> <tr th:each="cal : ${calendaries.?[#dates.format(dateAppointment, 'yyyy-MM-dd') == #dates.format(day, 'yyyy-MM-dd')]}"> <td th:text="${#dates.format(cal.dateAppointment, 'yyyy-MM-dd HH:mm')}"></td> <td th:text="${cal.hourAppointment}"></td> </tr> </tr>
方案二:后端提前分组(性能更优,推荐)
避免前端循环过滤的性能损耗,在后端将预约数据按日期分组,前端直接根据日期取对应数据:
后端分组代码
import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; // 生成LocalDate类型的日期列表(替代原Date类型的days) List<LocalDate> dayList = List.of( LocalDate.of(2024, 11, 10), LocalDate.of(2024, 12, 5) ); model.addAttribute("dayList", dayList); // 预约数据按日期分组 List<oCalendar> calendaries = myRepository.findAppointmentBeginEnd(dateBegin, dateEnd); Map<LocalDate, List<oCalendar>> calendarMap = calendaries.stream() .collect(Collectors.groupingBy(cal -> // 将Date转成LocalDate,提取日期部分 cal.getDateAppointment().toInstant().atZone(ZoneId.systemDefault()).toLocalDate() )); model.addAttribute("calendarMap", calendarMap);
前端渲染代码
<tr th:each="localDay : ${dayList}"> <!-- 直接获取当前日期对应的预约列表,无数据时显示空列表 --> <tr th:each="cal : ${calendarMap.get(localDay) ?: #lists.emptyList()}"> <td th:text="${#dates.format(cal.dateAppointment, 'yyyy-MM-dd HH:mm')}"></td> <td th:text="${cal.hourAppointment}"></td> </tr> </tr>
内容的提问来源于stack exchange,提问作者gapler
相关产品推荐
相关产品推荐

