diff --git a/hsweb-commons/hsweb-commons-utils/src/main/java/org/hswebframework/web/Sqls.java b/hsweb-commons/hsweb-commons-utils/src/main/java/org/hswebframework/web/Sqls.java new file mode 100644 index 000000000..acb319ce9 --- /dev/null +++ b/hsweb-commons/hsweb-commons-utils/src/main/java/org/hswebframework/web/Sqls.java @@ -0,0 +1,34 @@ +package org.hswebframework.web; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public class Sqls { + + public static List parse(String sqlText) { + String[] list = sqlText.split("[\n]"); + List sqlList = new ArrayList<>(); + List tmp = new ArrayList<>(); + Stream.of(list) + .filter(s -> !s.startsWith("--") && s.trim().length() != 0) + .forEach(s1 -> { + if (s1.trim().endsWith(";")) { + s1 = s1.trim(); + tmp.add(s1.substring(0, s1.length() - 1)); + sqlList.add(String.join("\n", tmp.toArray(new String[tmp.size()]))); + tmp.clear(); + } else { + tmp.add(s1); + } + }); + sqlList.add(String.join("\n", tmp.toArray(new String[tmp.size()]))); + tmp.clear(); + return sqlList; + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-dao/hsweb-system-schedule-dao-mybatis/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/schedule/ScheduleJobMapper.xml b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-dao/hsweb-system-schedule-dao-mybatis/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/schedule/ScheduleJobMapper.xml index d00a9bcab..9e8aa3b1c 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-dao/hsweb-system-schedule-dao-mybatis/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/schedule/ScheduleJobMapper.xml +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-dao/hsweb-system-schedule-dao-mybatis/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/schedule/ScheduleJobMapper.xml @@ -4,16 +4,16 @@ "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd"> - - - - - - - - - - + + + + + + + + + + @@ -21,8 +21,8 @@ - - + + diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/ScheduleJobEntity.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/ScheduleJobEntity.java index cbd0fa62a..c21baaa32 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/ScheduleJobEntity.java +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/ScheduleJobEntity.java @@ -1,131 +1,141 @@ package org.hswebframework.web.entity.schedule; + import org.hswebframework.web.commons.entity.GenericEntity; /** -* 调度任务 实体 -* @author hsweb-generator-online -*/ -public interface ScheduleJobEntity extends GenericEntity{ + * 调度任务 实体 + * + * @author hsweb-generator-online + */ +public interface ScheduleJobEntity extends GenericEntity { /*------------------------------------------- | 属性名常量 | ===========================================*/ - /** + /** * 任务名称 */ - String name="name"; - /** + String name = "name"; + /** * 备注 */ - String remark="remark"; - /** + String remark = "remark"; + /** * 定时调度配置 */ - String quartz_config="quartz_config"; - /** + String quartzConfig = "quartzConfig"; + /** * 执行脚本 */ - String script="script"; - /** + String script = "script"; + /** * 脚本语言 */ - String language="language"; - /** + String language = "language"; + /** * 是否启用 */ - String enabled="enabled"; - /** + String status = "status"; + /** * 启动参数 */ - String parameters="parameters"; - /** + String parameters = "parameters"; + /** * 任务类型 */ - String type="type"; - /** + String type = "type"; + /** * 标签 */ - String tags="tags"; - - /** - * @return 任务名称 - */ - String getName(); + String tags = "tags"; - /** - * @param name 任务名称 - */ - void setName(String name); - /** - * @return 备注 - */ - String getRemark(); + /** + * @return 任务名称 + */ + String getName(); - /** - * @param remark 备注 - */ - void setRemark(String remark); - /** - * @return 定时调度配置 - */ - String getQuartz_config(); + /** + * @param name 任务名称 + */ + void setName(String name); - /** - * @param quartz_config 定时调度配置 - */ - void setQuartz_config(String quartz_config); - /** - * @return 执行脚本 - */ - String getScript(); + /** + * @return 备注 + */ + String getRemark(); - /** - * @param script 执行脚本 - */ - void setScript(String script); - /** - * @return 脚本语言 - */ - String getLanguage(); + /** + * @param remark 备注 + */ + void setRemark(String remark); - /** - * @param language 脚本语言 - */ - void setLanguage(String language); - /** - * @return 是否启用 - */ - Long getEnabled(); + /** + * @return 定时调度配置 + */ + String getQuartzConfig(); - /** - * @param enabled 是否启用 - */ - void setEnabled(Long enabled); - /** - * @return 启动参数 - */ - String getParameters(); + /** + * @param quartzConfig 定时调度配置 + */ + void setQuartzConfig(String quartzConfig); - /** - * @param parameters 启动参数 - */ - void setParameters(String parameters); - /** - * @return 任务类型 - */ - String getType(); + /** + * @return 执行脚本 + */ + String getScript(); - /** - * @param type 任务类型 - */ - void setType(String type); - /** - * @return 标签 - */ - String getTags(); + /** + * @param script 执行脚本 + */ + void setScript(String script); + + /** + * @return 脚本语言 + */ + String getLanguage(); + + /** + * @param language 脚本语言 + */ + void setLanguage(String language); + + /** + * @return 是否启用 + */ + Byte getStatus(); + + /** + * @param status 是否启用 + */ + void setStatus(Byte status); + + /** + * @return 启动参数 + */ + String getParameters(); + + /** + * @param parameters 启动参数 + */ + void setParameters(String parameters); + + /** + * @return 任务类型 + */ + String getType(); + + /** + * @param type 任务类型 + */ + void setType(String type); + + /** + * @return 标签 + */ + String getTags(); + + /** + * @param tags 标签 + */ + void setTags(String tags); - /** - * @param tags 标签 - */ - void setTags(String tags); - } \ No newline at end of file diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/SimpleScheduleJobEntity.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/SimpleScheduleJobEntity.java index 4fc5af658..768d8b579 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/SimpleScheduleJobEntity.java +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-entity/src/main/java/org/hswebframework/web/entity/schedule/SimpleScheduleJobEntity.java @@ -11,13 +11,13 @@ public class SimpleScheduleJobEntity extends SimpleGenericEntity impleme //备注 private String remark; //定时调度配置 - private String quartz_config; + private String quartzConfig; //执行脚本 private String script; //脚本语言 private String language; //是否启用 - private Long enabled; + private Byte status; //启动参数 private String parameters; //任务类型 @@ -54,15 +54,15 @@ public class SimpleScheduleJobEntity extends SimpleGenericEntity impleme /** * @return 定时调度配置 */ - public String getQuartz_config(){ - return this.quartz_config; + public String getQuartzConfig(){ + return this.quartzConfig; } /** - * @param quartz_config 定时调度配置 + * @param quartzConfig 定时调度配置 */ - public void setQuartz_config(String quartz_config){ - this.quartz_config=quartz_config; + public void setQuartzConfig(String quartzConfig){ + this.quartzConfig = quartzConfig; } /** * @return 执行脚本 @@ -93,15 +93,15 @@ public class SimpleScheduleJobEntity extends SimpleGenericEntity impleme /** * @return 是否启用 */ - public Long getEnabled(){ - return this.enabled; + public Byte getStatus(){ + return this.status; } /** - * @param enabled 是否启用 + * @param status 是否启用 */ - public void setEnabled(Long enabled){ - this.enabled=enabled; + public void setStatus(Byte status){ + this.status = status; } /** * @return 启动参数 diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/pom.xml b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/pom.xml index 296069daf..325fdfc95 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/pom.xml +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/pom.xml @@ -22,5 +22,10 @@ hsweb-system-schedule-dao-api ${project.version} + + + org.quartz-scheduler + quartz + \ No newline at end of file diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobExecutor.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobExecutor.java new file mode 100644 index 000000000..e41178b84 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobExecutor.java @@ -0,0 +1,12 @@ +package org.hswebframework.web.service.schedule; + +import java.util.Map; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public interface ScheduleJobExecutor { + Object doExecuteJob(String jobId, Map parameter); +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobService.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobService.java index d6cf30a8d..bfcbf7b69 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobService.java +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleJobService.java @@ -4,10 +4,13 @@ import org.hswebframework.web.entity.schedule.ScheduleJobEntity; import org.hswebframework.web.service.CrudService; /** - * 调度任务 服务类 + * 调度任务 服务类 * * @author hsweb-generator-online */ public interface ScheduleJobService extends CrudService { + void enable(String id); + + void disable(String id); } diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleTriggerBuilder.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleTriggerBuilder.java new file mode 100644 index 000000000..f68c3f0ef --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-api/src/main/java/org/hswebframework/web/service/schedule/ScheduleTriggerBuilder.java @@ -0,0 +1,12 @@ +package org.hswebframework.web.service.schedule; + +import org.quartz.spi.MutableTrigger; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public interface ScheduleTriggerBuilder { + MutableTrigger buildTrigger(String config); +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DefaultScriptScheduleJobExecutor.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DefaultScriptScheduleJobExecutor.java new file mode 100644 index 000000000..77e780cf8 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DefaultScriptScheduleJobExecutor.java @@ -0,0 +1,46 @@ +package org.hswebframework.web.service.schedule.simple; + +import org.apache.commons.codec.digest.DigestUtils; +import org.hswebframework.expands.script.engine.DynamicScriptEngine; +import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory; +import org.hswebframework.web.entity.schedule.ScheduleJobEntity; +import org.hswebframework.web.service.schedule.ScheduleJobExecutor; +import org.hswebframework.web.service.schedule.ScheduleJobService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * @author zhouhao + */ +@Service +public class DefaultScriptScheduleJobExecutor implements ScheduleJobExecutor { + + private ScheduleJobService scheduleJobService; + + @Autowired + public void setScheduleJobService(ScheduleJobService scheduleJobService) { + this.scheduleJobService = scheduleJobService; + } + + @Override + public Object doExecuteJob(String jobId, Map parameter) { + try { + ScheduleJobEntity jobEntity = scheduleJobService.selectByPk(jobId); + if (null == jobEntity) { + return null; + } + DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(jobEntity.getLanguage()); + + String jobMd5 = DigestUtils.md5Hex(jobEntity.getScript()); + //脚本发生变化,重新编译执行 + if (!jobMd5.equals(engine.getContext(jobId).getMd5())) { + engine.compile(jobId, jobEntity.getScript()); + } + return engine.execute(jobId, parameter).getIfSuccess(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJob.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJob.java new file mode 100644 index 000000000..850b1fdae --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJob.java @@ -0,0 +1,19 @@ +package org.hswebframework.web.service.schedule.simple; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +@DisallowConcurrentExecution +public class DynamicJob implements Job { + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJobFactory.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJobFactory.java new file mode 100644 index 000000000..46354e3f6 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/DynamicJobFactory.java @@ -0,0 +1,42 @@ +package org.hswebframework.web.service.schedule.simple; + +import org.hswebframework.web.service.schedule.ScheduleJobExecutor; +import org.quartz.Job; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.spi.JobFactory; +import org.quartz.spi.TriggerFiredBundle; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Map; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public class DynamicJobFactory implements JobFactory { + + public static final String JOB_ID_KEY = "dynamic-job-id:"; + + private JobFactory defaultFactory; + + private ScheduleJobExecutor scheduleJobExecutor; + + public DynamicJobFactory(JobFactory defaultFactory) { + this.defaultFactory = defaultFactory; + } + + @Autowired + public void setScheduleJobExecutor(ScheduleJobExecutor scheduleJobExecutor) { + this.scheduleJobExecutor = scheduleJobExecutor; + } + + @Override + public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { + Map data = bundle.getJobDetail().getJobDataMap(); + String jobId = (String) data.get(JOB_ID_KEY); + if (null == jobId || bundle.getJobDetail().getJobClass() != DynamicJob.class) return defaultFactory.newJob(bundle, scheduler); + return context -> scheduleJobExecutor.doExecuteJob(jobId, data); + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SimpleScheduleJobService.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SimpleScheduleJobService.java index 79ab48279..01531d0a5 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SimpleScheduleJobService.java +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SimpleScheduleJobService.java @@ -1,12 +1,26 @@ package org.hswebframework.web.service.schedule.simple; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.hswebframework.web.BusinessException; +import org.hswebframework.web.commons.entity.DataStatus; import org.hswebframework.web.dao.schedule.ScheduleJobDao; import org.hswebframework.web.entity.schedule.ScheduleJobEntity; -import org.hswebframework.web.service.GenericEntityService; import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.service.GenericEntityService; import org.hswebframework.web.service.schedule.ScheduleJobService; +import org.hswebframework.web.service.schedule.ScheduleTriggerBuilder; +import org.quartz.*; +import org.quartz.spi.MutableTrigger; +import org.quartz.spi.OperableTrigger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; /** * 默认的服务实现 @@ -18,13 +32,114 @@ public class SimpleScheduleJobService extends GenericEntityService getIDGenerator() { return IDGenerator.MD5; } + @Override public ScheduleJobDao getDao() { return scheduleJobDao; } + public static List computeFireTimesBetween(OperableTrigger trigger, + org.quartz.Calendar cal, Date from, Date to, int num) { + List lst = new LinkedList<>(); + OperableTrigger t = (OperableTrigger) trigger.clone(); + if (t.getNextFireTime() == null) { + t.setStartTime(from); + t.setEndTime(to); + t.computeFirstFireTime(cal); + } + for (int i = 0; i < num; i++) { + Date d = t.getNextFireTime(); + if (d != null) { + if (d.before(from)) { + t.triggered(cal); + continue; + } + if (d.after(to)) { + break; + } + lst.add(d); + t.triggered(cal); + } else { + break; + } + } + return lst; + } + + protected void startJob(ScheduleJobEntity jobEntity) { + JobDetail jobDetail = JobBuilder + .newJob(DynamicJob.class) + .withIdentity(createJobKey(jobEntity)) + .setJobData(createJobDataMap(jobEntity.getParameters())) + .usingJobData(DynamicJobFactory.JOB_ID_KEY, jobEntity.getId()) + .withDescription(jobEntity.getName() + (jobEntity.getRemark() == null ? "" : jobEntity.getRemark())) + .build(); + MutableTrigger trigger = scheduleTriggerBuilder.buildTrigger(jobEntity.getQuartzConfig()); + trigger.setKey(createTriggerKey(jobEntity)); + try { + scheduler.scheduleJob(jobDetail, trigger); + } catch (SchedulerException e) { + throw new BusinessException("启动定时调度失败", e); + } + } + + protected JobDataMap createJobDataMap(String parameters) { + JobDataMap map = new JobDataMap(); + if (!StringUtils.isEmpty(parameters)) { + JSONArray jsonArray = JSON.parseArray(parameters); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject o = jsonArray.getJSONObject(i); + map.put(o.getString("key"), o.get("value")); + } + } + return map; + } + + protected JobKey createJobKey(ScheduleJobEntity jobEntity) { + String group = jobEntity.getType() == null ? "hsweb.scheduler" : jobEntity.getType(); + + return new JobKey(jobEntity.getId(), group); + } + + protected TriggerKey createTriggerKey(ScheduleJobEntity jobEntity) { + String group = jobEntity.getType() == null ? "hsweb.scheduler" : jobEntity.getType(); + + return new TriggerKey(jobEntity.getId(), group); + } + + @Override + public void enable(String id) { + createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_ENABLED) + .where(ScheduleJobEntity.id, id).exec(); + startJob(selectByPk(id)); + } + + private void deleteJob(ScheduleJobEntity jobEntity) { + JobKey jobKey = createJobKey(jobEntity); + try { + if (scheduler.checkExists(jobKey)) { + scheduler.deleteJob(jobKey); + } + } catch (SchedulerException e) { + throw new BusinessException("更新任务失败", e, 500); + } + } + + @Override + public void disable(String id) { + createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_DISABLED) + .where(ScheduleJobEntity.id, id).exec(); + deleteJob(selectByPk(id)); + } } diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SmartScheduleTriggerBuilder.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SmartScheduleTriggerBuilder.java new file mode 100644 index 000000000..4721e231d --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-service/hsweb-system-schedule-service-simple/src/main/java/org/hswebframework/web/service/schedule/simple/SmartScheduleTriggerBuilder.java @@ -0,0 +1,30 @@ +package org.hswebframework.web.service.schedule.simple; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.hswebframework.web.service.schedule.ScheduleTriggerBuilder; +import org.quartz.CronScheduleBuilder; +import org.quartz.spi.MutableTrigger; +import org.springframework.stereotype.Service; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +@Service +public class SmartScheduleTriggerBuilder implements ScheduleTriggerBuilder { + @Override + public MutableTrigger buildTrigger(String config) { + JSONObject configObj = JSON.parseObject(config); + switch (configObj.getString("type")) { + case "cron": + String cron = configObj.getString("config"); + return CronScheduleBuilder.cronSchedule(cron) + .build(); + default: + throw new UnsupportedOperationException(config); + } + + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/pom.xml b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/pom.xml index 668ee4c9a..fa2a33293 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/pom.xml +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/pom.xml @@ -40,6 +40,11 @@ ${project.version} + + org.springframework + spring-context-support + + com.h2database h2 diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/AutoCreateTable.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/AutoCreateTable.java new file mode 100644 index 000000000..f474c1609 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/AutoCreateTable.java @@ -0,0 +1,51 @@ +package org.hswebframework.web.schedule.configuration; + +import org.hsweb.ezorm.rdb.executor.SqlExecutor; +import org.hswebframework.utils.file.FileUtils; +import org.hswebframework.web.Sqls; +import org.hswebframework.web.datasource.DataSourceHolder; +import org.hswebframework.web.datasource.DatabaseType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public class AutoCreateTable implements CommandLineRunner { + + @Autowired + private SqlExecutor sqlExecutor; + + @Override + public void run(String... args) throws Exception { + if (sqlExecutor.tableExists("QRTZ_LOCKS")) return; + + DatabaseType databaseType = DataSourceHolder.currentDatabaseType(); + String databaseTypeName = databaseType.name(); + if (databaseType == DatabaseType.jtds_sqlserver) { + databaseTypeName = DatabaseType.sqlserver.name(); + } + String file = "classpath*:/quartz/sql/quartz-" + databaseTypeName + "-create.sql"; + Resource[] resources = new PathMatchingResourcePatternResolver().getResources(file); + + for (Resource resource : resources) { + try (Reader reader = new InputStreamReader(resource.getInputStream())) { + String str = FileUtils.reader2String(reader); + List sqlList = Sqls.parse(str); + for (String sql : sqlList) { + sqlExecutor.exec(sql); + } + } + } + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/ScheduleAutoConfiguration.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/ScheduleAutoConfiguration.java new file mode 100644 index 000000000..98386f587 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/ScheduleAutoConfiguration.java @@ -0,0 +1,81 @@ +package org.hswebframework.web.schedule.configuration; + +import org.hswebframework.web.datasource.DataSourceHolder; +import org.hswebframework.web.datasource.DatabaseType; +import org.hswebframework.web.service.schedule.simple.DynamicJobFactory; +import org.quartz.Calendar; +import org.quartz.Scheduler; +import org.quartz.SchedulerListener; +import org.quartz.impl.StdSchedulerFactory; +import org.quartz.spi.JobFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.AdaptableJobFactory; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.util.Map; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +@Configuration +@EnableConfigurationProperties(SchedulerProperties.class) +@ConditionalOnMissingBean({Scheduler.class, SchedulerFactoryBean.class}) +public class ScheduleAutoConfiguration { + @Autowired + private SchedulerProperties schedulerProperties; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private DataSource dataSource; + + @Autowired + private PlatformTransactionManager platformTransactionManager; + + @Autowired(required = false) + private Map calendarMap; + + @Autowired(required = false) + private SchedulerListener[] schedulerListeners; + + @Bean + public JobFactory jobFactory() { + return new DynamicJobFactory(new AdaptableJobFactory()); + } + + @Bean + public AutoCreateTable autoCreateTable() { + return new AutoCreateTable(); + } + + @Bean + public SchedulerFactoryBean schedulerFactory(JobFactory jobFactory) { + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); + schedulerFactoryBean.setApplicationContext(applicationContext); + schedulerFactoryBean.setAutoStartup(schedulerProperties.isAutoStartup()); + schedulerFactoryBean.setDataSource(dataSource); + schedulerFactoryBean.setTransactionManager(platformTransactionManager); + schedulerFactoryBean.setOverwriteExistingJobs(schedulerProperties.isOverwriteExistingJobs()); + schedulerFactoryBean.setSchedulerFactoryClass(StdSchedulerFactory.class); + schedulerFactoryBean.setBeanName(schedulerProperties.getBeanName()); + schedulerFactoryBean.setJobFactory(jobFactory); + schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(schedulerProperties.isWaitOnShutdown()); + schedulerFactoryBean.setQuartzProperties(schedulerProperties.getProperties()); + schedulerFactoryBean.setStartupDelay(schedulerProperties.getStartupDelay()); + schedulerFactoryBean.setCalendars(calendarMap); + schedulerFactoryBean.setSchedulerListeners(schedulerListeners); + return schedulerFactoryBean; + } + + +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/SchedulerProperties.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/SchedulerProperties.java new file mode 100644 index 000000000..aa28c3d4d --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/java/org/hswebframework/web/schedule/configuration/SchedulerProperties.java @@ -0,0 +1,84 @@ +/* + * Copyright 2015-2016 http://hsweb.me + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hswebframework.web.schedule.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Properties; + +@ConfigurationProperties(prefix = "scheduler") +public class SchedulerProperties { + private boolean autoStartup = true; + + private boolean overwriteExistingJobs = true; + + private String beanName = "scheduler"; + + private boolean waitOnShutdown = true; + + private int startupDelay = 5; + + private Properties properties = new Properties(); + + public boolean isAutoStartup() { + return autoStartup; + } + + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + + public boolean isOverwriteExistingJobs() { + return overwriteExistingJobs; + } + + public void setOverwriteExistingJobs(boolean overwriteExistingJobs) { + this.overwriteExistingJobs = overwriteExistingJobs; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public boolean isWaitOnShutdown() { + return waitOnShutdown; + } + + public void setWaitOnShutdown(boolean waitOnShutdown) { + this.waitOnShutdown = waitOnShutdown; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + public int getStartupDelay() { + return startupDelay; + } + + public void setStartupDelay(int startupDelay) { + this.startupDelay = startupDelay; + } +} \ No newline at end of file diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/hsweb-starter.js b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/hsweb-starter.js index 8fc4a98c7..d037f95b7 100644 --- a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/hsweb-starter.js +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/hsweb-starter.js @@ -25,10 +25,10 @@ function install(context) { .addColumn().name("u_id").alias("id").comment("ID").jdbcType(java.sql.JDBCType.VARCHAR).length(32).primaryKey().commit() .addColumn().name("name").alias("name").comment("任务名称").jdbcType(java.sql.JDBCType.VARCHAR).length(128).commit() .addColumn().name("remark").alias("remark").comment("备注").jdbcType(java.sql.JDBCType.VARCHAR).length(512).commit() - .addColumn().name("quartz_config").alias("quartz_config").comment("定时调度配置").jdbcType(java.sql.JDBCType.CLOB).commit() + .addColumn().name("quartz_config").alias("quartzConfig").comment("定时调度配置").jdbcType(java.sql.JDBCType.CLOB).commit() .addColumn().name("script").alias("script").comment("执行脚本").jdbcType(java.sql.JDBCType.CLOB).commit() .addColumn().name("language").alias("language").comment("脚本语言").jdbcType(java.sql.JDBCType.VARCHAR).length(32).commit() - .addColumn().name("enabled").alias("enabled").comment("是否启用").jdbcType(java.sql.JDBCType.DECIMAL).length(4,0).commit() + .addColumn().name("status").alias("status").comment("是否启用").jdbcType(java.sql.JDBCType.DECIMAL).length(4,0).commit() .addColumn().name("parameters").alias("parameters").comment("启动参数").jdbcType(java.sql.JDBCType.CLOB).commit() .addColumn().name("type").alias("type").comment("任务类型").jdbcType(java.sql.JDBCType.VARCHAR).length(32).commit() .addColumn().name("tags").alias("tags").comment("标签").jdbcType(java.sql.JDBCType.VARCHAR).length(512).commit() diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-h2-create.sql b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-h2-create.sql new file mode 100644 index 000000000..dcb0638cd --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-h2-create.sql @@ -0,0 +1,247 @@ +-- Thanks to Amir Kibbar and Peter Rietzler for contributing the schema for H2 database, +-- and verifying that it works with Quartz's StdJDBCDelegate +-- +-- Note, Quartz depends on row-level locking which means you must use the MVCC=TRUE +-- setting on your H2 database, or you will experience dead-locks +-- +-- +-- In your Quartz properties file, you'll need to set +-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate + +CREATE TABLE QRTZ_CALENDARS ( + SCHED_NAME VARCHAR(120) NOT NULL, + CALENDAR_NAME VARCHAR (200) NOT NULL , + CALENDAR IMAGE NOT NULL +); + +CREATE TABLE QRTZ_CRON_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + CRON_EXPRESSION VARCHAR (120) NOT NULL , + TIME_ZONE_ID VARCHAR (80) +); + +CREATE TABLE QRTZ_FIRED_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + ENTRY_ID VARCHAR (95) NOT NULL , + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + INSTANCE_NAME VARCHAR (200) NOT NULL , + FIRED_TIME BIGINT NOT NULL , + SCHED_TIME BIGINT NOT NULL , + PRIORITY INTEGER NOT NULL , + STATE VARCHAR (16) NOT NULL, + JOB_NAME VARCHAR (200) NULL , + JOB_GROUP VARCHAR (200) NULL , + IS_NONCONCURRENT BOOLEAN NULL , + REQUESTS_RECOVERY BOOLEAN NULL +); + +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_GROUP VARCHAR (200) NOT NULL +); + +CREATE TABLE QRTZ_SCHEDULER_STATE ( + SCHED_NAME VARCHAR(120) NOT NULL, + INSTANCE_NAME VARCHAR (200) NOT NULL , + LAST_CHECKIN_TIME BIGINT NOT NULL , + CHECKIN_INTERVAL BIGINT NOT NULL +); + +CREATE TABLE QRTZ_LOCKS ( + SCHED_NAME VARCHAR(120) NOT NULL, + LOCK_NAME VARCHAR (40) NOT NULL +); + +CREATE TABLE QRTZ_JOB_DETAILS ( + SCHED_NAME VARCHAR(120) NOT NULL, + JOB_NAME VARCHAR (200) NOT NULL , + JOB_GROUP VARCHAR (200) NOT NULL , + DESCRIPTION VARCHAR (250) NULL , + JOB_CLASS_NAME VARCHAR (250) NOT NULL , + IS_DURABLE BOOLEAN NOT NULL , + IS_NONCONCURRENT BOOLEAN NOT NULL , + IS_UPDATE_DATA BOOLEAN NOT NULL , + REQUESTS_RECOVERY BOOLEAN NOT NULL , + JOB_DATA IMAGE NULL +); + +CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + REPEAT_COUNT BIGINT NOT NULL , + REPEAT_INTERVAL BIGINT NOT NULL , + TIMES_TRIGGERED BIGINT NOT NULL +); + +CREATE TABLE qrtz_simprop_triggers + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INTEGER NULL, + INT_PROP_2 INTEGER NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 BOOLEAN NULL, + BOOL_PROP_2 BOOLEAN NULL, +); + +CREATE TABLE QRTZ_BLOB_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + BLOB_DATA IMAGE NULL +); + +CREATE TABLE QRTZ_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + JOB_NAME VARCHAR (200) NOT NULL , + JOB_GROUP VARCHAR (200) NOT NULL , + DESCRIPTION VARCHAR (250) NULL , + NEXT_FIRE_TIME BIGINT NULL , + PREV_FIRE_TIME BIGINT NULL , + PRIORITY INTEGER NULL , + TRIGGER_STATE VARCHAR (16) NOT NULL , + TRIGGER_TYPE VARCHAR (8) NOT NULL , + START_TIME BIGINT NOT NULL , + END_TIME BIGINT NULL , + CALENDAR_NAME VARCHAR (200) NULL , + MISFIRE_INSTR SMALLINT NULL , + JOB_DATA IMAGE NULL +); + +ALTER TABLE QRTZ_CALENDARS ADD + CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY + ( + SCHED_NAME, + CALENDAR_NAME + ); + +ALTER TABLE QRTZ_CRON_TRIGGERS ADD + CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_FIRED_TRIGGERS ADD + CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + ENTRY_ID + ); + +ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD + CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_SCHEDULER_STATE ADD + CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY + ( + SCHED_NAME, + INSTANCE_NAME + ); + +ALTER TABLE QRTZ_LOCKS ADD + CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY + ( + SCHED_NAME, + LOCK_NAME + ); + +ALTER TABLE QRTZ_JOB_DETAILS ADD + CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY + ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ); + +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD + CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD + CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_TRIGGERS ADD + CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_CRON_TRIGGERS ADD + CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + + +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD + CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD + CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + + +ALTER TABLE QRTZ_TRIGGERS ADD + CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY + ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ) REFERENCES QRTZ_JOB_DETAILS ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ); diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-mysql-create.sql b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-mysql-create.sql new file mode 100644 index 000000000..41fe6b946 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-mysql-create.sql @@ -0,0 +1,143 @@ +CREATE TABLE QRTZ_JOB_DETAILS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + JOB_CLASS_NAME VARCHAR(250) NOT NULL, + IS_DURABLE VARCHAR(1) NOT NULL, + IS_NONCONCURRENT VARCHAR(1) NOT NULL, + IS_UPDATE_DATA VARCHAR(1) NOT NULL, + REQUESTS_RECOVERY VARCHAR(1) NOT NULL, + JOB_DATA BLOB NULL, + PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE QRTZ_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + NEXT_FIRE_TIME BIGINT(13) NULL, + PREV_FIRE_TIME BIGINT(13) NULL, + PRIORITY INTEGER NULL, + TRIGGER_STATE VARCHAR(16) NOT NULL, + TRIGGER_TYPE VARCHAR(8) NOT NULL, + START_TIME BIGINT(13) NOT NULL, + END_TIME BIGINT(13) NULL, + CALENDAR_NAME VARCHAR(200) NULL, + MISFIRE_INSTR SMALLINT(2) NULL, + JOB_DATA BLOB NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) + REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE QRTZ_SIMPLE_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + REPEAT_COUNT BIGINT(7) NOT NULL, + REPEAT_INTERVAL BIGINT(12) NOT NULL, + TIMES_TRIGGERED BIGINT(10) NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE QRTZ_CRON_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + CRON_EXPRESSION VARCHAR(200) NOT NULL, + TIME_ZONE_ID VARCHAR(80), + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE QRTZ_SIMPROP_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INT NULL, + INT_PROP_2 INT NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 VARCHAR(1) NULL, + BOOL_PROP_2 VARCHAR(1) NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE QRTZ_BLOB_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + BLOB_DATA BLOB NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE QRTZ_CALENDARS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + CALENDAR_NAME VARCHAR(200) NOT NULL, + CALENDAR BLOB NOT NULL, + PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) +); + +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) +); + +CREATE TABLE QRTZ_FIRED_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + ENTRY_ID VARCHAR(95) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + FIRED_TIME BIGINT(13) NOT NULL, + SCHED_TIME BIGINT(13) NOT NULL, + PRIORITY INTEGER NOT NULL, + STATE VARCHAR(16) NOT NULL, + JOB_NAME VARCHAR(200) NULL, + JOB_GROUP VARCHAR(200) NULL, + IS_NONCONCURRENT VARCHAR(1) NULL, + REQUESTS_RECOVERY VARCHAR(1) NULL, + PRIMARY KEY (SCHED_NAME,ENTRY_ID) +); + +CREATE TABLE QRTZ_SCHEDULER_STATE + ( + SCHED_NAME VARCHAR(120) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + LAST_CHECKIN_TIME BIGINT(13) NOT NULL, + CHECKIN_INTERVAL BIGINT(13) NOT NULL, + PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) +); + +CREATE TABLE QRTZ_LOCKS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + LOCK_NAME VARCHAR(40) NOT NULL, + PRIMARY KEY (SCHED_NAME,LOCK_NAME) +); diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-oracle-create.sql b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-oracle-create.sql new file mode 100644 index 000000000..c381d9d4e --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/main/resources/quartz/sql/quartz-oracle-create.sql @@ -0,0 +1,157 @@ +CREATE TABLE qrtz_job_details + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + JOB_NAME VARCHAR2(200) NOT NULL, + JOB_GROUP VARCHAR2(200) NOT NULL, + DESCRIPTION VARCHAR2(250) NULL, + JOB_CLASS_NAME VARCHAR2(250) NOT NULL, + IS_DURABLE VARCHAR2(1) NOT NULL, + IS_NONCONCURRENT VARCHAR2(1) NOT NULL, + IS_UPDATE_DATA VARCHAR2(1) NOT NULL, + REQUESTS_RECOVERY VARCHAR2(1) NOT NULL, + JOB_DATA BLOB NULL, + CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +); +CREATE TABLE qrtz_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + JOB_NAME VARCHAR2(200) NOT NULL, + JOB_GROUP VARCHAR2(200) NOT NULL, + DESCRIPTION VARCHAR2(250) NULL, + NEXT_FIRE_TIME NUMBER(13) NULL, + PREV_FIRE_TIME NUMBER(13) NULL, + PRIORITY NUMBER(13) NULL, + TRIGGER_STATE VARCHAR2(16) NOT NULL, + TRIGGER_TYPE VARCHAR2(8) NOT NULL, + START_TIME NUMBER(13) NOT NULL, + END_TIME NUMBER(13) NULL, + CALENDAR_NAME VARCHAR2(200) NULL, + MISFIRE_INSTR NUMBER(2) NULL, + JOB_DATA BLOB NULL, + CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) + REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) +); +CREATE TABLE qrtz_simple_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + REPEAT_COUNT NUMBER(7) NOT NULL, + REPEAT_INTERVAL NUMBER(12) NOT NULL, + TIMES_TRIGGERED NUMBER(10) NOT NULL, + CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); +CREATE TABLE qrtz_cron_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + CRON_EXPRESSION VARCHAR2(120) NOT NULL, + TIME_ZONE_ID VARCHAR2(80), + CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); +CREATE TABLE qrtz_simprop_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + STR_PROP_1 VARCHAR2(512) NULL, + STR_PROP_2 VARCHAR2(512) NULL, + STR_PROP_3 VARCHAR2(512) NULL, + INT_PROP_1 NUMBER(10) NULL, + INT_PROP_2 NUMBER(10) NULL, + LONG_PROP_1 NUMBER(13) NULL, + LONG_PROP_2 NUMBER(13) NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 VARCHAR2(1) NULL, + BOOL_PROP_2 VARCHAR2(1) NULL, + CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); +CREATE TABLE qrtz_blob_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + BLOB_DATA BLOB NULL, + CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); +CREATE TABLE qrtz_calendars + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + CALENDAR_NAME VARCHAR2(200) NOT NULL, + CALENDAR BLOB NOT NULL, + CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) +); +CREATE TABLE qrtz_paused_trigger_grps + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) +); +CREATE TABLE qrtz_fired_triggers + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + ENTRY_ID VARCHAR2(95) NOT NULL, + TRIGGER_NAME VARCHAR2(200) NOT NULL, + TRIGGER_GROUP VARCHAR2(200) NOT NULL, + INSTANCE_NAME VARCHAR2(200) NOT NULL, + FIRED_TIME NUMBER(13) NOT NULL, + SCHED_TIME NUMBER(13) NOT NULL, + PRIORITY NUMBER(13) NOT NULL, + STATE VARCHAR2(16) NOT NULL, + JOB_NAME VARCHAR2(200) NULL, + JOB_GROUP VARCHAR2(200) NULL, + IS_NONCONCURRENT VARCHAR2(1) NULL, + REQUESTS_RECOVERY VARCHAR2(1) NULL, + CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID) +); +CREATE TABLE qrtz_scheduler_state + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + INSTANCE_NAME VARCHAR2(200) NOT NULL, + LAST_CHECKIN_TIME NUMBER(13) NOT NULL, + CHECKIN_INTERVAL NUMBER(13) NOT NULL, + CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) +); +CREATE TABLE qrtz_locks + ( + SCHED_NAME VARCHAR2(120) NOT NULL, + LOCK_NAME VARCHAR2(40) NOT NULL, + CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME) +); + +create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP); + +create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME); +create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP); +create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE); +create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); +create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); + +create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME); +create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); +create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP); + diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/DynamicScheduleTests.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/DynamicScheduleTests.java new file mode 100644 index 000000000..1455a8d65 --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/DynamicScheduleTests.java @@ -0,0 +1,39 @@ +package org.hswebframework.web.schedule.test; + +import org.hswebframework.web.commons.entity.DataStatus; +import org.hswebframework.web.entity.schedule.ScheduleJobEntity; +import org.hswebframework.web.service.schedule.ScheduleJobService; +import org.hswebframework.web.tests.SimpleWebApplicationTests; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +public class DynamicScheduleTests extends SimpleWebApplicationTests { + + @Autowired + private ScheduleJobService scheduleJobService; + + + public ScheduleJobEntity createJob() { + ScheduleJobEntity entity = scheduleJobService.createEntity(); + entity.setStatus(DataStatus.STATUS_ENABLED); + entity.setType("test"); + entity.setLanguage("javascript"); + entity.setScript("java.lang.System.out.println('job running...')"); + entity.setQuartzConfig("{\"type\":\"cron\",\"config\":\"0/5 * * * * ?\"}"); + return entity; + } + + @Test + public void testCreateJob() throws InterruptedException { + Thread.sleep(5000); + String id = scheduleJobService.insert(createJob()); + scheduleJobService.enable(id); + + Thread.sleep(40000); + } +} diff --git a/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/ScheduleTests.java b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/ScheduleTests.java new file mode 100644 index 000000000..46899701c --- /dev/null +++ b/hsweb-system/hsweb-system-schedule/hsweb-system-schedule-starter/src/test/java/org/hswebframework/web/schedule/test/ScheduleTests.java @@ -0,0 +1,35 @@ +package org.hswebframework.web.schedule.test; + +import org.hswebframework.web.tests.SimpleWebApplicationTests; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * TODO 完成注释 + * + * @author zhouhao + */ +@EnableScheduling +@Configuration +public class ScheduleTests extends SimpleWebApplicationTests { + + AtomicInteger counter = new AtomicInteger(); + + @Scheduled(cron = "0/1 * * * * ?") + public void quartzTest() { + System.out.println(1234); + counter.incrementAndGet(); + } + + @Test + public void test() throws InterruptedException { + Thread.sleep(10000); + Assert.assertTrue(counter.get() > 0); + System.out.println(counter.get()); + } +} diff --git a/hsweb-system/hsweb-system-schedule/pom.xml b/hsweb-system/hsweb-system-schedule/pom.xml index 76eac995e..0a24e158e 100644 --- a/hsweb-system/hsweb-system-schedule/pom.xml +++ b/hsweb-system/hsweb-system-schedule/pom.xml @@ -18,4 +18,13 @@ hsweb-system-schedule-starter + + + + org.quartz-scheduler + quartz + 2.2.3 + + + \ No newline at end of file diff --git a/hsweb-system/hsweb-system-script/hsweb-system-script-service/hsweb-system-script-service-simple/src/main/java/org/hswebframework/web/service/script/simple/SimpleScriptService.java b/hsweb-system/hsweb-system-script/hsweb-system-script-service/hsweb-system-script-service-simple/src/main/java/org/hswebframework/web/service/script/simple/SimpleScriptService.java index ecbf7ba2d..a62562410 100644 --- a/hsweb-system/hsweb-system-script/hsweb-system-script-service/hsweb-system-script-service-simple/src/main/java/org/hswebframework/web/service/script/simple/SimpleScriptService.java +++ b/hsweb-system/hsweb-system-script/hsweb-system-script-service/hsweb-system-script-service-simple/src/main/java/org/hswebframework/web/service/script/simple/SimpleScriptService.java @@ -18,10 +18,12 @@ public class SimpleScriptService extends GenericEntityService getIDGenerator() { return IDGenerator.MD5; } + @Override public ScriptDao getDao() { return scriptDao;