一、版本说明
spring3.1以上的版本才支持quartz 2.x,不然会出错。 此示例所选版本:spring版本号4.3.18.RELEASE,quartz版本2.3.0。
二、添加jar包
我的是maven工程,pom.xml相关配置如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.18.RELEASE</spring.version>
<quartz.version>2.3.0</quartz.version>
</properties>
<dependencies>
<!-- quartz begin -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>${quartz.version}</version>
</dependency>
<!-- quartz end -->
</dependencies>
三、整合实现
1、QuartzActiveJob 定时任务工作类
package com.whitelake.modules.sys.task;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import com.whitelake.modules.mes.wechat.entity.MesEventSourceTask;
import com.whitelake.modules.mes.wechat.service.MesEventSourceTaskService;
import com.whitelake.modules.mes.wechat.service.WechatService;
import com.whitelake.modules.sys.entity.User;
import com.whitelake.modules.sys.util.UserUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 实现Job接口,定义运行的任务
* 发送微信消息
* @author lixiuwu
* @date 2018年12月18日
*
*/
@Component
public class QuartzActiveJob implements Job {
private static Logger log = LoggerFactory.getLogger(QuartzActiveJob.class);
@Autowired
private MesEventSourceTaskService eventSourceTaskService;
@Autowired
private WechatService wechatService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 使得job对象可以通过注解实现依赖注入
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
// JobExecutionContext类提供了调度上线问的各种信息,为JobDetail和Trigger提供必要的信息
// JobKey是由name和group组成,并且name必须在group内是唯一的。如果只指定一组则将使用默认的组名。
JobKey jobKey = context.getJobDetail().getKey();
log.info("QuartzActiveJob says: " + jobKey + " executing at " + new Date());
String taskId = jobKey.getName(); //定时任务表ID
MesEventSourceTask eventSourceTask = eventSourceTaskService.get(taskId);
//将相应数据插入到待发送表中
User user = UserUtils.getUser();
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); //当前时间
String eventSourceCode = eventSourceTask.getEventSource().getCode(); //事件编码
Integer beforeDays = eventSourceTask.getBeforeDays(); //提前天数
List<Map<String,Object>> listMap = eventSourceTaskService.getJsonData(eventSourceCode,beforeDays,user.getCorpId()); //根据事件编码取出对应数据
for (int i = 0; i < listMap.size(); i++) {
Map<String,Object> map = listMap.get(i);
String id = null,total=null;
if(map.get("id")!=null){
id = map.get("id").toString();
}
if(map.get("total")!=null){
total = map.get("total").toString();
}
String userId = map.get("userId").toString(); //创建者ID
String userName = map.get("userName").toString(); //用户名称
//将相应数据插入到待发送表中
if("produce_work_order_day_quant_notice".equals(eventSourceCode)){ //生产工单-日完工数量通知
wechatService.dataSourceParms(user.getCorpId(),eventSourceCode,userId,userName,currentTime,
"/mes/mesReportWorkOrder/list","",total,"","","","","","","","","");
}else if("produce_flow_card_day_quant_notice".equals(eventSourceCode)){ //生产流转卡-日完工数量通知
wechatService.dataSourceParms(user.getCorpId(),eventSourceCode,userId,userName,currentTime,
"/mes/mesReportFlowCard/list","",total,"","","","","","","","","");
}else if("sale_bill_ship_date_warn".equals(eventSourceCode)){ //销售订单-发货日期预警
wechatService.dataSourceParms(user.getCorpId(),eventSourceCode,userId,userName,currentTime,
"/mes/mesSaleBill/form?id="+id,"",beforeDays.toString(),"","","","","","","","","");
}else if("produce_bill_start_date_warn".equals(eventSourceCode)){ //生产订单-开工日期预警
wechatService.dataSourceParms(user.getCorpId(),eventSourceCode,userId,userName,currentTime,
"/mes/mesProductionBill/form?id="+id,"",beforeDays.toString(),"","","","","","","","","");
}else if("produce_bill_end_date_warn".equals(eventSourceCode)){ //生产订单-完工日期预警
wechatService.dataSourceParms(user.getCorpId(),eventSourceCode,userId,userName,currentTime,
"/mes/mesProductionBill/form?id="+id,"",beforeDays.toString(),"","","","","","","","","");
}
updateExecuteTime(eventSourceTask);//成功发送微信消息后,更新定时任务列表的“最后执行时间”和“下次执行时间”。
}
}
/**
* 成功发送微信消息后,更新定时任务列表的“最后执行时间”和“下次执行时间”。
* @param eventSourceTask
*/
public void updateExecuteTime(MesEventSourceTask eventSourceTask){
Integer timerPeriod = eventSourceTask.getTimerPeriod();
Integer perQuant = eventSourceTask.getPerQuant();
int repeatInterval =0; //单位是秒
switch(timerPeriod){
case 1://年
repeatInterval = 365*86400*perQuant;
break;
case 2://月
repeatInterval = 30*86400*perQuant;
break;
case 3://周
repeatInterval = 7*86400*perQuant;
break;
case 4://天
repeatInterval = 86400*perQuant;
break;
case 5://小时
repeatInterval = 3600*perQuant;
break;
case 6://分钟
repeatInterval = 60*perQuant;
break;
default:
break;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = sdf.format(new Date().getTime() + repeatInterval * 1000L);
Date date = null;
try {
date= sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
eventSourceTask.setLastExecuteTime(new Date());//最后执行时间就是当前时间
eventSourceTask.setNextExecuteTime(date);//下次执行时间=最后执行时间+时间间隔(timerPeriod*perQuant)
eventSourceTaskService.updateExecuteTime(eventSourceTask);
}
}
2.QuartzUtils 定时任务工具类
package com.whitelake.modules.sys.util;
import com.whitelake.modules.sys.task.QuartzActiveJob;
import org.quartz.*;
import org.quartz.Trigger.TriggerState;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
/**
* SimpleTrigger:在某个时刻开始到某个时刻结束,在其间以某个时间间隔重复执行;<br>
* SimpleTrigger属性包括:开始时间,结束时间,重复次数,重复间隔时间。
*/
public class QuartzUtils {
private static Logger log = LoggerFactory.getLogger(QuartzUtils.class);
private static String JOB_GROUP_NAME = "group1"; //任务组名称
private static String TRIGGER_GROUP_NAME = "trigger1"; //触发器组名称
private static StdSchedulerFactory sf = new StdSchedulerFactory();// 通过SchedulerFactory获取一个调度器实例
private static Scheduler scheduler = null;
private static TriggerKey triggerKey = null;
/**
* 添加一个任务
* 在startTime时执行调试,endTime结束执行调度,重复执行repeatCount次,每隔repeatInterval秒执行一次
* @param jobName 任务名
* @param startTime 调度开始时间
* @param endTime 调度结束时间
* @param repeatCount 重复执行次数 :设为REPEAT_INDEFINITELY无限次重复
* @param repeatInterval 执行时间间隔秒数
* @param eventSourceId 事件源ID
* @return date 执行完时间
*/
public static void addJob(String jobName,Date startTime,Date endTime,int repeatInterval) throws SchedulerException {
// 代表一个Quartz的独立运行容器
scheduler = sf.getScheduler();
// 创建一个JobDetail实例,此版本JobDetail已经作为接口(interface)存在,通过JobBuilder创建
// 并指定Job在Scheduler中所属组及名称
JobDetail jobDetail = JobBuilder.newJob(QuartzActiveJob.class).withIdentity(jobName,JOB_GROUP_NAME).build();// 任务名,任务组名,任务执行类
// 设置定时任务执行规则为在指定的开始时间startTime进行执行,在endTime停止执行,其间 每隔repeatInterval秒执行一次,重复执行repeatCount次。
// 当指定为SimpleScheduleBuilder时,会发现不用对结果进行强制转换为SimpleTrigger了。
SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, TRIGGER_GROUP_NAME)//定义触发器名,触发器组名
.startAt(startTime).endAt(endTime) //定义开始和结束时间
.withSchedule( //定义任务调度的时间间隔和次数
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(repeatInterval)//定义时间间隔秒数
.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY)//定义重复执行次数是无限次
).build();
// 添加JobDetail到Scheduler容器中,并且和Trigger进行关联,返回执行时间
Date date = scheduler.scheduleJob(jobDetail,simpleTrigger);
log.info(jobDetail.getKey() + " will run at: " + date + " and repeat: " + simpleTrigger.getRepeatCount()
+ " times, every " + simpleTrigger.getRepeatInterval() / 1000L + " seconds");
// 在scheduler.start之后调用,可以重新定义trigger,重新注册
scheduler.start();
log.info("------- Started Scheduler -----------------");
// scheduler.shutdown(true);
// SchedulerMetaData metaData = scheduler.getMetaData();
// System.out.println("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");
}
/**
* 移除一个任务
* @param jobName
* @return 执行结果提示语
*/
public static void removeJob(String jobName){
try {
triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
scheduler.pauseTrigger(triggerKey);//停止触发器
scheduler.unscheduleJob(triggerKey);//移除触发器
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
scheduler.deleteJob(jobKey);//删除任务
log.info("删除任务=> [任务名:" + jobName + " 任务组:" + JOB_GROUP_NAME + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("删除任务=> [任务名:" + jobName + " 任务组:" + JOB_GROUP_NAME + "]=> [失败]");
}
}
/**
* 判断某个任务是否正在运行
* @param jobName
* @return true为正在运行
*/
public static boolean jobIsRun(String jobName){
if(scheduler != null){
triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
TriggerState triggerState;
try {
triggerState = scheduler.getTriggerState(triggerKey);
//[NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED]
//[-1 不存在, 0 正常, 1 暂停, 2 完成, 3 错误, 4 阻塞]
if("NORMAL".equals(triggerState.name())){
return true;
}
} catch (SchedulerException e) {
e.printStackTrace();
}
}
return false;
}
}
3、定时任务调用业务类
/**
* 事件源定时任务-保存
* @param mesEventSourceTask
* @param model
* @param redirectAttributes
* @return
* @throws SchedulerException
*/
@RequiresPermissions("mes:mesEventSource:edit")
@RequestMapping(value = "taskSave")
public String taskSave(MesEventSourceTask mesEventSourceTask, Model model, RedirectAttributes redirectAttributes) throws SchedulerException {
Map<String,String> map = isTimer(mesEventSourceTask.getEventSource().getId());
String isTimer = map.get("isTimer");
if("0".equals(isTimer)){
addMessage(redirectAttributes, "非定时事件不能被保存,请重试");
}else{
if (!beanValidator(model, mesEventSourceTask)){
return taskForm(mesEventSourceTask, model);
}
mesEventSourceTask.setCorpId(UserUtils.getUser().getCorpId());
mesEventSourceTaskService.save(mesEventSourceTask);
addMessage(redirectAttributes, "保存定时任务成功");
String jobName = mesEventSourceTask.getId();//存在任务名称相同的情况,因此用任务ID来唯一标识。
//如果该定时任务正在运行中
if(QuartzUtils.jobIsRun(jobName)){
QuartzUtils.removeJob(jobName); //先删除该任务
addMessage(redirectAttributes, "该定时任务已关闭");
}
//状态为“启用”,才新增定时任务
if(mesEventSourceTask.getIsEnable()==1){
//某个定时任务jobName,在startTime时执行调试,endTime结束执行调度,每隔repeatInterval秒执行一次
Integer timerPeriod = mesEventSourceTask.getTimerPeriod();
Integer perQuant = mesEventSourceTask.getPerQuant();
int repeatInterval =0; //单位是秒
switch(timerPeriod){
case 1://年
repeatInterval = 365*86400*perQuant;
break;
case 2://月
repeatInterval = 30*86400*perQuant;
break;
case 3://周
repeatInterval = 7*86400*perQuant;
break;
case 4://天
repeatInterval = 86400*perQuant;
break;
case 5://小时
repeatInterval = 3600*perQuant;
break;
case 6://分钟
repeatInterval = 60*perQuant;
break;
default:
break;
}
QuartzUtils.addJob(jobName,mesEventSourceTask.getStartTime(),mesEventSourceTask.getEndTime(),repeatInterval);
addMessage(redirectAttributes, "该定时任务已启用");
}
}
return "redirect:"+Global.getAdminPath()+"/mes/wechat/mesEventSource/taskList";
}