定時任務-quartz的使用,實現可頁面化管理
使用spring+quartz實現定時任務的頁面化管理。主要特色:
1.時間表達式等信息配置在數據庫中,從而實現頁面化管理。
2.能夠手動執行或者中止單個任務,也可使一個任務加入或者移出自動運行列表。
下面開始介紹用法,在這以前先說明框架的版本。spring3.2.4+quartz1.6.0
一.配置文件
只須要在spring的配置文件中加入:
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
</bean>
<bean id="jobManager" class="com.temobi.quartz.JobManager">
</bean>
說明:scheduler對象是spring管理定時任務的對象。
jobManager是咱們自定義加載定時任務列表的對象,此對象加載全部任務列表後,將他們加入到自動運行列表。
二.jobManager代碼:
public class JobManager implements InitializingBean {
private static final Log log = LogFactory.getLog(JobManager.class);
@Autowired
TaskJobService taskJobService;
@Autowired
QuartzManager quartzManager;
@Override
public void afterPropertiesSet() throws Exception {
loadAllJob();
}
private void loadAllJob(){
List<TaskJob> list =taskJobService.getTaskList();
quartzManager.enableCronSchedule(list);
}
}
說明:
1.實現spring中InitializingBean接口,並覆蓋afterPropertiesSet方法,則該方法會在應用啓動的時候並且其餘servlet執行完成以後執行,此處用來加載全部定時任務,並加入定時任務自動運行列表。
2.quartzManager是咱們自定義的定時任務管理類,用來實現咱們文章開頭說的功能。
三.QuartzManager代碼
@Controller
public class QuartzManager {
@Autowired
Scheduler scheduler;
private static final Log log = LogFactory.getLog(QuartzManager.class);
public void enableCronSchedule(List<TaskJob> list) {
for(TaskJob task : list){
SchedulingJob job = new SchedulingJob();
job.setJobId(task.getId());
job.setJobName(task.getJobName());
//job.setMemos(task.getNote());
job.setCronExpression(task.getJobCronExpression());
try{
String className= task.getJobClass().trim();
Class clazz = Class.forName(className);
job.setStateFulljobExecuteClass(clazz);
}catch(Exception e){
e.printStackTrace();
continue;
}
JobDataMap paramsMap = new JobDataMap();
paramsMap.put("jobName", task.getJobName());
if(task.getParamsKey1()!=null && task.getParamsValue1()!=null){
paramsMap.put(task.getParamsKey1(), task.getParamsValue1());
}
if(task.getParamsKey2()!=null && task.getParamsValue2()!=null){
paramsMap.put(task.getParamsKey2(), task.getParamsValue2());
}
if(task.getParamsKey3()!=null && task.getParamsValue3()!=null){
paramsMap.put(task.getParamsKey3(), task.getParamsValue3());
}
enableCronSchedule(job, paramsMap, true);
log.info("系統結束初始化任務:"+task.getId()+":"+task.getJobName()+":"+task.getJobId());
}
}
/**
* 啓動一個自定義的job
*
* @param schedulingJob
* 自定義的job
* @param paramsMap
* 傳遞給job執行的數據
* @param isStateFull
* 是不是一個同步定時任務,true:同步,false:異步
* @return 成功則返回true,不然返回false
*/
public boolean enableCronSchedule(SchedulingJob schedulingJob, JobDataMap paramsMap, boolean isStateFull) {
if (schedulingJob == null) {
return false;
}
try {
//scheduler = (Scheduler) ApplicationHelper.getBean("scheduler");
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(schedulingJob.getTriggerName(),
schedulingJob.getJobGroup());
if (null == trigger) {// 若是不存在該trigger則建立一個
JobDetail jobDetail = null;
if (isStateFull) {
jobDetail = new JobDetail(schedulingJob.getJobId(), schedulingJob.getJobGroup(),
schedulingJob.getStateFulljobExecuteClass());
} else {
jobDetail = new JobDetail(schedulingJob.getJobId(), schedulingJob.getJobGroup(),
schedulingJob.getJobExecuteClass());
}
jobDetail.setJobDataMap(paramsMap);
trigger = new CronTrigger(schedulingJob.getTriggerName(), schedulingJob.getJobGroup(),
schedulingJob.getCronExpression());
scheduler.scheduleJob(jobDetail, trigger);
} else {
// Trigger已存在,那麼更新相應的定時設置
trigger.setCronExpression(schedulingJob.getCronExpression());
scheduler.rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 禁用一個job
*
* @param jobId
* 須要被禁用的job的ID
* @param jobGroupId
* 須要被警用的jobGroupId
* @return 成功則返回true,不然返回false
*/
public boolean disableSchedule(String jobId) {
if (jobId.equals("")) {
return false;
}
try {
String jobGroupId="DEFAULT";
Trigger trigger = getJobTrigger(jobId, jobGroupId);
if (null != trigger) {
scheduler.deleteJob(jobId, jobGroupId);
}
} catch (SchedulerException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 獲得job的詳細信息
*
* @param jobId
* job的ID
* @param jobGroupId
* job的組ID
* @return job的詳細信息,若是job不存在則返回null
*/
public JobDetail getJobDetail(String jobId, String jobGroupId) {
if (jobId.equals("") || jobGroupId.equals("") || null == jobId || jobGroupId == null) {
return null;
}
try {
return scheduler.getJobDetail(jobId, jobGroupId);
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
}
/**
* 獲得job對應的Trigger
*
* @param jobId
* job的ID
* @param jobGroupId
* job的組ID
* @return job的Trigger,若是Trigger不存在則返回null
*/
public Trigger getJobTrigger(String jobId, String jobGroupId) {
if (jobId.equals("") || jobGroupId.equals("") || null == jobId || jobGroupId == null) {
return null;
}
try {
return scheduler.getTrigger(jobId + "Trigger", jobGroupId);
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
}
}
說明:
1.主要方法有三個,啓動一個任務,禁用一個任務,啓動多個任務。啓動即加入自動運行列表,禁用即移出自動運行列表。
2.TaskJob是一個任務對象,和數據庫表結構相對應,後面給出數據庫設計。
3.程序中有相似,
paramsMap.put(task.getParamsKey1(), task.getParamsValue1());
這樣的代碼,意思是假如你:若是你在數據庫的ParamsKey1值爲"username",ParamsValue1的值爲"zhangsang".那麼你在具體的job中給定變量名爲"username"的變量並給出set/get方法,就能夠獲得值"zhangsang",此功能適用於給定時任務配置固定參數,而且參數名字隨便你定。咱們這裏給了三個備用的,你也能夠擴展,步驟就是數據庫加一個字段,在上面的程序中paramsMap放入這個字段,固然你也能夠不用參數。你數據庫沒有配置任何值,表示該定時任務沒有固定參數。
4.SchedulingJob是一個定時任務執行參數的bean。即 將Taskjob對象的值通過處理轉換成SchedulingJob對象,而後用SchedulingJob對象的值調用定時任務的API。
SchedulingJob對象主要作的事就是,TriggerName和JobGroup分別給出默認值。根據className生成StateFulljobExecuteClass的Class對象。
四。SchedulingJob代碼:
public class SchedulingJob {
public static final int JS_ENABLED = 0; // 任務啓用狀態
public static final int JS_DISABLED = 1; // 任務禁用狀態
public static final int JS_DELETE = 2; // 任務已刪除狀態
private String jobId; // 任務的Id,通常爲所定義Bean的ID
private String jobName; // 任務的描述
private String jobGroup; // 任務所屬組的名稱
private int jobStatus; // 任務的狀態,0:啓用;1:禁用;2:已刪除
private String cronExpression; // 定時任務運行時間表達式
private String memos; // 任務描述
private Class<?> stateFulljobExecuteClass;//同步的執行類,須要從StatefulMethodInvokingJob繼承
private Class<?> jobExecuteClass;//異步的執行類,須要從MethodInvokingJob繼承
/**
* 獲得該job的Trigger名字
* @return
*/
public String getTriggerName() {
return this.getJobId() + "Trigger";
}
public String getJobId() {
return jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
if(jobGroup==null){
jobGroup = Scheduler.DEFAULT_GROUP;
}
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public int getJobStatus() {
return jobStatus;
}
public void setJobStatus(int jobStatus) {
this.jobStatus = jobStatus;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getMemos() {
return memos;
}
public void setMemos(String memos) {
this.memos = memos;
}
public Class<?> getStateFulljobExecuteClass() {
return stateFulljobExecuteClass;
}
public void setStateFulljobExecuteClass(Class<?> stateFulljobExecuteClass) {
this.stateFulljobExecuteClass = stateFulljobExecuteClass;
}
public Class<?> getJobExecuteClass() {
return jobExecuteClass;
}
public void setJobExecuteClass(Class<?> jobExecuteClass) {
this.jobExecuteClass = jobExecuteClass;
}
public static int getJS_ENABLED() {
return JS_ENABLED;
}
public static int getJS_DISABLED() {
return JS_DISABLED;
}
public static int getJS_DELETE() {
return JS_DELETE;
}
}
五。具體JOB實現
只要繼承QuartzJobBean類,覆蓋executeInternal方法便可。在job中可能經過get方法的方式獲得jobDetail對象中JobDataMap(詳見QuartzManager類)中同名參數值。示例代碼。
@Controller
public class ContentJob extends QuartzJobBean{
@Autowired
TaskJobService taskJobService;
private String beginDate;
private String endDate;
/**
* 手動執行任務
* @param request
*/
@RequestMapping("/contentJobManual.do")
public void manual(HttpServletRequest request) {
String startDate=request.getParameter("startDate");
String endDate=request.getParameter("endDate");
TaskJobService taskJobService = (TaskJobService) ApplicationHelper.getBean("taskJobService");
Map<String, String> param = new HashMap<String, String>();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
String today=sdf.format(new Date());
if(StringUtils.isEmpty(startDate)){
param.put("beginDate", today);
}else{
param.put("beginDate", startDate);
}
if(StringUtils.isEmpty(endDate)){
param.put("endDate", today);
}else{
param.put("endDate", endDate);
}
taskJobService.callStatisticContent(param);
}
@Override
public void executeInternal(JobExecutionContext context) {
TaskJobService taskJobService = (TaskJobService) ApplicationHelper.getBean("taskJobService");
Map<String, String> param = new HashMap<String, String>();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
String today=sdf.format(new Date());
if(StringUtils.isEmpty(beginDate)){
param.put("beginDate", today);
}else{
param.put("beginDate", beginDate);
}
if(StringUtils.isEmpty(endDate)){
param.put("endDate", today);
}else{
param.put("endDate", endDate);
}
taskJobService.callStatisticContent(param);
}
public String getBeginDate() {
return beginDate;
}
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
六。手動執行一個任務。能夠將該job類聲明成一個@Controller。另外寫一個方法如上例中的manual方法。
擴展:目前還不能將自動運行的方法和手動執行的方法(即executeInternal方法和manual方法)寫成一個。由於自動運行的方法不是一個action類,它不在web環境中,是經過反射實現的。若是把executeInternal這個方法強行配置成具備web功能的方法(即類上面加@Controller ,方法上面加@RequestMapping("/contentJobManual.do"))也是不行的,由於該方法沒有HttpServletRequest對象,獲取不了參數。除非你的定時任務沒有參數。固然你也不能修改該方法的參數類型,由於他是覆蓋QuartzJobBean的方法。
七。數據庫設計。
ID VARCHAR2(60) N
JOB_CLASS VARCHAR2(255) N
JOB_NAME VARCHAR2(60) N
JOB_CRON_EXPRESSION VARCHAR2(60) N
JOB_SERVICE_BEAN VARCHAR2(60) Y
PARAMS_KEY1 VARCHAR2(60) Y
PARAMS_VALUE1 VARCHAR2(60) Y
PARAMS_KEY2 VARCHAR2(60) Y
PARAMS_VALUE2 VARCHAR2(60) Y
PARAMS_KEY3 VARCHAR2(60) Y
PARAMS_VALUE3 VARCHAR2(60) Y
NOTE VARCHAR2(255) Y
JOB_STATUS VARCHAR2(1) Y
UPDATETIME DATE Y
JOB_AUTORUN VARCHAR2(1) Y
JOB_GROUP VARCHAR2(60) Y
說明:JOB_STATUS表示是否有效任務,JOB_AUTORUN表示是否自動運行,JOB_SERVICE_BEAN表示手動執行的請求URL,JOB_CLASS表示JOB類的全路徑,JOB_GROUP表示任務屬於哪一個組,方便對任務的分組管理(批量啓動,禁止等),區別於quartz的API所要求的同名參數,其實也能夠把這個值傳給API。其它字段比較好理解。該表對應的bean是taskjob。
八。頁面管理。
主要功能是將一個任務加入或者移出自動運行隊列(經過quartzManager對象)。和任務的增刪查改。示例代碼以下:
@Controller
public class TaskJobAction{
private static final Log log = LogFactory.getLog(TaskJobAction.class);
@Autowired
TaskJobService taskJobService;
@Autowired
QuartzManager quartzManager;
@RequestMapping("/enableTask.do")
public void enableTask(HttpServletRequest request, HttpServletResponse response) throws IOException {
String parameterStr="";
parameterStr = IOUtils.toString(request.getInputStream(), InputConstant.CHAR_SET);
parameterStr = StringUtils.trim(parameterStr);
parameterStr =URLDecoder.decode(parameterStr,"utf-8");
Map<String, String> p = JsonUtil.getParameterMap(parameterStr);
String id=p.get("id");
if(!StringUtils.isEmpty(id)){
TaskJob task=taskJobService.getTaskById(id);
List<TaskJob> list=new ArrayList<TaskJob>();
list.add(task);
quartzManager.enableCronSchedule(list);
task.setJobEnabled("Y");
taskJobService.update(task);//將任務設置成自動運行狀態
}
}
@RequestMapping("/disableTask.do")
public void disableTask(HttpServletRequest request, HttpServletResponse response) throws IOException {
String parameterStr="";
parameterStr = IOUtils.toString(request.getInputStream(), InputConstant.CHAR_SET);
parameterStr = StringUtils.trim(parameterStr);
parameterStr =URLDecoder.decode(parameterStr,"utf-8");
Map<String, String> p = JsonUtil.getParameterMap(parameterStr);
String id=p.get("id");
if(!StringUtils.isEmpty(id)){
TaskJob task=taskJobService.getTaskById(id);
quartzManager.disableSchedule(task.getJobId());
task.setJobEnabled("N");
taskJobService.update(task);//將任務設置成非運行狀態
}
}
@RequestMapping("/add.do")
public void add(HttpServletRequest request, HttpServletResponse response) throws IOException {
String parameterStr="";
parameterStr = IOUtils.toString(request.getInputStream(), InputConstant.CHAR_SET);
parameterStr = StringUtils.trim(parameterStr);
Map<String, String> p = JsonUtil.getParameterMap(parameterStr);
String jobjson=p.get("jobjson");
jobjson=URLDecoder.decode(jobjson,"utf-8");
TaskJob task=JsonUtil.toObject(jobjson, TaskJob.class);
String jobName=URLDecoder.decode(task.getJobName(),"utf-8");
task.setJobName(jobName);
if(!StringUtils.isEmpty(jobjson)){
taskJobService.insert(task);
}
}
@RequestMapping("/update.do")
public void update(HttpServletRequest request, HttpServletResponse response) throws IOException {
String parameterStr="";
parameterStr = IOUtils.toString(request.getInputStream(), InputConstant.CHAR_SET);
parameterStr = StringUtils.trim(parameterStr);
Map<String, String> p = JsonUtil.getParameterMap(parameterStr);
String jobjson=p.get("jobjson");
jobjson=URLDecoder.decode(jobjson,"utf-8");
TaskJob task=JsonUtil.toObject(jobjson, TaskJob.class);
String jobName=URLDecoder.decode(task.getJobName(),"utf-8");
task.setJobName(jobName);
if(!StringUtils.isEmpty(jobjson)){
taskJobService.update(task);
}
}
@RequestMapping("/delete.do")
public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException {
String parameterStr="";
parameterStr = IOUtils.toString(request.getInputStream(), InputConstant.CHAR_SET);
parameterStr = StringUtils.trim(parameterStr);
parameterStr =URLDecoder.decode(parameterStr,"utf-8");
Map<String, String> p = JsonUtil.getParameterMap(parameterStr);
String idStr=p.get("idStr");
if(!StringUtils.isEmpty(idStr)){
taskJobService.delete(idStr);
}
}
@ResponseBody
@RequestMapping("/taskList.do")
public RecordResultBean list(HttpServletRequest request, HttpServletResponse response,@RequestParam("pageSize") int pageSize,
@RequestParam("startIndex") int startIndex) throws IOException {
int pageNum=startIndex/pageSize+1;
String startDate=request.getParameter("startDate");
String endDate=request.getParameter("endDate");
String jobName=request.getParameter("jobName");
if (!StringUtils.isEmpty(jobName)) {
jobName=URLDecoder.decode(jobName, "UTF-8");
jobName=URLDecoder.decode(jobName, "UTF-8");
}
RecordResultBean resultBean = new RecordResultBean();
try {
Pager pager = new Pager(pageNum, pageSize);
Map<String, Object> map = new HashMap<String, Object>();
map.put("jobName",jobName);
pager.setKeys(map);
pager = taskJobService.findPage(pager);
if (pager == null || pager.getTotalCount() == 0) {
resultBean.setResult(false);
} else {
resultBean.setResult(true);
resultBean.setBean(pager);
}
}catch(Exception ex) {
log.warn(JDKStackTrace.getJDKStrack(ex));
}
return resultBean;
}