buhuazhen
8 天以前 47768d890fbfc1a5f3e93ca26137847361415e9e
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,259 @@
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<TimingTask> 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<DayOfWeek> 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<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) {
        Set<DayOfWeek> 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;
    }
}