增加了提醒的单独开关功能

This commit is contained in:
dengqichen 2025-05-30 11:03:24 +08:00
parent b3d98ce025
commit 48333f5b4a
10 changed files with 246 additions and 77 deletions

View File

@ -47,14 +47,7 @@ public class TaskReminderConfig {
.orElse(null);
}
/**
* 获取所有启用的群组
*/
public List<Group> getEnabledGroups() {
return groups.stream()
.filter(Group::isEnabled)
.toList();
}
public static class Global {
private int timeout = 5000;
@ -74,7 +67,7 @@ public class TaskReminderConfig {
private Webhook webhook = new Webhook();
private String taskSystem;
private Map<String, Schedule> schedules = new HashMap<>();
private boolean enabled = true;
private Zentao zentao = new Zentao();
private Map<String, String> userMapping = new HashMap<>();
@ -118,13 +111,7 @@ public class TaskReminderConfig {
this.schedules = schedules;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Zentao getZentao() {
return zentao;
@ -157,8 +144,8 @@ public class TaskReminderConfig {
public static class Schedule {
private String time;
private String type = "text"; // 默认为文本类型
private String message;
private boolean enabled = true; // 默认启用
public String getTime() {
return time;
@ -168,14 +155,6 @@ public class TaskReminderConfig {
this.time = time;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
@ -183,6 +162,14 @@ public class TaskReminderConfig {
public void setMessage(String message) {
this.message = message;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public static class Zentao {

View File

@ -64,11 +64,11 @@ public class TaskReminderController {
try {
String taskInfo = dynamicTaskScheduler.getTaskStatusInfo();
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
response.put("success", true);
response.put("taskInfo", taskInfo);
response.put("enabledGroupCount", enabledGroups.size());
response.put("totalGroupCount", allGroups.size());
response.put("activeTaskCount", dynamicTaskScheduler.getActiveTaskCount());
response.put("message", "获取系统信息成功");
} catch (Exception e) {
@ -129,7 +129,7 @@ public class TaskReminderController {
Map<String, Object> response = new HashMap<>();
try {
taskReminderService.sendMorningReminder();
taskReminderService.sendAllMorningReminders();
response.put("success", true);
response.put("message", "早上提醒已触发");
} catch (Exception e) {

View File

@ -1,6 +1,7 @@
package com.zeodao.reminder.scheduler;
import com.zeodao.reminder.config.TaskReminderConfig;
import com.zeodao.reminder.service.EnabledCheckService;
import com.zeodao.reminder.service.TaskReminderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -18,7 +19,7 @@ import java.util.concurrent.ScheduledFuture;
/**
* 动态任务调度器
* 根据配置文件动态创建定时任务
*
*
* @author Zeodao
* @version 2.0.0
*/
@ -33,6 +34,9 @@ public class DynamicTaskScheduler {
@Autowired
private TaskReminderService taskReminderService;
@Autowired
private EnabledCheckService enabledCheckService;
@Autowired
private TaskScheduler taskScheduler;
@ -41,11 +45,11 @@ public class DynamicTaskScheduler {
@PostConstruct
public void initScheduledTasks() {
logger.info("=== 初始化动态定时任务 ===");
for (TaskReminderConfig.Group group : taskReminderConfig.getEnabledGroups()) {
for (TaskReminderConfig.Group group : taskReminderConfig.getGroups()) {
createSchedulesForGroup(group);
}
logger.info("=== 动态定时任务初始化完成,共创建 {} 个任务 ===", scheduledTasks.size());
}
@ -54,16 +58,22 @@ public class DynamicTaskScheduler {
*/
private void createSchedulesForGroup(TaskReminderConfig.Group group) {
logger.info("为群组 {} 创建定时任务", group.getName());
for (Map.Entry<String, TaskReminderConfig.Schedule> entry : group.getSchedules().entrySet()) {
String scheduleType = entry.getKey();
TaskReminderConfig.Schedule schedule = entry.getValue();
// 检查该提醒类型是否启用
if (!enabledCheckService.isReminderEnabled(group, scheduleType)) {
logger.debug("跳过禁用的提醒类型: {} - {}", group.getName(), scheduleType);
continue;
}
String taskKey = group.getId() + "-" + scheduleType;
try {
CronTrigger cronTrigger = new CronTrigger(schedule.getTime());
Runnable task = () -> {
try {
logger.info("=== 执行定时任务: {} - {} ===", group.getName(), scheduleType);
@ -72,12 +82,12 @@ public class DynamicTaskScheduler {
logger.error("定时任务执行失败: {} - {}", group.getName(), scheduleType, e);
}
};
ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(task, cronTrigger);
scheduledTasks.put(taskKey, scheduledFuture);
logger.info("创建定时任务成功: {} - {} ({})", group.getName(), scheduleType, schedule.getTime());
} catch (Exception e) {
logger.error("创建定时任务失败: {} - {} ({})", group.getName(), scheduleType, schedule.getTime(), e);
}
@ -89,10 +99,10 @@ public class DynamicTaskScheduler {
*/
public void reloadScheduledTasks() {
logger.info("=== 重新加载定时任务 ===");
// 取消所有现有任务
cancelAllTasks();
// 重新创建任务
initScheduledTasks();
}
@ -102,17 +112,17 @@ public class DynamicTaskScheduler {
*/
private void cancelAllTasks() {
logger.info("取消所有现有定时任务");
for (Map.Entry<String, ScheduledFuture<?>> entry : scheduledTasks.entrySet()) {
String taskKey = entry.getKey();
ScheduledFuture<?> future = entry.getValue();
if (future != null && !future.isCancelled()) {
future.cancel(false);
logger.debug("取消定时任务: {}", taskKey);
}
}
scheduledTasks.clear();
}
@ -133,28 +143,37 @@ public class DynamicTaskScheduler {
info.append("=== 定时任务状态 ===\n");
info.append("总任务数: ").append(scheduledTasks.size()).append("\n");
info.append("活跃任务数: ").append(getActiveTaskCount()).append("\n");
info.append("启用群组数: ").append(taskReminderConfig.getEnabledGroups().size()).append("\n\n");
info.append("配置群组数: ").append(taskReminderConfig.getGroups().size()).append("\n\n");
info.append("=== 群组配置详情 ===\n");
for (TaskReminderConfig.Group group : taskReminderConfig.getEnabledGroups()) {
for (TaskReminderConfig.Group group : taskReminderConfig.getGroups()) {
info.append("群组: ").append(group.getName()).append(" (").append(group.getId()).append(")\n");
info.append("任务系统: ").append(group.getTaskSystem()).append("\n");
info.append("定时任务:\n");
for (Map.Entry<String, TaskReminderConfig.Schedule> entry : group.getSchedules().entrySet()) {
String scheduleType = entry.getKey();
TaskReminderConfig.Schedule schedule = entry.getValue();
String taskKey = group.getId() + "-" + scheduleType;
ScheduledFuture<?> future = scheduledTasks.get(taskKey);
String status = (future != null && !future.isCancelled()) ? "运行中" : "已停止";
boolean isEnabled = enabledCheckService.isReminderEnabled(group, scheduleType);
String status;
if (!isEnabled) {
status = "已禁用";
} else if (future != null && !future.isCancelled()) {
status = "运行中";
} else {
status = "已停止";
}
info.append(" - ").append(scheduleType).append(": ").append(schedule.getTime())
.append(" (").append(status).append(")\n");
}
info.append("\n");
}
return info.toString();
}

View File

@ -0,0 +1,75 @@
package com.zeodao.reminder.service;
import com.zeodao.reminder.config.TaskReminderConfig;
import com.zeodao.reminder.enums.ScheduleType;
import com.zeodao.reminder.strategy.EnabledChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
/**
* 启用状态检查服务
* 使用责任链模式按优先级检查各级启用状态
*
* @author Zeodao
* @version 2.0.0
*/
@Service
public class EnabledCheckService {
private static final Logger logger = LoggerFactory.getLogger(EnabledCheckService.class);
private final List<EnabledChecker> enabledCheckers;
@Autowired
public EnabledCheckService(List<EnabledChecker> enabledCheckers) {
// 按优先级排序
this.enabledCheckers = enabledCheckers.stream()
.sorted(Comparator.comparingInt(EnabledChecker::getPriority))
.toList();
logger.info("初始化启用状态检查器,共 {} 个检查器", this.enabledCheckers.size());
}
/**
* 检查群组的特定提醒类型是否启用
* 使用责任链模式任何一个检查器返回false则整体返回false
*
* @param group 群组配置
* @param scheduleType 提醒类型
* @return 是否启用
*/
public boolean isReminderEnabled(TaskReminderConfig.Group group, ScheduleType scheduleType) {
for (EnabledChecker checker : enabledCheckers) {
if (!checker.isEnabled(group, scheduleType)) {
logger.debug("检查器 {} 返回false群组: {}, 提醒类型: {}",
checker.getClass().getSimpleName(), group.getName(), scheduleType.getDescription());
return false;
}
}
logger.debug("所有检查器通过,群组: {}, 提醒类型: {} 已启用",
group.getName(), scheduleType.getDescription());
return true;
}
/**
* 检查群组的特定提醒类型是否启用字符串版本用于兼容
*
* @param group 群组配置
* @param scheduleTypeCode 提醒类型代码
* @return 是否启用
*/
public boolean isReminderEnabled(TaskReminderConfig.Group group, String scheduleTypeCode) {
ScheduleType scheduleType = ScheduleType.fromCode(scheduleTypeCode);
if (scheduleType == null) {
logger.warn("无效的提醒类型代码: {}", scheduleTypeCode);
return false;
}
return isReminderEnabled(group, scheduleType);
}
}

View File

@ -38,6 +38,9 @@ public class TaskReminderService {
@Autowired
private ReminderHandlerFactory reminderHandlerFactory;
@Autowired
private EnabledCheckService enabledCheckService;
/**
* 发送指定群组和时间段的任务提醒
*/
@ -53,8 +56,9 @@ public class TaskReminderService {
return;
}
if (!group.isEnabled()) {
logger.info("群组 {} 已禁用,跳过提醒", groupId);
// 使用启用状态检查服务进行多级检查
if (!enabledCheckService.isReminderEnabled(group, scheduleType)) {
logger.info("群组 {} 的 {} 提醒已禁用,跳过提醒", group.getName(), scheduleType);
return;
}
@ -94,9 +98,9 @@ public class TaskReminderService {
* 发送所有启用群组的早上提醒
*/
public void sendAllMorningReminders() {
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
for (TaskReminderConfig.Group group : enabledGroups) {
if (group.getSchedules().containsKey("morning")) {
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
for (TaskReminderConfig.Group group : allGroups) {
if (enabledCheckService.isReminderEnabled(group, ScheduleType.MORNING)) {
sendReminder(group.getId(), "morning");
}
}
@ -106,9 +110,9 @@ public class TaskReminderService {
* 发送所有启用群组的晚上提醒
*/
public void sendAllEveningReminders() {
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
for (TaskReminderConfig.Group group : enabledGroups) {
if (group.getSchedules().containsKey("evening")) {
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
for (TaskReminderConfig.Group group : allGroups) {
if (enabledCheckService.isReminderEnabled(group, ScheduleType.EVENING)) {
sendReminder(group.getId(), "evening");
}
}
@ -118,9 +122,9 @@ public class TaskReminderService {
* 发送所有启用群组的逾期任务提醒
*/
public void sendAllOverdueReminders() {
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
for (TaskReminderConfig.Group group : enabledGroups) {
if (group.getSchedules().containsKey("overdue-reminder")) {
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
for (TaskReminderConfig.Group group : allGroups) {
if (enabledCheckService.isReminderEnabled(group, ScheduleType.OVERDUE_REMINDER)) {
sendReminder(group.getId(), "overdue-reminder");
}
}

View File

@ -89,13 +89,13 @@ public class WechatWebhookService {
*/
@Deprecated
public boolean sendMarkdownMessage(String content) {
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
if (enabledGroups.isEmpty()) {
logger.error("没有启用的群组配置");
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
if (allGroups.isEmpty()) {
logger.error("没有配置的群组");
return false;
}
return sendMarkdownMessage(enabledGroups.get(0).getId(), content);
return sendMarkdownMessage(allGroups.get(0).getId(), content);
}
/**
@ -251,11 +251,11 @@ public class WechatWebhookService {
*/
@Deprecated
public String createTaskReminderMessage(String baseMessage, String timeType) {
List<TaskReminderConfig.Group> enabledGroups = taskReminderConfig.getEnabledGroups();
if (enabledGroups.isEmpty()) {
List<TaskReminderConfig.Group> allGroups = taskReminderConfig.getGroups();
if (allGroups.isEmpty()) {
return baseMessage;
}
return createTaskReminderMessage(enabledGroups.get(0).getId(), baseMessage, timeType);
return createTaskReminderMessage(allGroups.get(0).getId(), baseMessage, timeType);
}
/**

View File

@ -0,0 +1,30 @@
package com.zeodao.reminder.strategy;
import com.zeodao.reminder.config.TaskReminderConfig;
import com.zeodao.reminder.enums.ScheduleType;
/**
* 启用状态检查器接口
* 使用策略模式检查不同级别的启用状态
*
* @author Zeodao
* @version 2.0.0
*/
public interface EnabledChecker {
/**
* 检查是否启用
*
* @param group 群组配置
* @param scheduleType 提醒类型
* @return 是否启用
*/
boolean isEnabled(TaskReminderConfig.Group group, ScheduleType scheduleType);
/**
* 获取检查器的优先级数字越小优先级越高
*
* @return 优先级
*/
int getPriority();
}

View File

@ -0,0 +1,42 @@
package com.zeodao.reminder.strategy;
import com.zeodao.reminder.config.TaskReminderConfig;
import com.zeodao.reminder.enums.ScheduleType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 提醒计划级别启用状态检查器
* 检查特定提醒类型是否启用
*
* @author Zeodao
* @version 2.0.0
*/
@Component
public class ScheduleEnabledChecker implements EnabledChecker {
private static final Logger logger = LoggerFactory.getLogger(ScheduleEnabledChecker.class);
@Override
public boolean isEnabled(TaskReminderConfig.Group group, ScheduleType scheduleType) {
TaskReminderConfig.Schedule schedule = group.getSchedules().get(scheduleType.getCode());
if (schedule == null) {
logger.debug("群组 {} 未配置 {} 提醒", group.getName(), scheduleType.getDescription());
return false;
}
boolean enabled = schedule.isEnabled();
if (!enabled) {
logger.debug("群组 {} 的 {} 提醒已禁用", group.getName(), scheduleType.getDescription());
}
return enabled;
}
@Override
public int getPriority() {
return 2; // 次优先级在群组启用的前提下检查具体提醒类型
}
}

View File

@ -37,13 +37,15 @@ task:
morning:
time: "0 0 9 * * MON-FRI" # 工作日早上9点
message: "早上好!新的一天开始了,请大家及时登录禅道系统刷新今日的任务状态,确保任务进度准确反映当前工作情况。"
enabled: true # 启用早上提醒
evening:
time: "0 30 17 * * MON-FRI" # 工作日下午5:30
message: "下班前提醒:请大家登录禅道系统,及时更新今日任务的完成状态和进度,为明天的工作安排做好准备!"
enabled: true # 启用晚上提醒
overdue-reminder:
time: "0 0 10 * * MON-FRI" # 工作日上午10点
message: "禅道逾期任务提醒" # 这个消息会被系统动态生成包含具体的任务和BUG统计信息
enabled: true
enabled: false # 启用逾期提醒
# 智能表格团队群
- id: "smartsheet-team"
@ -55,10 +57,11 @@ task:
morning:
time: "0 50 8 * * MON-FRI" # 工作日早上8点50分
message: "早上好!请大家及时更新智能表格中的任务状态,确保项目进度信息准确无误。"
enabled: true # 启用早上提醒
evening:
time: "0 20 17 * * MON-FRI" # 工作日下午5点20分
message: "下班前提醒:请在智能表格中更新今日工作完成情况,为明天做好准备!"
enabled: true
enabled: false # 禁用晚上提醒(示例:智能表格团队不需要晚上提醒)
# 日志配置
logging:

View File

@ -1,6 +1,7 @@
package com.zeodao.reminder.service;
import com.zeodao.reminder.config.TaskReminderConfig;
import com.zeodao.reminder.enums.ScheduleType;
import com.zeodao.reminder.util.HolidayUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -37,6 +38,9 @@ class TaskReminderServiceTest {
@Mock
private TaskReminderConfig taskReminderConfig;
@Mock
private EnabledCheckService enabledCheckService;
@InjectMocks
private TaskReminderService taskReminderService;
@ -48,7 +52,7 @@ class TaskReminderServiceTest {
testGroup = new TaskReminderConfig.Group();
testGroup.setId("test-group");
testGroup.setName("测试群组");
testGroup.setEnabled(true);
TaskReminderConfig.Webhook webhook = new TaskReminderConfig.Webhook();
webhook.setUrl("https://test.webhook.url");
@ -59,11 +63,13 @@ class TaskReminderServiceTest {
TaskReminderConfig.Schedule morningSchedule = new TaskReminderConfig.Schedule();
morningSchedule.setTime("0 0 9 * * MON-FRI");
morningSchedule.setMessage("测试早上消息");
morningSchedule.setEnabled(true);
schedules.put("morning", morningSchedule);
TaskReminderConfig.Schedule eveningSchedule = new TaskReminderConfig.Schedule();
eveningSchedule.setTime("0 30 17 * * MON-FRI");
eveningSchedule.setMessage("测试晚上消息");
eveningSchedule.setEnabled(true);
schedules.put("evening", eveningSchedule);
testGroup.setSchedules(schedules);
@ -75,6 +81,7 @@ class TaskReminderServiceTest {
when(holidayUtil.isWeekend(any(LocalDate.class))).thenReturn(false);
when(holidayUtil.isHoliday(any(LocalDate.class))).thenReturn(false);
when(taskReminderConfig.getGroupById("test-group")).thenReturn(testGroup);
when(enabledCheckService.isReminderEnabled(testGroup, "morning")).thenReturn(true);
when(wechatWebhookService.createTaskReminderMessage(anyString(), anyString(), anyString())).thenReturn("测试消息");
when(wechatWebhookService.sendMarkdownMessage(anyString(), anyString())).thenReturn(true);
@ -118,8 +125,9 @@ class TaskReminderServiceTest {
// 模拟工作日
when(holidayUtil.isWeekend(any(LocalDate.class))).thenReturn(false);
when(holidayUtil.isHoliday(any(LocalDate.class))).thenReturn(false);
when(taskReminderConfig.getEnabledGroups()).thenReturn(Arrays.asList(testGroup));
when(taskReminderConfig.getGroups()).thenReturn(Arrays.asList(testGroup));
when(taskReminderConfig.getGroupById("test-group")).thenReturn(testGroup);
when(enabledCheckService.isReminderEnabled(testGroup, ScheduleType.MORNING)).thenReturn(true);
when(wechatWebhookService.createTaskReminderMessage(anyString(), anyString(), anyString())).thenReturn("测试消息");
when(wechatWebhookService.sendMarkdownMessage(anyString(), anyString())).thenReturn(true);
@ -135,8 +143,9 @@ class TaskReminderServiceTest {
// 模拟工作日
when(holidayUtil.isWeekend(any(LocalDate.class))).thenReturn(false);
when(holidayUtil.isHoliday(any(LocalDate.class))).thenReturn(false);
when(taskReminderConfig.getEnabledGroups()).thenReturn(Arrays.asList(testGroup));
when(taskReminderConfig.getGroups()).thenReturn(Arrays.asList(testGroup));
when(taskReminderConfig.getGroupById("test-group")).thenReturn(testGroup);
when(enabledCheckService.isReminderEnabled(testGroup, ScheduleType.EVENING)).thenReturn(true);
when(wechatWebhookService.createTaskReminderMessage(anyString(), anyString(), anyString())).thenReturn("测试消息");
when(wechatWebhookService.sendMarkdownMessage(anyString(), anyString())).thenReturn(true);
@ -160,10 +169,10 @@ class TaskReminderServiceTest {
}
@Test
void testSendReminderWithDisabledGroup() {
// 创建禁用的群组
testGroup.setEnabled(false);
void testSendReminderWithDisabledReminder() {
// 模拟提醒被禁用
when(taskReminderConfig.getGroupById("test-group")).thenReturn(testGroup);
when(enabledCheckService.isReminderEnabled(testGroup, "morning")).thenReturn(false);
// 执行测试
taskReminderService.sendReminder("test-group", "morning");