第二篇我们主要介绍了Quartz引入Spring框架的基本配置,这一篇直接开始对定时任务进行动态操控
一、 创建相关实体类
(1)定时任务参数
(2)存储TriggerName 的类,主要用来防重
(3)定时任务参数类的请求与返回
(4)调用任务实体类
package com.test.pojo.job;
import java.lang.reflect.Method;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* 功能说明:任务实体类<br>
* 注意事项:<br>
* 系统版本:version 1.0<br>
* 开发人员:renzw26782<br>
* 开发时间:2020年8月3日<br>
*/
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {
private static final Logger logger = LoggerFactory.getLogger(QuartzJob.class);
private UseJobDto useJobDto;
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
// 调用余额对账定时服务
this.execute(useJobDto.getFunctionId());
}
public UseJobDto getUseJobDto() {
return useJobDto;
}
public void setUseJobDto(UseJobDto useJobDto) {
this.useJobDto = useJobDto;
}
private void execute(String url) {
try {
if (logger.isDebugEnabled()) {
logger.debug("调用服务[" + url + "]调用开始!");
}
String[] arr = url.split("#");
String useJobMethod = arr[1].trim();
// 通过反射调用服务
String useJob = arr[0].trim();
String useJobName = useJob.substring(0, 1).toUpperCase() + useJob.substring(1);
@SuppressWarnings("rawtypes")
Class c = Class.forName("com.test.job." + useJobName);
Object obj = c.newInstance();
Method jobMethod = obj.getClass().getMethod(useJobMethod);
jobMethod.invoke(obj);
System.out.println("执行成功");
} catch (Exception e) {
logger.debug("调用服务[" + url + "]失败", e);
System.out.println("执行失败");
} finally {
if (logger.isDebugEnabled()) {
logger.debug("调用服务[" + url + "]调用结束!");
}
}
}
}
二、 各处理层逻辑处理
直接上代码吧
(1)controller控制层
package com.test.controller.job;
import java.util.List;
import org.apache.maven.surefire.shade.org.apache.maven.shared.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.test.enums.UseJobExecutePathEnum;
import com.test.enums.UseJobStatusEnum;
import com.test.pojo.job.BaseResp;
import com.test.pojo.job.UseJob;
import com.test.pojo.job.UseJobReq;
import com.test.pojo.job.UseJobResp;
import com.test.service.common.CommonService;
import com.test.service.job.UseJobService;
@Controller
@RequestMapping(value = "/useJop")
public class UseJobController {
@ModelAttribute
protected void initData(Model model) {
// 1、定时任务状态
model.addAttribute("useJobStatusMap", UseJobStatusEnum.toMap());
model.addAttribute("useJobExecutePathMap", UseJobExecutePathEnum.toMap());
model.addAttribute("aaa", "111");
}
@RequestMapping(value = "/toJobPage")
public String totoJobPage() {
return "WEB-INF/job/jobPage";
}
@RequestMapping(value = "/addJobPage")
public String toAddJobPage(UseJob useJob, Model model) {
if (useJob != null && StringUtils.isNotBlank(useJob.getJobId())) {
UseJobReq req = new UseJobReq(useJob);
UseJobResp resp = useJobService.getUseJodInfoById(req);
model.addAttribute("job", resp.getItem());
}
return "WEB-INF/job/addJobPage";
}
@Autowired
private UseJobService useJobService;
@Autowired
CommonService commonService;
@RequestMapping(value = "/queryJobList.do")
@ResponseBody
public List<UseJob> queryUseJobList(String jobName, String jobState) {
UseJob job = new UseJob();
if (StringUtils.isBlank(jobState)
|| StringUtils.equals(jobState.trim(), UseJobStatusEnum.PLEASE_SELECT.getCode())) {
job.setJobState("");
} else {
job.setJobState(jobState.trim());
}
if (StringUtils.isBlank(jobName)) {
job.setJobName("");
} else {
job.setJobName(jobName.trim());
}
UseJobReq useJobReq = new UseJobReq(job);
UseJobResp useJobResp = null;
useJobResp = useJobService.queryUseJobList(useJobReq);
return useJobResp.getItems();
}
@RequestMapping("/addUseJob.do")
@ResponseBody
public void addUseJob(UseJob useJob) {
UseJobReq req = new UseJobReq(useJob);
BaseResp baseResp = null;
if (StringUtils.isBlank(useJob.getJobId())) {
Long nowDate = commonService.getNowDate();
Long nowTime = commonService.getNowTime();
useJob.setJobId(nowDate.toString() + nowTime.toString());
baseResp = useJobService.addUseJob(req);
} else {
baseResp = useJobService.updateUseJob(req);
}
}
/**
* 启动定时任务
*
* @param info
* @return
*/
@RequestMapping("/startJob.do")
@ResponseBody
public String startUseJob(String jobId, String functionId) {
UseJob object = new UseJob();
object.setFunctionId(functionId);
object.setJobId(jobId);
UseJobReq req = new UseJobReq(object);
BaseResp resp = useJobService.startUseJob(req);
String message = "启动任务成功";
if (resp.getErrorNo() != 0) {
message = "启动任务失败" + resp.getErrorInfo();
}
return message;
}
/**
* 启动定时任务
*
* @param info
* @return
*/
@RequestMapping("/stopJob.do")
@ResponseBody
public String stopUseJob(String jobId, String functionId) {
UseJob object = new UseJob();
object.setFunctionId(functionId);
object.setJobId(jobId);
UseJobReq req = new UseJobReq(object);
BaseResp resp = useJobService.stopUseJob(req);
String message = "启动任务成功";
if (resp.getErrorNo() != 0) {
message = "启动任务失败" + resp.getErrorInfo();
}
return message;
}
/**
* 删除定时任务
*
* @param info
* @return
*/
@RequestMapping("/delJob.do")
@ResponseBody
public String delUseJob(String jobId, String functionId) {
UseJob object = new UseJob();
object.setFunctionId(functionId);
object.setJobId(jobId);
UseJobReq req = new UseJobReq(object);
BaseResp resp = useJobService.delUseJob(req);
String message = "删除任务成功";
if (resp.getErrorNo() != 0) {
message = "删除任务失败" + resp.getErrorInfo();
}
return message;
}
}
(2) service服务层
package com.test.service.job;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.test.logic.job.UseJobLogic;
import com.test.pojo.job.BaseResp;
import com.test.pojo.job.UseJob;
import com.test.pojo.job.UseJobDto;
import com.test.pojo.job.UseJobReq;
import com.test.pojo.job.UseJobResp;
import com.test.utils.BeanUtils;
import com.test.utils.StringUtils;
@Service("jobFactory")
public class UseJobServiceImpl implements UseJobService {
private Logger logger = Logger.getLogger(UseJobServiceImpl.class);
@Autowired
private UseJobLogic useJobLogic;
@Override
public UseJobResp queryUseJobList(UseJobReq req) {
UseJobResp resp = new UseJobResp();
List<UseJob> ls = null;
try {
ls = useJobLogic.queryJobs(req.getObject());
} catch (Exception e) {
resp.setErrorId("999999");
resp.setErrorInfo("查询定时任务失败,请联系相关技术人员!");
}
resp.setItems(ls);
return resp;
}
@Override
public BaseResp addUseJob(UseJobReq req) {
BaseResp resp = new BaseResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-参数校验
resp = validateJobDto(job);
if (resp.getErrorNo() > 0) {
return resp;
}
// 2-校验任务是否存在
if (useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("待新增的任务已存在");
return resp;
}
// 2-添加任务
useJobLogic.addJob(job);
// 记录操作日志
try {
} catch (Exception e) {
}
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("新增定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
/**
* 描述:校验入参<br>
* 参数:@param job 参数:@return<br>
* 返回值:BaseResp<br>
*
* @throws Exception
*/
private BaseResp validateJobDto(UseJobDto job) throws Exception {
BaseResp resp = new BaseResp();
if (job == null) {
resp.setErrorNo(999999);
resp.setErrorInfo("任务对象不能为空");
return resp;
}
if (StringUtils.isBlank(job.getJobId())) {
resp.setErrorNo(999999);
resp.setErrorInfo("批次信息不能为空");
return resp;
}
if (StringUtils.isBlank(job.getFunctionId())) {
resp.setErrorNo(999999);
resp.setErrorInfo("服务路径不能为空");
return resp;
}
if (StringUtils.isBlank(job.getJobName())) {
resp.setErrorNo(999999);
resp.setErrorInfo("任务名称不能为空");
return resp;
}
if (StringUtils.isBlank(job.getExpression())) {
resp.setErrorNo(999999);
resp.setErrorInfo("时间间隔表达式不能为空");
return resp;
}
return resp;
}
@Override
public BaseResp startUseJob(UseJobReq req) {
BaseResp resp = new BaseResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-校验任务是否存在
if (!useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("该任务不存在");
return resp;
}
if (!useJobLogic.isPausedJob(job)) {
return resp;
}
useJobLogic.startUseJob(job);
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("启动定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
@Override
public BaseResp stopUseJob(UseJobReq req) {
BaseResp resp = new BaseResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-校验任务是否存在
if (!useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("该任务不存在");
return resp;
}
if (useJobLogic.isPausedJob(job)) {
return resp;
}
useJobLogic.stopUseJob(job);
// 记录操作日志
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("暂停定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
@Override
public BaseResp delUseJob(UseJobReq req) {
BaseResp resp = new BaseResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-校验任务是否存在
if (!useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("所删除的任务不存在");
return resp;
}
// 2-校验当前任务状态是否是暂停状态
if (!useJobLogic.isPausedJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("所删除的任务必须处于暂停状态");
return resp;
}
// 3-删除任务
useJobLogic.deleteJob(job);
// 记录操作日志
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("删除定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
@Override
public UseJobResp getUseJodInfoById(UseJobReq req) {
UseJobResp resp = new UseJobResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-校验任务是否存在
if (!useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("所查看的任务不存在");
return resp;
}
// 2-添加任务
UseJob item = useJobLogic.getUseJodInfo(job);
resp.setItem(item);
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("查看定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
@Override
public BaseResp updateUseJob(UseJobReq req) {
BaseResp resp = new BaseResp();
UseJobDto job = new UseJobDto();
try {
UseJob object = req.getObject();
BeanUtils.copyProperties(job, object);
// 1-参数校验
resp = validateJobDto(job);
if (resp.getErrorNo() > 0) {
return resp;
}
// 2-校验任务是否存在
if (!useJobLogic.isExistJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("所修改的任务不存在");
return resp;
}
// 3-校验当前任务状态是否是暂停状态
if (!useJobLogic.isPausedJob(job)) {
resp.setErrorNo(999999);
resp.setErrorInfo("所修改的任务必须处于暂停状态");
return resp;
}
// 4-修改任务
useJobLogic.updateJob(job);
// 记录操作日志
} catch (Exception e) {
resp.setErrorNo(999999);
resp.setErrorInfo("新增定时任务失败,请联系相关技术人员!");
logger.error(resp.getErrorInfo(), e);
}
return resp;
}
}
(3)logic逻辑层
package com.test.logic.job;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.utils.Key;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import com.chinabond.core.exception.BusinessException;
import com.test.pojo.job.QuartzJob;
import com.test.pojo.job.UseJob;
import com.test.pojo.job.UseJobDto;
import com.test.utils.StringUtils;
@Component
public class UseJobLogic {
private static final String GROUP_NAME_DEFAULT = Key.DEFAULT_GROUP;
@Autowired(required = false)
private SchedulerFactoryBean schedulerFactory;
/**
* 获取线程调度器
*
* @return
*/
private Scheduler getScheduler() {
Scheduler scheduler = schedulerFactory.getScheduler();
if (scheduler == null) {
throw new BusinessException("999999", "定时任务调度器为空,请确认是否开启定时任务功能!");
}
return scheduler;
}
public List<UseJob> queryJobs(UseJob useJob) throws SchedulerException {
List<UseJob> ls = new ArrayList<UseJob>();
Set<TriggerKey> triggerKeys = getScheduler()
.getTriggerKeys(GroupMatcher.triggerGroupEquals(GROUP_NAME_DEFAULT));
for (TriggerKey triggerKey : triggerKeys) {
Trigger trigger = getScheduler().getTrigger(triggerKey);
TriggerState triggerState = getScheduler().getTriggerState(triggerKey);
UseJobDto useJobDto = (UseJobDto) getScheduler().getJobDetail(trigger.getJobKey()).getJobDataMap()
.get("useJobDto");
if (useJobDto == null) {
// 只处理新增的
continue;
}
useJobDto.setJobState(triggerState.toString());
useJobDto.setNextFireTime(trigger.getNextFireTime());
ls.add(useJobDto);
}
// 条件查询
CollectionUtils.filter(ls, new Predicate() {
@Override
public boolean evaluate(Object object) {
if (object == null || !(object instanceof UseJob)) {
return false;
}
UseJob temp = (UseJob) object;
if (StringUtils.isNotBlank(useJob.getJobName()) && !temp.getJobName().contains(useJob.getJobName())) {
return false;
}
if (StringUtils.isNotBlank(useJob.getJobState())
&& !StringUtils.equals(useJob.getJobState(), temp.getJobState())) {
return false;
}
return true;
}
});
return ls;
}
/**
* 判断任务是否存在
*
* @param job
* @return
* @throws SchedulerException
*/
public boolean isExistJob(UseJobDto job) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(job.getTriggerKey(), GROUP_NAME_DEFAULT);
CronTrigger trigger = (CronTrigger) getScheduler().getTrigger(triggerKey);
return trigger != null;
}
/**
* <pre>
* addJob(这里用一句话描述这个方法的作用)
* 创建人:任智伟
* 创建时间:2020年9月18日 上午9:51:36
* 修改人:任智伟
* 修改时间:2020年9月18日 上午9:51:36
* 修改备注:
* @param job
* @throws SchedulerException
* </pre>
*/
public void addJob(UseJobDto job) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(job.getTriggerKey(), GROUP_NAME_DEFAULT);
CronTrigger trigger = (CronTrigger) getScheduler().getTrigger(triggerKey);
if (trigger == null) {
/** Trigger不存在,则新建 */
JobDataMap jobDataMap = new JobDataMap();
job.setJobState(TriggerState.NORMAL.toString());
jobDataMap.put("useJobDto", job);
// 新建任务
JobKey jobKey = new JobKey(job.getJobDetailKey(), GROUP_NAME_DEFAULT);
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).setJobData(jobDataMap).withIdentity(jobKey)
.requestRecovery(true).storeDurably(true).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getExpression());
// 构建触发器
trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 装配任务
System.out.println("暂停ing-------------");
getScheduler().scheduleJob(jobDetail, trigger);
getScheduler().pauseTrigger(triggerKey);
}
}
/**
* <pre>
* isPausedJob(判断任务状态是否已执行)
* 创建人:任智伟
* 创建时间:2020年9月24日 上午10:31:01
* 修改人:任智伟
* 修改时间:2020年9月24日 上午10:31:01
* 修改备注:
* @param job 定时任务
* @return 暂停 :true ,其他 :false
* </pre>
*
* @throws SchedulerException
*/
public boolean isPausedJob(UseJobDto job) throws SchedulerException {
TriggerState triggerState = getScheduler().getTriggerState(TriggerKey.triggerKey(job.getTriggerKey()));
return triggerState.toString().equals(TriggerState.PAUSED.toString());
}
/**
* <pre>
* startUseJob(启动定时任务)
* 创建人:任智伟
* 创建时间:2020年9月24日 上午10:36:42
* 修改人:任智伟
* 修改时间:2020年9月24日 上午10:36:42
* 修改备注:
* @param job 定时任务
* </pre>
*
* @throws SchedulerException
*/
public void startUseJob(UseJobDto job) throws SchedulerException {
getScheduler().resumeTrigger(TriggerKey.triggerKey(job.getTriggerKey()));
getScheduler().resumeJob(JobKey.jobKey(job.getJobDetailKey()));
}
/**
* <pre>
* stopUseJob(停止定时任务)
* 创建人:任智伟
* 创建时间:2020年9月24日 上午11:10:47
* 修改人:任智伟
* 修改时间:2020年9月24日 上午11:10:47
* 修改备注:
* @param job
* </pre>
*
* @throws SchedulerException
*/
public void stopUseJob(UseJobDto job) throws SchedulerException {
getScheduler().pauseJob(JobKey.jobKey(job.getJobDetailKey()));
getScheduler().pauseTrigger(TriggerKey.triggerKey(job.getTriggerKey()));
}
/**
* <pre>
* deleteJob(删除定时任务)
* 创建人:任智伟
* 创建时间:2020年9月24日 下午4:54:57
* 修改人:任智伟
* 修改时间:2020年9月24日 下午4:54:57
* 修改备注:
* @param job
* @throws SchedulerException
* </pre>
*/
public void deleteJob(UseJobDto job) throws SchedulerException {
if (getScheduler().checkExists(JobKey.jobKey(job.getJobDetailKey()))) {
getScheduler().deleteJob(JobKey.jobKey(job.getJobDetailKey()));
}
}
/**
* <pre>
* getUseJodInfo(修改回显查询数据)
* 创建人:任智伟
* 创建时间:2020年9月29日 下午2:49:09
* 修改人:任智伟
* 修改时间:2020年9月29日 下午2:49:09
* 修改备注:
* @param job
* @return
* </pre>
*
* @throws SchedulerException
*/
public UseJob getUseJodInfo(UseJobDto job) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(job.getTriggerKey());
Trigger trigger = getScheduler().getTrigger(triggerKey);
TriggerState triggerState = getScheduler().getTriggerState(triggerKey);
UseJobDto jobDto = (UseJobDto) getScheduler().getJobDetail(JobKey.jobKey(job.getJobDetailKey())).getJobDataMap()
.get("useJobDto");
jobDto.setJobState(triggerState.toString());
jobDto.setNextFireTime(trigger.getNextFireTime());
return jobDto;
}
/**
* <pre>
* updateJob(修改定时任务)
* 创建人:任智伟
* 创建时间:2020年10月12日 上午9:44:29
* 修改人:任智伟
* 修改时间:2020年10月12日 上午9:44:29
* 修改备注:
* @param job
* </pre>
*
* @throws SchedulerException
*/
public void updateJob(UseJobDto job) throws SchedulerException {
deleteJob(job);
addJob(job);
}
}
三、完成后效果
关联时间表达式的js代码逻辑较为复杂,这里就不展示了,有需要的小伙伴可以私我