Commit f6f162ad2fb7676e46b9747a661ed17427847292

Authored by YunaiV
1 parent 8d0caaa1

【功能新增】IoT:增加 IotRuleSceneJob 执行定时任务

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.rule;
  2 +
  3 +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService;
  4 +import io.swagger.v3.oas.annotations.tags.Tag;
  5 +import jakarta.annotation.Resource;
  6 +import jakarta.annotation.security.PermitAll;
  7 +import org.springframework.validation.annotation.Validated;
  8 +import org.springframework.web.bind.annotation.GetMapping;
  9 +import org.springframework.web.bind.annotation.RequestMapping;
  10 +import org.springframework.web.bind.annotation.RestController;
  11 +
  12 +@Tag(name = "管理后台 - IoT 规则场景")
  13 +@RestController
  14 +@RequestMapping("/iot/rule-scene")
  15 +@Validated
  16 +public class IotRuleSceneController {
  17 +
  18 + @Resource
  19 + private IotRuleSceneService ruleSceneService;
  20 +
  21 + @GetMapping("/test")
  22 + @PermitAll
  23 + public void test() {
  24 + ruleSceneService.test();
  25 + }
  26 +
  27 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java
@@ -80,18 +80,18 @@ public class IotSchedulerManager { @@ -80,18 +80,18 @@ public class IotSchedulerManager {
80 * 添加或更新 Job 到 Quartz 中 80 * 添加或更新 Job 到 Quartz 中
81 * 81 *
82 * @param jobClass 任务处理器的类 82 * @param jobClass 任务处理器的类
83 - * @param jobHandlerName 任务处理器的名字 83 + * @param jobName 任务名
84 * @param cronExpression CRON 表达式 84 * @param cronExpression CRON 表达式
85 * @param jobDataMap 任务数据 85 * @param jobDataMap 任务数据
86 * @throws SchedulerException 添加异常 86 * @throws SchedulerException 添加异常
87 */ 87 */
88 - public void addOrUpdateJob(Class <? extends Job> jobClass, String jobHandlerName, 88 + public void addOrUpdateJob(Class <? extends Job> jobClass, String jobName,
89 String cronExpression, Map<String, Object> jobDataMap) 89 String cronExpression, Map<String, Object> jobDataMap)
90 throws SchedulerException { 90 throws SchedulerException {
91 - if (scheduler.checkExists(new JobKey(jobHandlerName))) {  
92 - this.updateJob(jobHandlerName, cronExpression); 91 + if (scheduler.checkExists(new JobKey(jobName))) {
  92 + this.updateJob(jobName, cronExpression);
93 } else { 93 } else {
94 - this.addJob(jobClass, jobHandlerName, cronExpression, jobDataMap); 94 + this.addJob(jobClass, jobName, cronExpression, jobDataMap);
95 } 95 }
96 } 96 }
97 97
@@ -99,20 +99,20 @@ public class IotSchedulerManager { @@ -99,20 +99,20 @@ public class IotSchedulerManager {
99 * 添加 Job 到 Quartz 中 99 * 添加 Job 到 Quartz 中
100 * 100 *
101 * @param jobClass 任务处理器的类 101 * @param jobClass 任务处理器的类
102 - * @param jobHandlerName 任务处理器的名字 102 + * @param jobName 任务名
103 * @param cronExpression CRON 表达式 103 * @param cronExpression CRON 表达式
104 * @param jobDataMap 任务数据 104 * @param jobDataMap 任务数据
105 * @throws SchedulerException 添加异常 105 * @throws SchedulerException 添加异常
106 */ 106 */
107 - public void addJob(Class <? extends Job> jobClass, String jobHandlerName, 107 + public void addJob(Class <? extends Job> jobClass, String jobName,
108 String cronExpression, Map<String, Object> jobDataMap) 108 String cronExpression, Map<String, Object> jobDataMap)
109 throws SchedulerException { 109 throws SchedulerException {
110 // 创建 JobDetail 对象 110 // 创建 JobDetail 对象
111 JobDetail jobDetail = JobBuilder.newJob(jobClass) 111 JobDetail jobDetail = JobBuilder.newJob(jobClass)
112 .usingJobData(new JobDataMap(jobDataMap)) 112 .usingJobData(new JobDataMap(jobDataMap))
113 - .withIdentity(jobHandlerName).build(); 113 + .withIdentity(jobName).build();
114 // 创建 Trigger 对象 114 // 创建 Trigger 对象
115 - Trigger trigger = this.buildTrigger(jobHandlerName, cronExpression); 115 + Trigger trigger = this.buildTrigger(jobName, cronExpression);
116 // 新增 Job 调度 116 // 新增 Job 调度
117 scheduler.scheduleJob(jobDetail, trigger); 117 scheduler.scheduleJob(jobDetail, trigger);
118 } 118 }
@@ -120,70 +120,70 @@ public class IotSchedulerManager { @@ -120,70 +120,70 @@ public class IotSchedulerManager {
120 /** 120 /**
121 * 更新 Job 到 Quartz 121 * 更新 Job 到 Quartz
122 * 122 *
123 - * @param jobHandlerName 任务处理器的名字 123 + * @param jobName 任务名
124 * @param cronExpression CRON 表达式 124 * @param cronExpression CRON 表达式
125 * @throws SchedulerException 更新异常 125 * @throws SchedulerException 更新异常
126 */ 126 */
127 - public void updateJob(String jobHandlerName, String cronExpression) 127 + public void updateJob(String jobName, String cronExpression)
128 throws SchedulerException { 128 throws SchedulerException {
129 // 创建新 Trigger 对象 129 // 创建新 Trigger 对象
130 - Trigger newTrigger = this.buildTrigger(jobHandlerName, cronExpression); 130 + Trigger newTrigger = this.buildTrigger(jobName, cronExpression);
131 // 修改调度 131 // 修改调度
132 - scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); 132 + scheduler.rescheduleJob(new TriggerKey(jobName), newTrigger);
133 } 133 }
134 134
135 /** 135 /**
136 * 删除 Quartz 中的 Job 136 * 删除 Quartz 中的 Job
137 * 137 *
138 - * @param jobHandlerName 任务处理器的名字 138 + * @param jobName 任务名
139 * @throws SchedulerException 删除异常 139 * @throws SchedulerException 删除异常
140 */ 140 */
141 - public void deleteJob(String jobHandlerName) throws SchedulerException { 141 + public void deleteJob(String jobName) throws SchedulerException {
142 // 暂停 Trigger 对象 142 // 暂停 Trigger 对象
143 - scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); 143 + scheduler.pauseTrigger(new TriggerKey(jobName));
144 // 取消并删除 Job 调度 144 // 取消并删除 Job 调度
145 - scheduler.unscheduleJob(new TriggerKey(jobHandlerName));  
146 - scheduler.deleteJob(new JobKey(jobHandlerName)); 145 + scheduler.unscheduleJob(new TriggerKey(jobName));
  146 + scheduler.deleteJob(new JobKey(jobName));
147 } 147 }
148 148
149 /** 149 /**
150 * 暂停 Quartz 中的 Job 150 * 暂停 Quartz 中的 Job
151 * 151 *
152 - * @param jobHandlerName 任务处理器的名字 152 + * @param jobName 任务名
153 * @throws SchedulerException 暂停异常 153 * @throws SchedulerException 暂停异常
154 */ 154 */
155 - public void pauseJob(String jobHandlerName) throws SchedulerException {  
156 - scheduler.pauseJob(new JobKey(jobHandlerName)); 155 + public void pauseJob(String jobName) throws SchedulerException {
  156 + scheduler.pauseJob(new JobKey(jobName));
157 } 157 }
158 158
159 /** 159 /**
160 * 启动 Quartz 中的 Job 160 * 启动 Quartz 中的 Job
161 * 161 *
162 - * @param jobHandlerName 任务处理器的名字 162 + * @param jobName 任务名
163 * @throws SchedulerException 启动异常 163 * @throws SchedulerException 启动异常
164 */ 164 */
165 - public void resumeJob(String jobHandlerName) throws SchedulerException {  
166 - scheduler.resumeJob(new JobKey(jobHandlerName));  
167 - scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); 165 + public void resumeJob(String jobName) throws SchedulerException {
  166 + scheduler.resumeJob(new JobKey(jobName));
  167 + scheduler.resumeTrigger(new TriggerKey(jobName));
168 } 168 }
169 169
170 /** 170 /**
171 * 立即触发一次 Quartz 中的 Job 171 * 立即触发一次 Quartz 中的 Job
172 * 172 *
173 - * @param jobHandlerName 任务处理器的名字 173 + * @param jobName 任务名
174 * @throws SchedulerException 触发异常 174 * @throws SchedulerException 触发异常
175 */ 175 */
176 - public void triggerJob(String jobHandlerName) 176 + public void triggerJob(String jobName)
177 throws SchedulerException { 177 throws SchedulerException {
178 // 触发任务 178 // 触发任务
179 JobDataMap data = new JobDataMap(); 179 JobDataMap data = new JobDataMap();
180 - data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);  
181 - scheduler.triggerJob(new JobKey(jobHandlerName), data); 180 + data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobName);
  181 + scheduler.triggerJob(new JobKey(jobName), data);
182 } 182 }
183 183
184 - private Trigger buildTrigger(String jobHandlerName, String cronExpression) { 184 + private Trigger buildTrigger(String jobName, String cronExpression) {
185 return TriggerBuilder.newTrigger() 185 return TriggerBuilder.newTrigger()
186 - .withIdentity(jobHandlerName) 186 + .withIdentity(jobName)
187 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) 187 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
188 .build(); 188 .build();
189 } 189 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.job.rule;
  2 +
  3 +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
  4 +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.quartz.JobExecutionContext;
  8 +import org.springframework.scheduling.quartz.QuartzJobBean;
  9 +
  10 +import java.util.Map;
  11 +
  12 +/**
  13 + * IoT 规则场景 Job,用于执行 {@link IotRuleSceneTriggerTypeEnum#TIMER} 类型的规则场景
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Slf4j
  18 +public class IotRuleSceneJob extends QuartzJobBean {
  19 +
  20 + /**
  21 + * JobData Key - 规则场景编号
  22 + */
  23 + public static final String JOB_DATA_KEY_RULE_SCENE_ID = "ruleSceneId";
  24 +
  25 + @Resource
  26 + private IotRuleSceneService ruleSceneService;
  27 +
  28 + @Override
  29 + protected void executeInternal(JobExecutionContext context) {
  30 + // 获得规则场景编号
  31 + Long ruleSceneId = context.getMergedJobDataMap().getLong(JOB_DATA_KEY_RULE_SCENE_ID);
  32 +
  33 + // 执行规则场景
  34 + ruleSceneService.executeRuleSceneByTimer(ruleSceneId);
  35 + }
  36 +
  37 + /**
  38 + * 创建 JobData Map
  39 + *
  40 + * @param ruleSceneId 规则场景编号
  41 + * @return JobData Map
  42 + */
  43 + public static Map<String, Object> buildJobDataMap(Long ruleSceneId) {
  44 + return Map.of(JOB_DATA_KEY_RULE_SCENE_ID, ruleSceneId);
  45 + }
  46 +
  47 + /**
  48 + * 创建 Job 名字
  49 + *
  50 + * @param ruleSceneId 规则场景编号
  51 + * @return Job 名字
  52 + */
  53 + public static String buildJobName(Long ruleSceneId) {
  54 + return String.format("%s_%d", IotRuleSceneJob.class.getSimpleName(), ruleSceneId);
  55 + }
  56 +
  57 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java
@@ -29,6 +29,16 @@ public interface IotRuleSceneService { @@ -29,6 +29,16 @@ public interface IotRuleSceneService {
29 */ 29 */
30 void executeRuleSceneByDevice(IotDeviceMessage message); 30 void executeRuleSceneByDevice(IotDeviceMessage message);
31 31
32 - // TODO @芋艿:基于 timer 场景,执行规则场景 32 + /**
  33 + * 基于 {@link IotRuleSceneTriggerTypeEnum#TIMER} 场景,执行规则场景
  34 + *
  35 + * @param id 场景编号
  36 + */
  37 + void executeRuleSceneByTimer(Long id);
  38 +
  39 + /**
  40 + * TODO 芋艿:测试方法,需要删除
  41 + */
  42 + void test();
33 43
34 } 44 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
@@ -7,6 +7,7 @@ import cn.hutool.core.text.CharPool; @@ -7,6 +7,7 @@ import cn.hutool.core.text.CharPool;
7 import cn.hutool.core.util.NumberUtil; 7 import cn.hutool.core.util.NumberUtil;
8 import cn.hutool.core.util.ObjUtil; 8 import cn.hutool.core.util.ObjUtil;
9 import cn.hutool.core.util.StrUtil; 9 import cn.hutool.core.util.StrUtil;
  10 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 11 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
11 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 12 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
12 import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; 13 import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
@@ -19,9 +20,12 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; @@ -19,9 +20,12 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
19 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 20 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
20 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; 21 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum;
21 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; 22 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
  23 +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager;
  24 +import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob;
22 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; 25 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
23 import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction; 26 import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction;
24 import jakarta.annotation.Resource; 27 import jakarta.annotation.Resource;
  28 +import lombok.SneakyThrows;
25 import lombok.extern.slf4j.Slf4j; 29 import lombok.extern.slf4j.Slf4j;
26 import org.quartz.JobKey; 30 import org.quartz.JobKey;
27 import org.quartz.Scheduler; 31 import org.quartz.Scheduler;
@@ -54,6 +58,9 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -54,6 +58,9 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
54 @Resource 58 @Resource
55 private List<IotRuleSceneAction> ruleSceneActions; 59 private List<IotRuleSceneAction> ruleSceneActions;
56 60
  61 + @Resource(name = "iotSchedulerManager")
  62 + private IotSchedulerManager schedulerManager;
  63 +
57 // TODO 芋艿,缓存待实现 64 // TODO 芋艿,缓存待实现
58 @Override 65 @Override
59 @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 66 @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略
@@ -186,7 +193,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -186,7 +193,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
186 public void executeRuleSceneByDevice(IotDeviceMessage message) { 193 public void executeRuleSceneByDevice(IotDeviceMessage message) {
187 TenantUtils.execute(message.getTenantId(), () -> { 194 TenantUtils.execute(message.getTenantId(), () -> {
188 // 1. 获得设备匹配的规则场景 195 // 1. 获得设备匹配的规则场景
189 - List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneList(message); 196 + List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneListByMessage(message);
190 if (CollUtil.isEmpty(ruleScenes)) { 197 if (CollUtil.isEmpty(ruleScenes)) {
191 return; 198 return;
192 } 199 }
@@ -196,13 +203,60 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -196,13 +203,60 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
196 }); 203 });
197 } 204 }
198 205
  206 + @Override
  207 + public void executeRuleSceneByTimer(Long id) {
  208 + // 1.1 获得规则场景
  209 +// IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id));
  210 + // TODO @芋艿:这里,临时测试,后续删除。
  211 + IotRuleSceneDO scene = new IotRuleSceneDO().setStatus(CommonStatusEnum.ENABLE.getStatus());
  212 + if (true) {
  213 + scene.setTenantId(1L);
  214 + IotRuleSceneDO.TriggerConfig triggerConfig = new IotRuleSceneDO.TriggerConfig();
  215 + triggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType());
  216 + scene.setTriggers(ListUtil.toList(triggerConfig));
  217 + // 动作
  218 + IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();
  219 + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType());
  220 + IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();
  221 + actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT");
  222 + actionDeviceControl01.setDeviceNames(ListUtil.of("small"));
  223 + actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
  224 + actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
  225 + actionDeviceControl01.setData(MapUtil.<String, Object>builder()
  226 + .put("power", 1)
  227 + .put("color", "red")
  228 + .build());
  229 + action01.setDeviceControl(actionDeviceControl01);
  230 + scene.setActions(ListUtil.toList(action01));
  231 + }
  232 + if (scene == null) {
  233 + log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id);
  234 + return;
  235 + }
  236 + if (CommonStatusEnum.isDisable(scene.getStatus())) {
  237 + log.info("[executeRuleSceneByTimer][规则场景({}) 已被禁用]", id);
  238 + return;
  239 + }
  240 + // 1.2 判断是否有定时触发器,避免脏数据
  241 + IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(),
  242 + trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType()));
  243 + if (config == null) {
  244 + log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene);
  245 + return;
  246 + }
  247 +
  248 + // 2. 执行规则场景
  249 + TenantUtils.execute(scene.getTenantId(),
  250 + () -> executeRuleSceneAction(null, ListUtil.toList(scene)));
  251 + }
  252 +
199 /** 253 /**
200 - * 获得匹配的规则场景列表 254 + * 基于消息,获得匹配的规则场景列表
201 * 255 *
202 * @param message 设备消息 256 * @param message 设备消息
203 * @return 规则场景列表 257 * @return 规则场景列表
204 */ 258 */
205 - private List<IotRuleSceneDO> getMatchedRuleSceneList(IotDeviceMessage message) { 259 + private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) {
206 // 1. 匹配设备 260 // 1. 匹配设备
207 // TODO @芋艿:可能需要 getSelf(); 缓存 261 // TODO @芋艿:可能需要 getSelf(); 缓存
208 List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( 262 List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache(
@@ -335,16 +389,37 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -335,16 +389,37 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
335 }); 389 });
336 } 390 }
337 391
338 - // TODO @芋艿:测试思路代码,记得删除!!!  
339 - // 1. Job 类:IotRuleSceneJob  
340 - // 2. 参数:id  
341 - // 3. jobHandlerName:IotRuleSceneJob + id 392 + @Override
  393 + @SneakyThrows
  394 + public void test() {
  395 + // TODO @芋艿:测试思路代码,记得删除!!!
  396 + // 1. Job 类:IotRuleSceneJob DONE
  397 + // 2. 参数:id DONE
  398 + // 3. jobHandlerName:IotRuleSceneJob + id DONE
  399 +
  400 + // 新增:addJob
  401 + // 修改:不存在 addJob、存在 updateJob
  402 + // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以)pauseJob
  403 + // 有 + 开启:1)存在,更新;2)不存在,新增;结论:使用 save(addOrUpdateJob)
  404 + // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以)deleteJob
  405 +
  406 + //
  407 + if (true) {
  408 + Long id = 1L;
  409 + Map<String, Object> jobDataMap = IotRuleSceneJob.buildJobDataMap(id);
  410 + schedulerManager.addOrUpdateJob(IotRuleSceneJob.class,
  411 + IotRuleSceneJob.buildJobName(id),
  412 + "0/10 * * * * ?",
  413 + jobDataMap);
  414 + }
  415 + if (false) {
  416 + Long id = 1L;
  417 + schedulerManager.pauseJob(IotRuleSceneJob.buildJobName(id));
  418 + }
  419 + if (true) {
342 420
343 - // 新增:addJob  
344 - // 修改:不存在 addJob、存在 updateJob  
345 - // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以)  
346 - // 有 + 开启:1)存在,更新;2)不存在,新增;  
347 - // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以) 421 + }
  422 + }
348 423
349 public static void main2(String[] args) throws SchedulerException { 424 public static void main2(String[] args) throws SchedulerException {
350 // System.out.println(QuartzJobBean.class); 425 // System.out.println(QuartzJobBean.class);