package com.ruoyi.inspectiontask.service.impl; import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper; import com.ruoyi.inspectiontask.mapper.TimingTaskMapper; import com.ruoyi.inspectiontask.pojo.InspectionTask; import com.ruoyi.inspectiontask.pojo.TimingTask; import com.ruoyi.inspectiontask.service.TimingTaskService; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.sql.DataSource; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.util.HashSet; import java.util.List; import java.util.Set; @Component @DisallowConcurrentExecution // 禁止并发执行同一个Job public class TimingTaskJob implements Job { @Autowired private TimingTaskMapper timingTaskMapper; @Autowired private TimingTaskService timingTaskService; @Autowired private InspectionTaskMapper inspectionTaskMapper; @Autowired private JdbcTemplate jdbcTemplate; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); // 修复类型转换错误,正确获取taskId Long taskId = jobDataMap.getLong("taskId"); try { // 3. 尝试查询你的业务数据 // 通过JDBC模板查询定时任务信息,使用参数化查询防止SQL注入 String yourSql = "SELECT * FROM timing_task where id = ?"; List tasks = jdbcTemplate.query( yourSql, new BeanPropertyRowMapper<>(TimingTask.class), taskId ); TimingTask timingTask = tasks.isEmpty() ? null : tasks.get(0); if (timingTask == null) { throw new JobExecutionException("找不到定时任务: " + taskId); } // if (!timingTask.isActive()) { // throw new JobExecutionException("定时任务已禁用: " + taskId); // } // 2. 创建并保存巡检任务记录 - 这就是您提供的代码应该放的位置 InspectionTask inspectionTask = createInspectionTask(timingTask); inspectionTaskMapper.insert(inspectionTask); // 3. 更新定时任务的执行时间 if (!tasks.isEmpty()) { TimingTask task = tasks.get(0); // 更新最后执行时间为当前时间 LocalDateTime lastExecutionTime = LocalDateTime.now(); // 计算下次执行时间 LocalDateTime nextExecutionTime = calculateNextExecutionTime( task.getFrequencyType(), task.getFrequencyDetail(), lastExecutionTime ); // 执行更新操作 String updateSql = "UPDATE timing_task " + "SET last_execution_time = ?, next_execution_time = ? " + "WHERE id = ?"; jdbcTemplate.update( updateSql, lastExecutionTime, nextExecutionTime, taskId ); } // timingTaskService.updateTaskExecutionTime(taskId); // 4. 记录执行日志 // timingTaskService.recordExecutionLog(taskId, true, "任务执行成功,生成巡检任务ID: " + inspectionTask.getId()); } catch (Exception e) { // timingTaskService.recordExecutionLog(taskId, false, "任务执行失败: " + e.getMessage()); throw new JobExecutionException(e); } } // 这就是您提供的代码封装成的方法 private InspectionTask createInspectionTask(TimingTask timingTask) { InspectionTask inspectionTask = new InspectionTask(); // 复制基本属性 inspectionTask.setTaskName(timingTask.getTaskName()); inspectionTask.setTaskId(timingTask.getTaskId()); inspectionTask.setInspectorId(timingTask.getInspectorIds()); inspectionTask.setInspectionLocation(timingTask.getInspectionLocation()); inspectionTask.setRemarks("自动生成自定时任务ID: " + timingTask.getId()); inspectionTask.setRegistrantId(timingTask.getRegistrantId()); inspectionTask.setFrequencyType(timingTask.getFrequencyType()); inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail()); inspectionTask.setTenantId(timingTask.getTenantId()); return inspectionTask; } /** * 计算下次执行时间 */ private LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) { try { switch (frequencyType) { case "DAILY": return calculateDailyNextTime(frequencyDetail, currentTime); case "WEEKLY": return calculateWeeklyNextTime(frequencyDetail, currentTime); case "MONTHLY": return calculateMonthlyNextTime(frequencyDetail, currentTime); case "QUARTERLY": return calculateQuarterlyNextTime(frequencyDetail, currentTime); default: throw new IllegalArgumentException("不支持的频率类型: " + frequencyType); } } catch (Exception e) { throw new RuntimeException("计算下次执行时间失败: " + e.getMessage(), e); } } /** * 计算每日任务的下次执行时间 */ private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) { LocalTime executionTime = LocalTime.parse(timeStr); // 解析格式 "HH:mm" LocalDateTime nextTime = LocalDateTime.of(current.toLocalDate(), executionTime); // 如果今天的时间已过,则安排明天 return current.isBefore(nextTime) ? nextTime : nextTime.plusDays(1); } /** * 计算每周任务的下次执行时间 */ private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); String dayOfWeekStr = parts[0]; // 如 "MON" 或 "MON|WED|FRI" LocalTime time = LocalTime.parse(parts[1]); // 时间部分 // 解析星期几(支持多个星期) Set targetDays = parseDayOfWeeks(dayOfWeekStr); // 从当前时间开始找下一个符合条件的星期几 LocalDateTime nextTime = current; while (true) { nextTime = nextTime.plusDays(1); if (targetDays.contains(nextTime.getDayOfWeek())) { return LocalDateTime.of(nextTime.toLocalDate(), time); } // 防止无限循环(理论上不会发生) if (nextTime.isAfter(current.plusYears(1))) { throw new RuntimeException("无法找到下次执行时间"); } } } /** * 计算每月任务的下次执行时间 */ private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int dayOfMonth = Integer.parseInt(parts[0]); LocalTime time = LocalTime.parse(parts[1]); // 从下个月开始计算 LocalDateTime nextTime = current.plusMonths(1) .withDayOfMonth(Math.min(dayOfMonth, current.plusMonths(1).toLocalDate().lengthOfMonth())) .with(time); return nextTime; } /** * 计算每季度任务的下次执行时间 */ private LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int quarterMonth = Integer.parseInt(parts[0]); // 1=第1个月,2=第2个月,3=第3个月 int dayOfMonth = Integer.parseInt(parts[1]); LocalTime time = LocalTime.parse(parts[2]); // 计算当前季度 int currentQuarter = (current.getMonthValue() - 1) / 3 + 1; int currentMonthInQuarter = (current.getMonthValue() - 1) % 3 + 1; YearMonth targetYearMonth; if (currentMonthInQuarter < quarterMonth) { // 本季度内还有执行机会 targetYearMonth = YearMonth.from(current) .plusMonths(quarterMonth - currentMonthInQuarter); } else { // 需要到下个季度 targetYearMonth = YearMonth.from(current) .plusMonths(3 - currentMonthInQuarter + quarterMonth); } // 处理月末日期 int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth()); return LocalDateTime.of( targetYearMonth.getYear(), targetYearMonth.getMonthValue(), adjustedDay, time.getHour(), time.getMinute() ); } /** * 解析星期几字符串 */ private Set parseDayOfWeeks(String dayOfWeekStr) { Set days = new HashSet<>(); String[] dayStrs = dayOfWeekStr.split("\\|"); for (String dayStr : dayStrs) { switch (dayStr) { case "MON": days.add(DayOfWeek.MONDAY); break; case "TUE": days.add(DayOfWeek.TUESDAY); break; case "WED": days.add(DayOfWeek.WEDNESDAY); break; case "THU": days.add(DayOfWeek.THURSDAY); break; case "FRI": days.add(DayOfWeek.FRIDAY); break; case "SAT": days.add(DayOfWeek.SATURDAY); break; case "SUN": days.add(DayOfWeek.SUNDAY); break; default: throw new IllegalArgumentException("无效的星期几: " + dayStr); } } return days; } }