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;
|
}
|
}
|