Spring+Quartz實現動態添加定時任務

發佈時間:2018-12-03
 
技術:spring4.0.2+quartz2.2.1
 

概述

在最近工做中,因爲涉及到定時任務特別多,而這些工做又是由下屬去完成的,在生成環境中常常會出現業務邏輯錯誤,分析下來多數是定時任務運行問題,因此就但願把定時任務優化一下,主要實現2個方面 1.定時任務動態配置及持久化 2.可視化的管理界面,能夠很是清晰的管理本身的全部定時任務 源碼是我從新梳理後的(陸陸續續花了我好幾天晚上),整個框架去除了多餘的內容,僅保留quartz及springAop,能很是好的解決業務中的定時任務,並且還能所見即所得的知道目前有哪些任務在跑,對任務具體執行的狀況進行日誌分析;框架採用ssm搭建,結合本身工做中框架的結構問題作了優化,若是對這個單體架構感興趣,底層能夠在platform_parent中擴展,應用層可在cloud_parent中進行擴展

詳細

1、準備工做

1.java環境搭建,具體參考包中的webapp/resources/doc/平臺開發環境安裝Guide_V1.0.docx文檔html

image.png

2.使用源碼中的webapp/resources/doc/init.sql初始化表結構及數據前端

t_timetask 任務表java

t_timetask_log 任務運行日誌web

3.數據庫鏈接配置在cloud_parent中的pom.xml中,數據庫名稱ffxl_cloud,默認帳號root,密碼123456,一樣可在pom.xml中修改spring

4.運行quartz項目,此處注意,使用的端口號須要與platform_parent下pom.xml中的quartz.job.url的一致,程序中用的是8080端口,具體使用哪一個配置,請參考maven中profiles的使用sql

5.運行admin項目,注意,此處端口要與quartz不一樣,程序中用的是80端口,瀏覽器中輸入http://localhost/admin 運行結果如圖:數據庫

image.png

2、代碼引入

一、文件引入順序:lib_parent → platform_parent → cloud_parentapache

二、代碼結構json

image.png

3、程序實現

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.前端頁面

1.png

能夠看到在這裏我把定時任務的狀態分爲兩大類,任務狀態跟業務有關,分爲已發佈和未發佈;計劃狀態跟定時任務的運行有關,分爲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.定時任務詳情

2.png

3.點擊規則彈出頁面以下,可自行修改界面,這裏我是從網上隨便找了個插件,而後按照本身想要的修改下源碼

3.png

 

注:本文著做權歸做者,由demo大師發表,拒絕轉載,轉載須要做者受權

相關文章
相關標籤/搜索