diff --git a/smtweb-framework/bpm/pom.xml b/smtweb-framework/bpm/pom.xml index 867b1d7..2fd5116 100644 --- a/smtweb-framework/bpm/pom.xml +++ b/smtweb-framework/bpm/pom.xml @@ -35,6 +35,10 @@ spring-boot-starter-freemarker + org.quartz-scheduler + quartz + + net.coobird thumbnailator [0.4, 0.5) diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/BpmStartedListener.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/BpmStartedListener.java index 3c830c4..f640834 100644 --- a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/BpmStartedListener.java +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/BpmStartedListener.java @@ -26,6 +26,7 @@ public class BpmStartedListener implements IStartListener { SwConsts.SysParam.RUN_PROJECTS = "bpm"; SysServiceFactory.getInstance().reg(new OneTimeTaskCleanService()); TreeHelper.regTreeHelper(ModelCatalog.ENTITY_NAME, ModelCatalogTreeHelper.class); + } @Override @@ -36,4 +37,9 @@ public class BpmStartedListener implements IStartListener { CacheManager.getIntance().init(); OneTimeServiceFactory.getInstance().start(); } + + @Override + public void close() { + OneTimeServiceFactory.getInstance().stop(); + } } diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/BaseJob.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/BaseJob.java new file mode 100644 index 0000000..86cbbb2 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/BaseJob.java @@ -0,0 +1,57 @@ +package cc.smtweb.system.bpm.web.sys.base.job; + +import cc.smtweb.framework.core.common.SwConsts; +import cc.smtweb.framework.core.db.DbEngine; +import cc.smtweb.framework.core.db.jdbc.ISimpleWorker; +import cc.smtweb.framework.core.systask.SingleRequestHelper; +import cc.smtweb.framework.core.util.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +/** + * Created by Akmm at 2022-09-14 09:51 + * 定时任务的基类 + */ +@Slf4j +public abstract class BaseJob implements Job { + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + JobEntity job = (JobEntity) jobExecutionContext.getJobDetail().getJobDataMap().get("job"); + + final String id = this.getClass().getName(); + SingleRequestHelper.singleRequest(SwConsts.REDIS_KEY_BASE_JOB, id, job.getName() + "任务执行中,本次忽略.........", () -> { + JobLog jlog = startLog(job); + try { + String info = work(); + endLog(jlog, true, info); + } catch (Exception e) { + endLog(jlog, false, e.getMessage()); + log.error(job.getName() + ":::执行失败", e); + } + + }); + } + + //任务执行信息,可返回执行结果 + protected abstract String work(); + + //存任务日志-开始 + private JobLog startLog(JobEntity job) { + JobLog jlog = new JobLog(); + jlog.setId(DbEngine.getInstance().nextId()); + jlog.setSjId(job.getId()); + jlog.setBeginTime(DateUtil.nowDateTimeLong()); + DbEngine.getInstance().doTransSingle(() -> DbEngine.getInstance().findDao(JobLog.class).insertEntity(jlog)); + return jlog; + } + + //存任务日志-结束 + private void endLog(JobLog jlog, boolean sucess, String info) { + jlog.setEndTime(DateUtil.nowDateTimeLong()); + jlog.setSuccess(sucess); + jlog.setInfo(info); + DbEngine.getInstance().doTransSingle(() -> DbEngine.getInstance().findDao(JobLog.class).updateEntity(jlog)); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobCache.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobCache.java new file mode 100644 index 0000000..40c4594 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobCache.java @@ -0,0 +1,30 @@ +package cc.smtweb.system.bpm.web.sys.base.job; + +import cc.smtweb.framework.core.annotation.SwCache; +import cc.smtweb.framework.core.cache.AbstractEntityCache; +import cc.smtweb.framework.core.cache.CacheManager; + +/** + * Created by 1 at 2022-09-13 19:35:56 + * 实体【[定时任务](SYS_JOB)】的缓存类 + */ +@SwCache(ident = "SYS_JOB", title = "定时任务") +public class JobCache extends AbstractEntityCache { + //缓存key:按编码 + public final static String mk_code = "code"; + + public static JobCache getInstance() { + return CacheManager.getIntance().getCache(JobCache.class); + } + + public JobCache() { + //缓存key:按编码 + regMap(mk_code, "sj_code"); + } + + //缓存key:按编码 + public final JobEntity getByCode(String key) { + return getByKey(mk_code, key); + } + +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobEntity.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobEntity.java new file mode 100644 index 0000000..b7ec032 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobEntity.java @@ -0,0 +1,81 @@ +package cc.smtweb.system.bpm.web.sys.base.job; + +import cc.smtweb.framework.core.annotation.SwTable; +import cc.smtweb.framework.core.db.impl.DefaultEntity; + +/** + * Created by 1 at 2022-09-13 19:35:56 + * 实体【[定时任务](SYS_JOB)】的Entity类 + */ +@SwTable("SYS_JOB") +public class JobEntity extends DefaultEntity { + public static final String ENTITY_NAME = "SYS_JOB"; + + public JobEntity() { + super(ENTITY_NAME); + } + + /** 主键 */ + public long getId() { + return getLong("sj_id"); + } + + /** 主键 */ + public void setId(long sj_id) { + put("sj_id", sj_id); + } + /** 编码 */ + public String getCode() { + return getStr("sj_code"); + } + + /** 编码 */ + public void setCode(String sj_code) { + put("sj_code", sj_code); + } + /** 名称 */ + public String getName() { + return getStr("sj_name"); + } + + /** 名称 */ + public void setName(String sj_name) { + put("sj_name", sj_name); + } + /** 执行类的路径 */ + public String getExeClass() { + return getStr("sj_exe_class"); + } + + /** 执行类的路径 */ + public void setExeClass(String sj_exe_class) { + put("sj_exe_class", sj_exe_class); + } + /** cron表达式 */ + public String getCron() { + return getStr("sj_cron"); + } + + /** cron表达式 */ + public void setCron(String sj_cron) { + put("sj_cron", sj_cron); + } + /** 是否启用 */ + public boolean isEnable() { + return getBool("sj_enable"); + } + + /** 是否启用 */ + public void setEnable(boolean sj_enable) { + setBool("sj_enable", sj_enable); + } + /** 备注 */ + public String getRemark() { + return getStr("sj_remark"); + } + + /** 备注 */ + public void setRemark(String sj_remark) { + put("sj_remark", sj_remark); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobLog.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobLog.java new file mode 100644 index 0000000..9d8e5a9 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobLog.java @@ -0,0 +1,102 @@ +package cc.smtweb.system.bpm.web.sys.base.job; + +import cc.smtweb.framework.core.annotation.SwTable; +import cc.smtweb.framework.core.common.SwMap; +import cc.smtweb.framework.core.db.impl.DefaultEntity; + +/** + * Created by 1 at 2022-09-14 10:09:03 + * 实体【[定时任务执行日志](SYS_JOB_LOG)】的Entity类 + */ +@SwTable("SYS_JOB_LOG") +public class JobLog extends DefaultEntity { + public static final String ENTITY_NAME = "SYS_JOB_LOG"; + + public JobLog() { + super(ENTITY_NAME); + } + + /** + * 主键 + */ + public long getId() { + return getLong("sjl_id"); + } + + /** + * 主键 + */ + public void setId(long sjl_id) { + put("sjl_id", sjl_id); + } + + /** + * 任务id + */ + public long getSjId() { + return getLong("sjl_sj_id"); + } + + /** + * 任务id + */ + public void setSjId(long sjl_sj_id) { + put("sjl_sj_id", sjl_sj_id); + } + + /** + * 开始时间 + */ + public long getBeginTime() { + return getLong("sjl_begin_time"); + } + + /** + * 开始时间 + */ + public void setBeginTime(long sjl_begin_time) { + put("sjl_begin_time", sjl_begin_time); + } + + /** + * 完成时间 + */ + public long getEndTime() { + return getLong("sjl_end_time"); + } + + /** + * 完成时间 + */ + public void setEndTime(long sjl_end_time) { + put("sjl_end_time", sjl_end_time); + } + + /** + * 是否成功 + */ + public boolean isSuccess() { + return getBool("sjl_success"); + } + + /** + * 是否成功 + */ + public void setSuccess(boolean sjl_success) { + setBool("sjl_success", sjl_success); + } + + /** + * 执行情况 + */ + public String getInfo() { + return getStr("sjl_info"); + } + + /** + * 执行情况 + */ + public void setInfo(String sjl_info) { + put("sjl_info", sjl_info); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobUtils.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobUtils.java new file mode 100644 index 0000000..ca10395 --- /dev/null +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/base/job/JobUtils.java @@ -0,0 +1,113 @@ +package cc.smtweb.system.bpm.web.sys.base.job; + +import lombok.extern.slf4j.Slf4j; +import org.quartz.*; +import org.quartz.impl.StdSchedulerFactory; + +import java.util.*; + +/** + * Created by Akmm at 13-2-27 下午9:32 + * 定时任务工厂 + */ +@Slf4j +public class JobUtils { + private static Scheduler scheduler = null; + private static JobUtils instance = null; + private Map mapJob = new HashMap<>(); + + + public static Scheduler getScheduler() { + return scheduler; + } + + public static JobUtils getInstance() { + if (instance == null) { + synchronized (JobUtils.class) { + if (instance == null) { + instance = new JobUtils(); + } + } + } + return instance; + } + + private JobUtils() { + try { + SchedulerFactory schedulerFactory = new StdSchedulerFactory(); + scheduler = schedulerFactory.getScheduler(); + } catch (Exception e) { + log.error("计划任务初始化失败", e); + e.printStackTrace(); + } + } + + //初始化所有任务 + private void initJob() throws Exception { + Collection list = JobCache.getInstance().getAll(); + for (JobEntity job : list) { + if (job.isEnable()) { + addJob(job); + } + } + + } + + public void start() { + try { + clear(); + if (!scheduler.isStarted()) scheduler.start(); + initJob(); + } catch (Exception e) { + log.error("计划任务开始失败", e); + e.printStackTrace(); + } + } + + public void stop() { + try { + if (!scheduler.isShutdown()) { + clear(); + scheduler.shutdown(); + } + } catch (Exception e) { + log.error("计划任务开始失败", e); + e.printStackTrace(); + } + } + + public void clear() throws SchedulerException { + for (JobEntity job : mapJob.values()) { + try { + deleteJob(job); + } catch (Exception e) { + log.debug("任务" + job.getId() + "删除失败!"); + } + } + } + + //添加任务 + public synchronized void addJob(JobEntity job) throws Exception { + String jobId = String.valueOf(job.getId()); + JobDetail jobDetail = JobBuilder.newJob((Class) Class.forName(job.getExeClass())) + .withIdentity(jobId).build(); + jobDetail.getJobDataMap().put("job", job); + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger() + .withIdentity(jobId) + .startNow() + .withSchedule(CronScheduleBuilder.cronSchedule(job.getCron())) + .build(); + + scheduler.scheduleJob(jobDetail, trigger); + } + + //删除任务 + public synchronized void deleteJob(JobEntity job) throws Exception { + String jobId = String.valueOf(job.getId()); + + scheduler.pauseTrigger(TriggerKey.triggerKey(jobId)); + scheduler.unscheduleJob(TriggerKey.triggerKey(jobId)); + scheduler.deleteJob(JobKey.jobKey(jobId)); + } +} diff --git a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/oneTimeService/OneTimeTaskCleanService.java b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/oneTimeService/OneTimeTaskCleanService.java index a7c9c7e..66dbf6c 100644 --- a/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/oneTimeService/OneTimeTaskCleanService.java +++ b/smtweb-framework/bpm/src/main/java/cc/smtweb/system/bpm/web/sys/oneTimeService/OneTimeTaskCleanService.java @@ -21,8 +21,8 @@ public class OneTimeTaskCleanService extends BaseSysService { } @Override - public void work() throws Exception { + public void work() { String t = DateUtil.getNowYm() + "01000000"; - DbEngine.getInstance().update("delete from " + EntityHelper.getSchemaTableName(OnetimeTask.ENTITY_NAME) + " where statu=? and create_time { + @Override + public void onApplicationEvent(ContextClosedEvent event) { + SysServiceFactory.getInstance().stop(); + List list = BeanManager.getInstance().getStartListeners(); + list.sort(Comparator.comparingInt(IStartListener::order)); + for (IStartListener sl : list) { + sl.close(); + } + } +} diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java index 629b789..822539d 100644 --- a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java @@ -4,6 +4,7 @@ import cc.smtweb.framework.core.common.SwConsts; import cc.smtweb.framework.core.mvc.controller.IStartListener; import cc.smtweb.framework.core.mvc.controller.scan.ApplicationScanner; import cc.smtweb.framework.core.mvc.controller.scan.BeanManager; +import cc.smtweb.framework.core.systask.SysServiceFactory; import cc.smtweb.framework.core.systask.WebStartedEvent; import lombok.SneakyThrows; import org.springframework.boot.context.event.ApplicationStartedEvent; @@ -38,6 +39,7 @@ public class CoreApplicationStartedListener implements ApplicationListener { + long time = System.currentTimeMillis(); + if (isPrintLog()) { + log.debug(getTitle() + ":::开始执行........."); + } + work(); + if (isPrintLog()) { + log.debug(getTitle() + ":::执行完成,耗时:" + (System.currentTimeMillis() - time) + "毫秒........."); } }); } catch (Exception e) { @@ -42,5 +39,5 @@ public abstract class BaseSysService implements Runnable { } //主要要干的活 - protected abstract void work() throws Exception; + protected abstract void work(); } diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SingleRequestHelper.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SingleRequestHelper.java index 5997a52..d701938 100644 --- a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SingleRequestHelper.java +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SingleRequestHelper.java @@ -8,15 +8,15 @@ import cc.smtweb.framework.core.util.StringUtil; public class SingleRequestHelper { public static interface ISingleWork { - void doSingleWork() throws Exception; + void doSingleWork(); } - public static void singleRequest(String region_key, String key, ISingleWork singleWork) throws Exception { + public static void singleRequest(String region_key, String key, ISingleWork singleWork) { singleRequest(region_key, key, "其他人正在执行该操作,请等待!", singleWork); } - public static void singleRequest(String region_key, String key, String tip_msg, ISingleWork singleWork) throws Exception { + public static void singleRequest(String region_key, String key, String tip_msg, ISingleWork singleWork) { boolean clearCache = false; try { String lastTime = RedisManager.getInstance().hGet(region_key, key, String.class); diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SysServiceFactory.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SysServiceFactory.java index bfa82d5..c90f6f8 100644 --- a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SysServiceFactory.java +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/systask/SysServiceFactory.java @@ -39,7 +39,7 @@ public class SysServiceFactory { //启动任务 - protected void start() { + public void start() { if (schedule != null) { stop(); } @@ -52,7 +52,7 @@ public class SysServiceFactory { } //停止任务 - protected void stop() { + public void stop() { schedule.shutdown(); } }