概述
詳細
一、准備工作
1.java環境搭建,具體參考包中的webapp/resources/doc/平台開發環境安裝Guide_V1.0.docx文檔

2.使用源碼中的webapp/resources/doc/init.sql初始化表結構及數據
t_timetask 任務表
t_timetask_log 任務運行日志
3.數據庫連接配置在cloud_parent中的pom.xml中,數據庫名稱ffxl_cloud,默認賬號root,密碼123456,同樣可在pom.xml中修改
4.運行quartz項目,此處注意,使用的端口號需要與platform_parent下pom.xml中的quartz.job.url的一致,程序中用的是8080端口,具體使用哪個配置,請參考maven中profiles的使用
5.運行admin項目,注意,此處端口要與quartz不同,程序中用的是80端口,瀏覽器中輸入http://localhost/admin 運行結果如圖:

二、代碼引入
1、文件引入順序:lib_parent → platform_parent → cloud_parent
2、代碼結構

三、程序實現
quartz項目部分代碼
1.quartz項目啟動時,初始化數據庫中的定時任務
package com.ffxl.quartz.init;
import java.util.ArrayList;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.STimetaskExample;
import com.ffxl.cloud.model.base.BaseSTimetaskExample.Criteria;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.cloud.service.STimetaskService;
import com.ffxl.quartz.task.util.QuartzJobFactory;
import com.ffxl.quartz.task.util.QuartzJobFactoryDisallowConcurrentExecution;
/**
* 根據上下文獲取spring類
*
* @author
*/
public class InitQuartzJob implements ApplicationContextAware{
private static final Logger logger = LoggerFactory.getLogger(InitQuartzJob.class);
private static ApplicationContext appCtx;
public static SchedulerFactoryBean schedulerFactoryBean = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (this.appCtx == null) {
this.appCtx = applicationContext;
}
}
public static void init() {
schedulerFactoryBean = (SchedulerFactoryBean) appCtx.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
try {
logger.info(scheduler.getSchedulerName());
} catch (SchedulerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 這里從數據庫中獲取任務信息數據
STimetaskService sTimetaskService = (STimetaskService) appCtx.getBean(STimetaskService.class);
STimetaskExample example = new STimetaskExample();
Criteria c = example.createCriteria();
c.andJobStatusEqualTo("1"); // 已發布的定時任務
List<STimetask> list = sTimetaskService.selectByExample(example);
List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
for (STimetask sTimetask : list) {
ScheduleJob job1 = new ScheduleJob();
job1.setJobId(sTimetask.getId());
job1.setJobGroup(sTimetask.getGroupName()); // 任務組
job1.setJobName(sTimetask.getName());// 任務名稱
job1.setJobStatus(sTimetask.getJobStatus()); // 任務發布狀態
job1.setIsConcurrent(sTimetask.getConcurrent() ? "1" : "0"); // 運行狀態
job1.setCronExpression(sTimetask.getCron());
job1.setBeanClass(sTimetask.getBeanName());// 一個以所給名字注冊的bean的實例
job1.setMethodName(sTimetask.getMethodName());
job1.setJobData(sTimetask.getJobData()); // 參數
jobList.add(job1);
}
for (ScheduleJob job : jobList) {
try {
addJob(job);
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 添加任務
*
* @param scheduleJob
* @throws SchedulerException
*/
public static void addJob(ScheduleJob job) throws SchedulerException {
if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
return;
}
Scheduler scheduler = schedulerFactoryBean.getScheduler();
logger.debug(scheduler + "...........................................add");
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 不存在,創建一個
if (null == trigger) {
Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
: QuartzJobFactoryDisallowConcurrentExecution.class;
JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).usingJobData("data", job.getJobData()).build();
jobDetail.getJobDataMap().put("scheduleJob", job);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId().toString()).withIdentity(job.getJobName(), job.getJobGroup())
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} else {
// Trigger已存在,那么更新相應的定時設置
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表達式重新構建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).usingJobData("data", job.getJobData()).withSchedule(scheduleBuilder).build();
// 按新的trigger重新設置job執行
scheduler.rescheduleJob(triggerKey, trigger);
}
}
}
2.提供job對應的操作服務
package com.ffxl.quartz.task;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.ffxl.cloud.annotation.ControllerLogAnnotation;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.platform.util.JsonResult;
import com.ffxl.platform.util.StringUtil;
import com.ffxl.quartz.init.InitQuartzJob;
@Component
@RequestMapping(value = "/opt")
public class JobSerlvet {
public final Logger log = Logger.getLogger(this.getClass());
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
/**
* 獲取所有計划中的任務列表
*
* @return
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/getAllJob")
@ResponseBody
@ControllerLogAnnotation(description = "獲取所有計划中的任務列表")
public void getAllJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
ScheduleJob job = new ScheduleJob();
job.setJobId(trigger.getDescription());//description 放的是job的id
job.setJobName(jobKey.getName());
job.setJobGroup(jobKey.getGroup());
job.setDescription("觸發器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}
jobList.add(job);
}
}
//輸出
if(jobList.size() >0){
JSONArray listArray=JSONArray.fromObject(jobList);
Map<String,Object> m =new HashMap<String, Object>();
m.put("job", listArray);
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\",\"data\":"+m+"}");
out.close();
}else{
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"沒有計划任務\"}");
out.close();
}
}
/**
* 所有正在運行的job
*
* @return
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/getRunningJob")
@ResponseBody
public void getRunningJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size());
for (JobExecutionContext executingJob : executingJobs) {
ScheduleJob job = new ScheduleJob();
JobDetail jobDetail = executingJob.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = executingJob.getTrigger();
job.setJobName(jobKey.getName());
job.setJobGroup(jobKey.getGroup());
job.setDescription("觸發器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}
jobList.add(job);
}
//輸出
if(jobList.size() >0){
JSONArray listArray=JSONArray.fromObject(jobList);
Map<String,Object> m =new HashMap<String, Object>();
m.put("job", listArray);
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\",\"data\":"+m+"}");
out.close();
}else{
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"沒有正在執行的任務\"}");
out.close();
}
}
/**
* 添加任務
*
* @param
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/addJob")
@ResponseBody
public void addJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
StringBuffer info=new StringBuffer();
ServletInputStream in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
ScheduleJob job = new ScheduleJob();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
job.setJobId(sTimetask.getId());
job.setJobGroup(sTimetask.getGroupName()); //任務組
job.setJobName(sTimetask.getName());// 任務名稱
job.setJobStatus(sTimetask.getJobStatus()); // 任務發布狀態
job.setIsConcurrent(sTimetask.getConcurrent()?"1":"0"); // 運行狀態
job.setCronExpression(sTimetask.getCron());
job.setBeanClass(sTimetask.getBeanName());// 一個以所給名字注冊的bean的實例
job.setMethodName(sTimetask.getMethodName());
job.setJobData(sTimetask.getJobData()); //參數
}
}
InitQuartzJob.addJob(job);
//輸入
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}
/**
* 暫停一個job
*
* @param scheduleJob
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/pauseJob")
@ResponseBody
public void pauseJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
StringBuffer info=new StringBuffer();
ServletInputStream in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
scheduler.pauseJob(jobKey);
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}else{
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"任務不存在\"}");
out.close();
}
}
}
/**
* 恢復一個job
*
* @param scheduleJob
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/resumeJob")
@ResponseBody
public void resumeJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
StringBuffer info=new StringBuffer();
ServletInputStream in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
scheduler.resumeJob(jobKey);
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}else{
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"任務不存在\"}");
out.close();
}
}
}
/**
* 刪除一個job
*
* @param scheduleJob
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/deleteJob")
@ResponseBody
public void deleteJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
StringBuffer info=new StringBuffer();
ServletInputStream in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
scheduler.deleteJob(jobKey);
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}else{
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"任務不存在\"}");
out.close();
}
}
}
/**
* 立即執行job
*
* @param scheduleJob
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/runAJobNow")
@ResponseBody
public void runAJobNow(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, IOException {
StringBuffer info=new StringBuffer();
ServletInputStream in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
scheduler.triggerJob(jobKey);
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}else{
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"任務不存在\"}");
out.close();
}
}
}
/**
* 更新job時間表達式
*
* @param scheduleJob
* @throws SchedulerException
* @throws IOException
*/
@RequestMapping(value="/updateJobCron")
@ResponseBody
public void updateJobCron(HttpServletRequest request,HttpServletResponse response) throws SchedulerException{
try {
StringBuffer info=new StringBuffer();
ServletInputStream in;
in = request.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
byte[] buffer=new byte[1024];
int iRead;
while((iRead=buf.read(buffer))!=-1){
info.append(new String(buffer,0,iRead,"UTF-8"));
}
// 釋放資源
buf.close();
in.close();
if(info!=null&&!StringUtil.isEmpty(info.toString())){
JSONObject json = JSONObject.parseObject(info.toString());
STimetask sTimetask = JSONObject.toJavaObject(json, STimetask.class);
if(sTimetask !=null){
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
TriggerKey triggerKey = TriggerKey.triggerKey(sTimetask.getName(), sTimetask.getGroupName());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(sTimetask.getCron());
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"2000\",\"message\":\"成功\"}");
out.close();
}else{
//輸出
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\":\"5000\",\"message\":\"任務不存在\"}");
out.close();
}
}
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.編寫 定時清除timeTaskLog 7天之前的記錄
@Component
public class TimeTaskLogDispatchController {
private static final Logger LOGGER = Logger.getLogger(TimeTaskLogDispatchController.class);
/**
* 定時清除timeTaskLog 7天之前的記錄
*/
public void deleteTimeTaskLog(String data) {
LOGGER.info("【定時清除timeTaskLog 7天之前的記錄】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>開始執行");
STimetaskLogService bActiveService = (STimetaskLogService) ApplicationContextUtils.getBean(STimetaskLogService.class);
Date currentDate = new Date();
int day = -7;
Date deleteDate = DateUtil.getAfterNumDay(currentDate, day);
int ret = bActiveService.deleteLog(deleteDate);
if(ret >0){
LOGGER.info("【定時清除timeTaskLog 7天之前的記錄】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>執行成功");
}else{
LOGGER.info("【定時清除timeTaskLog 7天之前的記錄】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>執行失敗");
}
}
}
4.dispatcher-servlet.xml中添加如下配置
<!-- 初始化springUtils -->
<bean id="springUtils" class="com.ffxl.quartz.task.util.SpringUtils" />
<!-- 初始化Scheduler -->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
<!-- 初始化job -->
<bean id="initQuartzJob" class="com.ffxl.quartz.init.InitQuartzJob" init-method="init" lazy-init="false" />
admin項目部分代碼
1.可視化項目的controller層
package com.ffxl.admin.controller.task;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.ffxl.admin.controller.BaseController;
import com.ffxl.admin.util.DataTablesUtil;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.cloud.service.STimetaskService;
import com.ffxl.platform.constant.Const;
import com.ffxl.platform.core.Page;
import com.ffxl.platform.exception.BusinessException;
import com.ffxl.platform.util.CronUtil;
import com.ffxl.platform.util.DateUtil;
import com.ffxl.platform.util.HttpConnectUtil;
import com.ffxl.platform.util.JsonDateValueProcessor;
import com.ffxl.platform.util.JsonResult;
import com.ffxl.platform.util.Message;
import com.ffxl.platform.util.StringUtil;
/**
* 定時任務
* @author wison
*
*/
@Controller
@RequestMapping(value = "/task")
public class TimeTaskController extends BaseController {
private static String JOB_URL = Const.QUARTZ_JOB_URL;
private static String ALL_JOB = JOB_URL+"/opt/getAllJob"; //所有計划中的任務列表
private static String RUNNING_JOB = JOB_URL+"/opt/getRunningJob";//所有正在運行的job
private static String ADD_JOB = JOB_URL+"/opt/addJob";//添加任務
private static String PAUSE_JOB =JOB_URL+ "/opt/pauseJob";//暫停一個job
private static String RESUME_JOB = JOB_URL+"/opt/resumeJob";//恢復一個job
private static String DELETE_JOB = JOB_URL+"/opt/deleteJob";//刪除一個job
private static String RUNA_JOB =JOB_URL+ "/opt/runAJobNow";//立即執行job
private static String UPDATE_JOB = JOB_URL+"/opt/updateJobCron";//更新job時間表達式
private static final Logger logger = LoggerFactory.getLogger(TimeTaskController.class);
@Autowired
private STimetaskService stimetaskService;
@InitBinder
public void initBinder(WebDataBinder binder) {
DateFormat fmt = new SimpleDateFormat(DateUtil.STANDARD_DATE_FORMAT_STR);
CustomDateEditor dateEditor = new CustomDateEditor(fmt, true);
binder.registerCustomEditor(Date.class, dateEditor);
}
/**
* 列表頁面跳轉
* @return
*/
@RequestMapping(value="/list")
public ModelAndView userList(STimetask task){
ModelAndView mv = this.getModelAndView();
mv.setViewName("system/timeTaskList");
return mv;
}
/**
* 列表
* @return
*/
@RequestMapping(value="/task_list")
@ResponseBody
public JsonResult taskList(DataTablesUtil dataTables, STimetask task, Page page, HttpSession session){
List<STimetask> list = stimetaskService.selectByPage(task, page);
// 查詢task的運行狀態
String result = HttpConnectUtil.httpRequest(RUNNING_JOB, Const.REQUEST_METHOD_POST, null);
if(result!=null){
JSONObject jsonResult = JSONObject.fromObject(result);
Map<String, ScheduleJob> map = new HashMap<String, ScheduleJob>();
if( jsonResult.get("code").equals("2000")){
JSONObject js = (JSONObject) jsonResult.get("data");
JSONArray dataArray = (JSONArray) js.get("job");
if(dataArray.size() > 0){
List<ScheduleJob> jobList = JSONArray.toList(dataArray,ScheduleJob.class);
for(ScheduleJob job: jobList){
map.put(job.getJobId().toString(), job);
}
}
}
for(STimetask st: list){
if(map.containsKey(st.getId())){
st.setConcurrent(true);
}
}
}
// 查詢task的計划狀態
String planResult = HttpConnectUtil.httpRequest(ALL_JOB, Const.REQUEST_METHOD_POST, null);
if(planResult!=null){
JSONObject jsonPlanResult = JSONObject.fromObject(planResult);
Map<String, ScheduleJob> planMap = new HashMap<String, ScheduleJob>();
if(jsonPlanResult.get("code").equals("2000")){
JSONObject js = (JSONObject) jsonPlanResult.get("data");
JSONArray dataArray = (JSONArray) js.get("job");
if(dataArray.size() > 0){
List<ScheduleJob> jobList = JSONArray.toList(dataArray,ScheduleJob.class);
for(ScheduleJob job: jobList){
planMap.put(job.getJobId().toString(), job);
}
}
}
for(STimetask st: list){
if(planMap.containsKey(st.getId())){
String status = planMap.get(st.getId()).getJobStatus();
st.setPlanStatus(status);
}
}
}
//返回dataTable所需數據
dataTables = this.getDataTables(page, dataTables, list);
return new JsonResult("2000", dataTables);
}
/**
* 立即執行一次job
* 用於測試任務是否正確
* @param id
* @return
*/
@RequestMapping(value="/run_task2job")
@ResponseBody
public JsonResult run_task2job(String id){
//查詢task
STimetask stimetask = stimetaskService.selectByPrimaryKey(id);
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
JSONObject jsonArray = JSONObject.fromObject(stimetask,jsonConfig);
String result = HttpConnectUtil.httpRequest(RUNA_JOB, Const.REQUEST_METHOD_POST, jsonArray.toString());
logger.info(result);
if(result ==null){
return new JsonResult("5000", "定時項目未啟動",null);
}else{
return new JsonResult("2000", null);
}
}
/**
* 添加job到計划列表
* @param id
* @return
*/
@RequestMapping(value="/add_task2job")
@ResponseBody
public JsonResult add_task2job(String id){
//查詢task
STimetask stimetask = stimetaskService.selectByPrimaryKey(id);
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
JSONObject jsonArray = JSONObject.fromObject(stimetask,jsonConfig);
String result = HttpConnectUtil.httpRequest(ADD_JOB, Const.REQUEST_METHOD_POST, jsonArray.toString());
logger.info(result);
if(result ==null){
return new JsonResult("5000", "定時項目未啟動",null);
}else{
return new JsonResult("2000", null);
}
}
/**
* 從計划列表中暫停job
* @param id
* @return
*/
@RequestMapping(value="/stop_task2job")
@ResponseBody
public JsonResult stop_task2job(String id){
//查詢task
STimetask stimetask = stimetaskService.selectByPrimaryKey(id);
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
JSONObject jsonArray = JSONObject.fromObject(stimetask,jsonConfig);
String result = HttpConnectUtil.httpRequest(PAUSE_JOB, Const.REQUEST_METHOD_POST, jsonArray.toString());
logger.info(result);
if(result ==null){
return new JsonResult("5000", "定時項目未啟動",null);
}else{
return new JsonResult("2000", null);
}
}
/**
* 從計划列表中移除job
* @param id
* @return
*/
@RequestMapping(value="/remove_task2job")
@ResponseBody
public JsonResult remove_task2job(String id){
//查詢task
STimetask stimetask = stimetaskService.selectByPrimaryKey(id);
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
JSONObject jsonArray = JSONObject.fromObject(stimetask,jsonConfig);
String result = HttpConnectUtil.httpRequest(DELETE_JOB, Const.REQUEST_METHOD_POST, jsonArray.toString());
logger.info(result);
if(result ==null){
return new JsonResult("5000", "定時項目未啟動",null);
}else{
return new JsonResult("2000", null);
}
}
/**
* 變更job狀態
* @param id
* @return
*/
@RequestMapping(value="/update_task")
@ResponseBody
public JsonResult update_task(String ids,String type){
//查詢task
String[] idArray = ids.split(",");
Map<String,String> selectedIdMap = new HashMap<String,String>();
List<String> idList = new ArrayList<String>();
for (int i = 0; i < idArray.length; i++) {
idList.add(idArray[i]);
}
int ret = stimetaskService.updatebyOperate(idList,type);
if(ret >0){
return new JsonResult(true);
}else{
return new JsonResult(false);
}
}
/**
* 刪除job
* @param id
* @return
*/
@RequestMapping(value="/delete_task")
@ResponseBody
public JsonResult delete_task(String ids){
//查詢task
String[] idArray = ids.split(",");
Map<String,String> selectedIdMap = new HashMap<String,String>();
List<String> idList = new ArrayList<String>();
for (int i = 0; i < idArray.length; i++) {
idList.add(idArray[i]);
}
int ret = stimetaskService.deleteByIds(idList);
if(ret >0){
return new JsonResult(true);
}else{
return new JsonResult(false);
}
}
/**
* 詳情頁面
* @return
*/
@RequestMapping(value="/task_detail")
public ModelAndView detail(String id){
ModelAndView mv = this.getModelAndView();
STimetask model = new STimetask();
model = stimetaskService.selectByPrimaryKey(id);
mv.addObject("model", model);
mv.setViewName("system/timeTaskDetail");
return mv;
}
/**
* 解析cron
* @return
*/
@RequestMapping(value="/analysis_cron")
@ResponseBody
public JsonResult analysisCron(String cron){
try {
Date date = new Date();
String dateStr = DateUtil.formatStandardDatetime(date);
List<String> dateList = CronUtil.cronAlgBuNums(cron, dateStr, 5);
return new JsonResult("2000", dateList);
} catch (Exception e) {
e.printStackTrace();
return new JsonResult("5000", null);
}
}
/**
* 驗證名稱是否存在
* @param id
* @param groupName
* @param name
* @return
*
*/
@RequestMapping(value="/check_name")
@ResponseBody
public Boolean check_name(String id, String groupName, String name){
if(StringUtil.isEmpty(groupName,name)){
throw new BusinessException(Message.M4003);
}
STimetask task = new STimetask();
task.setId(id);
task.setGroupName(groupName);
task.setName(name);
STimetask queryTask = stimetaskService.checkName(task);
if(queryTask !=null){
logger.debug("組.任務名 exists,return false");
return false;
}else{
logger.debug("組.任務名 not exists,return true");
return true;
}
}
/**
* 保存
* @return
*/
@RequestMapping(value="/task_save")
@ResponseBody
public JsonResult userSave(STimetask task, HttpSession session){
//獲取系統操作人員
String longName = "admin";
task.setModifyUserId(longName);
try{
int ret= stimetaskService.insertOrUpdateByUser(task,longName);
if(ret > 0){
return new JsonResult("2000",task);
}else{
return new JsonResult("5000");
}
}catch(BusinessException e){
return new JsonResult("5001",e.getMessage(),null);
}
}
}
2.前端頁面

可以看到在這里我把定時任務的狀態分為兩大類,任務狀態跟業務有關,分為已發布和未發布;計划狀態跟定時任務的運行有關,分為None,正常運行,已暫停,任務執行中,線程阻塞,未計划,錯誤
2.1計划狀態
function formatPlan(value, rowData, rowIndex){
if(value=="None"){
return "<span class='text-danger'>None</span>"
}
if(value=="NORMAL"){
return "<span class='text-success'>正常運行</span>"
}
if(value=="PAUSED"){
return "<span class='text-yellow'>已暫停</span>"
}
if(value=="COMPLETE"){
return "<span class='text-success'>任務執行中</span>"
}
if(value=="BLOCKED"){
return "<span class='text-danger'>線程阻塞</span>"
}
if(value=="ERROR"){
return "<span class='text-danger'>錯誤</span>"
}else{
return "<span class='text-danger'>未計划</span>"
}
}
2.2操作邏輯
function formatOpt(value, rowData, rowIndex) {
var msg = "";
msg+="<a href='#' class='btnstyle' onclick='showDetail(\""
+ rowData.id + "\")'>編輯</a>";
//已發布,
if(rowData.jobStatus=='1'){
var value = rowData.planStatus;
if(value=="None"|| value==null){
msg +='<a href="#"class="btnstyle" onclick="addJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="定時任務按照計划開始執行" >計划</a>';
}
if(value=="NORMAL"){
msg += '<a href="#"class="btnstyle" onclick="runJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="緊執行一次" >立即執行</a>'
+ '<a href="#"class="btnstyle" onclick="stopJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="定時任務暫時停止執行" >暫停</a>'
+'<a href="#"class="btnstyle" onclick="removeJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="定時任務從計划列表中移除" >移除</a>';
}
if(value=="PAUSED"){
msg += '<a href="#"class="btnstyle" onclick="runJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="緊執行一次" >立即執行</a>'
+ '<a href="#"class="btnstyle" onclick="addJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="定時任務按照計划開始執行" >計划</a>'
+'<a href="#"class="btnstyle" onclick="removeJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="定時任務從計划列表中移除" >移除</a>';
}
if(value=="COMPLETE"){
msg += '<a href="#"class="btnstyle" onclick="runJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="緊執行一次" >立即執行</a>'
}
if(value=="BLOCKED"){
msg += '<a href="#"class="btnstyle" onclick="runJob(\''+rowData.id+'\')" '
+'onMouseOver="popTip(this,\' '+rowData+' \' )" class="btn btn-info btn-xs" data-toggle="tooltip"'
+' data-placement="top" title="緊執行一次" >立即執行</a>'
}
if(value=="ERROR"){
}
}
return msg;
}
簡單概述為:已發布的定時任務出現【計划】按鈕;執行【計划】后,定時任務正常運行,且出現【立即執行】【暫停】【移除】三個按鈕,【立即執行】用於測試當前定時任務的業務邏輯是否正確,【暫停】很容易理解,就是把當前任務暫停,及時到達cron定義的時間,定時任務也不會執行,【移除】僅僅是把計划列表中相應的任務暫時清除掉,你可以理解為清除緩存中的定時任務,並不是物理刪除
3.定時任務詳情

3.點擊規則彈出頁面如下,可自行修改界面,這里我是從網上隨便找了個插件,然后按照自己想要的修改下源碼

