最近有业务需求要用户自定义一个定时器,最开始想用spring自带的@Scheduled,但是需要用户自定义且要求较高,果断放弃,最后使用Java的定时器大哥Quartz,完没解决需求。不多说直接上码:
pom.xml 中添加
其他的spring相关jar包项目开发应该都整合了
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
Quartz相关方法
import com.css.taskManage.bean.ScheduleJob;
import com.css.taskManage.service.ScheduleJobManageService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QuartzManager {
public final static transient Logger log = LoggerFactory.getLogger(QuartzManager.class);
//这里可以用new的但是在服务器关闭后,定时器的线程没有关
//private static SchedulerFactory schedulerFactory=new SchedulerFactory();
private static Scheduler sched;
//将定时器交给容器管理!
static{
sched = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
}
/**
* @Description: 添加一个定时任务
* @ jobName 任务名
* @ jobGroupName 任务组名
* @ triggerName 触发器名
* @ triggerGroupName 触发器组名
* @ jobClass 任务
* @ cron 时间设置,参考quartz说明文档
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void addJob(ScheduleJob scheduleJob, Class jobClass, ScheduleJobManageService service) {
try {
// Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
.build();
jobDetail.getJobDataMap().put("ScheduleJobManageService", service);
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(scheduleJob.getTriggerName(),scheduleJob.getTriggerGroupName());
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
log.info(scheduleJob.getJobName()+scheduleJob.getJobGroup()+"定时器已经启动");
} catch (Exception e) {
log.error(scheduleJob.getJobName()+scheduleJob.getJobGroup()+"定时任务启动失败",e);
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
*/
public static void modifyJobTime(String jobName,String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
// Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
// log.info(scheduleJob.getJobName()+scheduleJob.getJobGroup()+"定时器已经启动");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*/
public static void removeJob(ScheduleJob scheduleJob) {
try {
// Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getTriggerName(), scheduleJob.getTriggerGroupName());
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()));// 删除任务
log.info(scheduleJob.getJobName()+scheduleJob.getJobGroup()+"定时任务已移除");
} catch (Exception e) {
log.error(scheduleJob.getJobName()+scheduleJob.getJobGroup()+"定时任务移除失败",e);
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
// Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
// Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
spring-*的配置文件中加入
<!--定时器的bean-->
<bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- <property name="startupDelay" value="180"/> 启动服务器后延迟启动定时任务-->
</bean>
<!--获取spring上下文的bean,是为了获取schedulerFactoryBean,将定时器交给spring容器管理,如果new的话,服务器关闭后,定时器并不会关闭!-->
<bean id="springContextUtil" class="com.css.commcon.util.SpringContextUtil" lazy-init="false"/>
springContextUtil类,获取spring所管理对象的工具类
package com.css.commcon.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文环境
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法。设置上下文环境
*
* @param applicationContext
*/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
/**
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 获取对象
*
* @param name
* @return Object
* @throws BeansException
*/
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
}
前端页面
前端jsp页面代码
前端部分数据不全!但业务功能是没有问题的。
前端框架是ligerUI,时间选择器是My97DatePicker
<table cellpadding="0" cellspacing="0" class="l-table-edit" style="margin:0 auto;">
<tr class="l-table-edit-tr"> </tr>
<tr class="l-table-edit-tr">
<td align="right" class="l-table-edit-td">起始时间:</td>
<td align="left" class="l-table-edit-td-input">
<%--<input id="Ddl_Year1" type="text" runat="server" onfocus="WdatePicker({skin:'default',dateFmt:'yyyy'})"/>--%>
<input id="startTime" name="startTime" type="text" validate="{required:true}"
onfocus="WdatePicker({minDate:'%y-%M-{%d}',maxDate:'#F{$dp.$D(\'endTime\')||\'%y-%M-%ld\'}'})"/>
</td><%--开始时间不能小于结束时间--%>
<td align="left"></td>
<td align="right" class="l-table-edit-td">结束时间:</td>
<td align="left" class="l-table-edit-td-input">
<input id="endTime" name="endTime" type="text" validate="{required:true}"
onfocus="WdatePicker({minDate:'#F{$dp.$D(\'startTime\')}',maxDate:'%y-%M-%ld'})"/>
</td>
<td align="left"></td>
<td align="right" class="l-table-edit-td">下发时间:</td>
<td align="left" class="l-table-edit-td-input">
<input id="cycleTime" type="text" name="cycleTime" validate="{required:true}"
onfocus="WdatePicker({skin:'default',dateFmt:'HH:mm'})"/>
</td>
<td align="left"></td>
</tr>
</table>
</form>
<div style="margin-right: 450px;margin-top:50px; ">
<button type="button" id="sures" name="dsa" class="choses"
onclick="sureOutQuartz();">确定
</button>
</div>
前端js页面代码
function sureOutQuartz(){
if(jobGrid.data.Rows.length>0){
top.$.ligerDialog.warn("你已经有定时任务存在,无法再添加!请删除后添加");
return;
}
var v = $("#taskOutManages").validate({
debug : true,
errorPlacement : function(lable, element) {
if (element.hasClass("l-textarea")) {
element.ligerTip({
content : lable.html(),
target : element[0]
});
} else if (element.hasClass("l-text-field")) {
element.parent().ligerTip({
content : lable.html(),
target : element[0]
});
} else {
lable.appendTo(element.parents("td:first").next("td"));
}
},
success : function(lable) {
lable.ligerHideTip();
lable.remove();
},
submitHandler : function() {
$("#" + routeName + " .l-text,.l-textarea").ligerHideTip();
subScheduleJob();
}
});
if($("#taskOutManages").valid()){
subScheduleJob();
}
}
function subScheduleJob() {
var data =$("#taskOutManages").serializeArray();
var url = basePath + "rest/scheduleJobManageAction/taskQuartz";
$.ajax({
url : url,
type : "post",
dataType : "json",
data : $.param(data),
success : function(json) {
$("#taskOutManages :input").not(":button, :submit, :reset, :hidden").val("").removeAttr("checked").remove("selected");
//回调,写自己需要的业务
},
error : function(json) {
//回调失败,写自己需要的业务
}
});
}
业务controller
@Controller
@RequestMapping("/scheduleJobManageAction")
public class ScheduleJobManageAction extends BaseSpringSupportAction<ScheduleJob, ScheduleJobManageService> {
//@Autowired
private ScheduleJobManageService service;
@Override
public ScheduleJobManageService getEntityManager() {
return service;
}
public ScheduleJobManageService getService() {
return service;
}
@Resource(name="scheduleJobManageService")
public void setService(ScheduleJobManageService service) {
this.service = service;
}
@RequestMapping({ "taskQuartz" })
@ResponseBody
public HashMap<String, Object> taskQuartz(HttpServletRequest request, ScheduleJob scheduleJob,String groups,String groupsShow) {
try {
String cron = "";//定时表达式,看Quartz 的API,网上有相应的解释
String startTime = scheduleJob.getStartTime();
String endTime = scheduleJob.getEndTime();
String cycleTime = scheduleJob.getCycleTime();
String[] data=startTime.split("-");
String day=data[2]+"-"+endTime.split("-")[2];
String[] time = cycleTime.split(":");
cron = "0 "+time[1]+" "+time[0]+" "+day+" "+data[1]+" ? "+ data[0] +"-"+data[0];
SysUser user= SessionUtils.getUser(request);//装配定时器的相关属性,可以根据自己的业务自行配制
scheduleJob.setJobName(user.getId().toString());
scheduleJob.setJobGroup(user.getName());
scheduleJob.setTriggerName(user.getPcode());
scheduleJob.setTriggerGroupName(user.getAreaCode());
scheduleJob.setCronExpression(cron);
scheduleJob.setGroupIds(groups);
scheduleJob.setGroupNames(groupsShow);
QuartzManager.removeJob(scheduleJob);
QuartzManager.addJob(scheduleJob, MyJob.class,service);
this.save(request,scheduleJob);
return JsonWrapper.successWrapper(scheduleJob,"定时任务已启动!");
} catch (Exception e) {
this.log.error(e.getMessage(),e);
return JsonWrapper.failureWrapperMsg("系统出错,请联系管理员");
}
}
@RequestMapping({ "removeQuartzJob" })
@ResponseBody
public HashMap<String, Object> removeQuartzJob(HttpServletRequest request, Integer id) {
try {
if(id==null){
return JsonWrapper.failureWrapperMsg("定时任务的不存在,请刷新后重试!");
}
ScheduleJob scheduleJob = this.getEntityManager().get(id);
if(scheduleJob==null){
return JsonWrapper.failureWrapperMsg("定时任务的不存在,请刷新后重试!");
}
this.delete(id.toString());
QuartzManager.removeJob(scheduleJob);
return JsonWrapper.successWrapper(scheduleJob,"定时任务已移除!");
} catch (Exception e) {
this.log.error(e.getMessage(),e);
return JsonWrapper.failureWrapperMsg("系统出错,请联系管理员");
}
}
}
任务和业务的实体
package com.css.taskManage.bean;
import com.css.commcon.bean.BaseEntity;
import com.css.commcon.util.Constant;
import com.css.commcon.util.JsonDateSerializer;
import com.css.commcon.util.StringUtil;
import com.css.sysManage.bean.SysArea;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "schedule_job")
public class ScheduleJob implements BaseEntity {
private Integer id;
@Column(name = "create_date")
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = JsonDateSerializer.class)
private Date createDate;
@Column(name = "update_date")
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = JsonDateSerializer.class)
private Date updateDate;
@Column(name = "job_name")
private String jobName;
@Column(name = "job_group")
private String jobGroup;
@Column(name = "job_status")
private String jobStatus;
@Column(name = "cron_expression")
private String cronExpression;
@Column(name = "description")
private String description;
@Column(name = "trigger_name")
private String triggerName;
@Column(name = "trigger_group_name")
private String triggerGroupName;
@Column(name = "group_ids")
private String groupIds;
@Column(name = "group_names")
private String groupNames;
@Column(name = "amount")
private Integer amount;
@Column(name = "start_time")
private String startTime;
@Column(name = "end_time")
private String endTime;
@Column(name = "cycle_time")
private String cycleTime;
//getter和setter
public ScheduleJob() {
}
public ScheduleJob(String jobName, String jobGroup, String triggerName, String triggerGroupName, String cronExpression) {
this.jobName = jobName;
this.jobGroup = jobGroup;
this.triggerName = triggerName;
this.triggerGroupName = triggerGroupName;
this.cronExpression = cronExpression;
}
定时器的方法类具体的业务类
package com.css.taskManage.job;
import com.css.commcon.util.QuartzManager;
import com.css.taskManage.bean.ScheduleJob;
import com.css.taskManage.service.ScheduleJobManageService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyJob implements Job {
//这里不能直接@Autowired,如果引用的话下面的方法不能用,需要的参数,要从QuartzManager传。
//不知道是不是我没有在类上面加注解,这里不能引用Spring管理的Bean!有兴趣可以自己试一试!
public final transient Logger log = LoggerFactory.getLogger(MyJob.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info("定时器开始运行!");
ScheduleJob scheduleJob = null;
String jobName ="" ;
String jobGroupName ="";
try {
ScheduleJobManageService service = (ScheduleJobManageService) jobExecutionContext.getJobDetail().getJobDataMap().get("ScheduleJobManageService");
scheduleJob = (ScheduleJob) jobExecutionContext.getJobDetail().getJobDataMap().get("scheduleJob");//接收QuartzManager传过来的参数,
jobName = scheduleJob.getJobName();
jobGroupName = scheduleJob.getJobGroup();
String groupIds = scheduleJob.getGroupIds();
Integer amount = scheduleJob.getAmount();
service.timmerTask(groupIds,amount, jobGroupName,scheduleJob.getTriggerGroupName());//具体的业务操作,这里就粘贴出来了!根据自己的业务写!
log.info(jobName +jobGroupName +"定时器运行结束!");
}catch (Exception e){
QuartzManager.removeJob(scheduleJob);
log.error(e.getMessage(),e);
throw new RuntimeException(jobName +jobGroupName +"定时器意外终止");
}
}
}
最后上图表示成功:
以上部分代码有借鉴网上大神的。如有侵权请联系删帖。QQ:718563711