Spring Reactive WebFlux调用外部API并计算工作日数的问题
解决方案:响应式计算两日之间的工作日数
核心思路
先将API返回的节假日集合转为Set<LocalDate>(方便快速查找),再遍历起止日期范围内的每一天,过滤掉周六、周日及节假日后统计数量。以下是具体实现步骤和代码:
1. 日期格式转换工具方法
先处理前端和API的日期格式差异:
import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 解析前端传入的dd/mm/yyyy格式日期 private LocalDate parseFrontendDate(String dateStr) { return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("dd/MM/yyyy")); } // 解析API返回的yyyy-MM-dd格式日期(默认ISO格式,直接调用parse即可) private LocalDate parseApiDate(String dateStr) { return LocalDate.parse(dateStr); }
2. 响应式工作日数计算实现
根据你的CompanyCalendarService,在getDaysCount方法中结合Flux完成逻辑:
import reactor.core.publisher.Mono; import reactor.core.publisher.Flux; import java.util.Set; import java.util.stream.Collectors; import java.time.DayOfWeek; public Mono<Integer> getWorkDaysCount(String startDateStr, String endDateStr) { LocalDate start = parseFrontendDate(startDateStr); LocalDate end = parseFrontendDate(endDateStr); // 1. 将Flux<CompanyHolidayCalendar>转为Mono<Set<LocalDate>> Mono<Set<LocalDate>> holidaysSet = yourHolidayApiClient.getHolidays() // 替换为你获取Flux的实际方法 .map(holidayDto -> parseApiDate(holidayDto.getDate())) // 假设CompanyHolidayCalendar有getDate()返回日期字符串 .collect(Collectors.toSet()); // 2. 遍历日期范围,过滤工作日并排除节假日 return holidaysSet.map(holidays -> { int workDayCount = 0; LocalDate currentDate = start; while (!currentDate.isAfter(end)) { DayOfWeek day = currentDate.getDayOfWeek(); // 排除周六、周日,且不在节假日集合中 if (day != DayOfWeek.SATURDAY && day != DayOfWeek.SUNDAY && !holidays.contains(currentDate)) { workDayCount++; } currentDate = currentDate.plusDays(1); } return workDayCount; }); }
3. 大日期范围优化(可选)
如果起止日期跨度极大(如跨年),用Flux.generate生成日期流更贴合响应式风格,避免同步循环的潜在性能问题:
return holidaysSet.flatMap(holidays -> Flux.generate(() -> start, (current, sink) -> { if (current.isAfter(end)) { sink.complete(); } else { sink.next(current); } return current.plusDays(1); }) .filter(date -> { DayOfWeek day = date.getDayOfWeek(); return day != DayOfWeek.SATURDAY && day != DayOfWeek.SUNDAY && !holidays.contains(date); }) .count() .map(Long::intValue) );
关键注意事项
- 日期转换时建议添加异常处理(如前端传错格式),可结合
try-catch或DateTimeFormatter的宽松模式。 - 确保API返回的节假日数据覆盖起止日期的所有年份,避免漏判节假日。
- 所有外部API调用必须保持响应式(使用WebClient的
retrieve().bodyToFlux(...)),不要切换到同步阻塞操作。
内容的提问来源于stack exchange,提问作者Nisha
相关产品推荐
相关产品推荐

