spring之quartz的配置与使用

spring之quartz的配置与使用

在项目中要使用定时启动某些应用的时候,我们可以用quartz定时器。那接下来讲一下在项目中的使用。

1. 首先要在maven中添加架包依赖

   <!--定时任务框架-->
    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>2.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz-jobs</artifactId>
      <version>2.2.3</version>
    </dependency>

 2. spring配置文件

        <!-- 项目启动开启定时对象和方法 -->
	<bean id="cancelOrderJob"
		  class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<!-- 对象 -->
		<property name="targetObject" ref="timersInfoService" />
		<!-- 方法 -->
		<property name="targetMethod" value="quartsJob" />
	</bean>
	<!-- 定时出发时间 -->
	<bean id="cancelOrderTrigger"
		  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<!-- 任务明细 -->
		<property name="jobDetail" ref="cancelOrderJob" />
		 <!--cron表达式-->
		<property name="cronExpression" value="0 0/1 * * * ?" /><!--每隔1小时0 0 */1 * * ?-->
	</bean>

3. 表示层(Controller)代码TimersInfoController.java

   @RequiresPermissions("timers:timersInfo:view")
    @RequestMapping(value = "form")
    public String form(TimersInfo timersInfo, Model model) {
        model.addAttribute("timersInfo", timersInfo);
        return "modules/timers/timersInfoForm";
    }

    @RequiresPermissions("timers:timersInfo:edit")
    @RequestMapping(value = "save")
    public String save(TimersInfo timersInfo, Model model, RedirectAttributes redirectAttributes) {
        if (!beanValidator(model, timersInfo)) {
            return form(timersInfo, model);
        }
        timersInfoService.save(timersInfo);
        addMessage(redirectAttributes, "保存系统定时任务成功");
        return "redirect:" + Global.getAdminPath() + "/timers/timersInfo/list?repage";
    }

    @RequiresPermissions("timers:timersInfo:edit")
    @RequestMapping(value = "delete")
    public String delete(TimersInfo timersInfo, RedirectAttributes redirectAttributes) {
        timersInfoService.delete(timersInfo);
        addMessage(redirectAttributes, "删除系统定时任务成功");
        return "redirect:" + Global.getAdminPath() + "/timers/timersInfo/list?repage";
    }

    @RequiresPermissions("timers:timersInfo:edit")
    @RequestMapping(value = "start")
    public String start(TimersInfo timersInfo, RedirectAttributes redirectAttributes) {
        timersInfoService.start(timersInfo);
        addMessage(redirectAttributes, "开启系统定时任务成功");
        return "redirect:" + Global.getAdminPath() + "/timers/timersInfo/list?repage";
    }

    @RequiresPermissions("timers:timersInfo:edit")
    @RequestMapping(value = "shutdown")
    public String shutdown(TimersInfo timersInfo, RedirectAttributes redirectAttributes){
        timersInfoService.shutdown(timersInfo);
        addMessage(redirectAttributes, "关闭系统定时任务成功");
        return "redirect:" + Global.getAdminPath() + "/timers/timersInfo/list?repage";
    }

    @RequiresPermissions("timers:timersInfo:edit")
    @RequestMapping(value = "checkIsExist")
    @ResponseBody
    public String checkIsExist(TimersInfo timersInfo) {
        return timersInfoService.checkIsExist(timersInfo);
    }

4. 逻辑业务层(Service)代码TimersInfoService.java

 @Transactional(readOnly = false)
    public void save(TimersInfo timersInfo) {
        super.save(timersInfo);
    }

    @Transactional(readOnly = false)
    public void delete(TimersInfo timersInfo) {
        super.delete(timersInfo);
    }

    @Transactional(readOnly = false)
    public void start(TimersInfo timersInfo) {
        //开启定时
        QuartzLoad.addJob(timersInfo);
        //修改定时状态
        timersInfo.preUpdate();
        timersInfo.setTimerStatus("1");
        timersInfoDao.updateTimerStatus(timersInfo);
    }

    @Transactional(readOnly = false)
    public void shutdown(TimersInfo timersInfo) {
        //移除定时
        QuartzLoad.removeJob(timersInfo);
        //修改定时状态
        timersInfo.preUpdate();
        timersInfo.setTimerStatus("0");
        timersInfoDao.updateTimerStatus(timersInfo);
    }


    /**
     * 项目启动开始的定时任务,负责开启库中开启的状态的定时任务
     */
    public void quartsJob() {
        //只执行一次
        while (i++ == 0) {
            List<TimersInfo> timersInfos = timersInfoDao.findTimerStatus();
            for (TimersInfo timersInfo : timersInfos) {
                //开启定时
                QuartzLoad.addJob(timersInfo);
            }
        }
    }

    /**
     * 校验所属区域是否存在
     */
    public String checkIsExist(TimersInfo timersInfo) {
        int retval = timersInfoDao.checkIsExist(timersInfo);
        if (retval > 0) {
            return "false";
        }
        return "true";
    }

5. 定时器工具类QuartzLoad.java

public class QuartzLoad {

    public static void addJob(TimersInfo timersInfo) {
        try {
            // String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron
            // TODO: 2017/11/9/009  出发时间自己设定,为方便测试 设置为1分钟执行一次
            //  String cron = "0 0/1 * * * ?";
            String cron = getCron(timersInfo.getExecTime());

            // 任务名,任务组,任务执行类
            JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) MyJob.class).withIdentity(timersInfo.getTimesName(), timersInfo.getRegionId()).build();

            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(timersInfo.getTimesName(), timersInfo.getId());
            triggerBuilder.startNow();
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            CronTrigger trigger = (CronTrigger) triggerBuilder.build();

            //创建scheduler对象
            SchedulerFactory sfact = new StdSchedulerFactory();
            Scheduler scheduler = sfact.getScheduler();
            // scheduler.start();

            // 调度容器设置JobDetail和Trigger
            scheduler.scheduleJob(jobDetail, trigger);

            // 启动
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //移除一个任务
    public static void removeJob(TimersInfo timersInfoe) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(timersInfoe.getTimesName(), timersInfoe.getId());

            //创建scheduler对象
            SchedulerFactory sfact = new StdSchedulerFactory();
            Scheduler scheduler = sfact.getScheduler();
            //scheduler.start();

            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            scheduler.deleteJob(JobKey.jobKey(timersInfoe.getTimesName(), timersInfoe.getRegionId()));// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //停止 关闭所有定时任务
    public static void stop() throws Exception {
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        // scheduler.start();
        scheduler.shutdown();
    }


    /**
     * 获取时分秒的cron表达式
     *
     * @param time 时分秒(23:09:08)
     * @return cron表达式
     */
    public static String getCron(String time) {
        String[] str = time.split(":");
        StringBuffer sbf = new StringBuffer();
        for (int i = (str.length - 1); i > -1; i--)
            sbf.append(Integer.parseInt(str[i]) + " ");
        sbf.append("* * ?");
        return sbf.toString();
    }

    public static void main(String[] args) {
        System.out.println(getCron("23:09:08"));
    }
}

6. 使用定时器MyJob.java

该类要实现Job接口才能使用。

         /**
	 * 统一处理定时业务
	 */
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		TimersKeywordService service = (TimersKeywordService) SpringContextUtil.getBean("timersKeywordService",
				TimersKeywordService.class);
logger.info("进入定时任务业务区===============================>>【begin】");
		logger.info("能获取的参数:{编号[id]:" + ((CronTriggerImpl) ((JobExecutionContextImpl) arg0).getTrigger()).getGroup()
				+ ",定时器名称[timesName]:" + ((CronTriggerImpl) ((JobExecutionContextImpl) arg0).getTrigger()).getName()
				+ ",定时器名称[timesName]:" + arg0.getJobDetail().getKey().getName() + ",区域id[regionId]:"
				+ arg0.getJobDetail().getKey().getGroup() + "}");
		timersId = ((CronTriggerImpl) ((JobExecutionContextImpl) arg0).getTrigger()).getGroup();}

7. 界面展示timesInfoList.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<html>
<head>
	<title>系统定时任务管理</title>
	<meta name="decorator" content="default"/>
	<script type="text/javascript">
		$(document).ready(function() {
			 $("#btnDelete").click(function(){
	        		var row = document.getElementsByName("box");
	 				 ids = [];
	 				for(i in row){
	 					if(row[i].checked){
	 						ids.push(row[i].value);
	 					}
	 				}
	 				if(ids.length == 0){
						top.$.jBox.alert("请选择要删除的数据","系统提示");
					}else{
						top.$.jBox.confirm("确定删除选中的数据?","系统提示",function(v,h,f){
		     				if(v=="ok"){
		     					$("#searchForm").attr("action","${ctx}/timers/timersInfo/delete?id="+ids);
		     					$("#searchForm").submit();
		     					
		     				}
		     			},{buttonsFocus:1});
					}
	     			top.$('.jbox-body .jbox-icon').css('top','55px');
	     		});
	        	 $("#btnUpdate").click(function(){
	         		var row = document.getElementsByName("box");
	  				 ids = [];
	  				for(i in row){
	  					if(row[i].checked){
	  						ids.push(row[i].value);
	  					}
	  				}
	  				if(ids.length == 0){
	 					top.$.jBox.alert("请选择要修改的数据","系统提示");
	 				}else if(ids.length == 1){
	 	     			$("#searchForm").attr("action","${ctx}/timers/timersInfo/form?id="+ids);
	 	     			$("#searchForm").submit();
	 				}else {
	 					top.$.jBox.alert("只能修改一条数据","系统提示");
	 				}
	      			top.$('.jbox-body .jbox-icon').css('top','55px');
	      		});
	        	 $("#btnSave").click(function(){
		 	     	$("#searchForm").attr("action","${ctx}/timers/timersInfo/form");
		 	     	$("#searchForm").submit();
		      	});
		});
		function page(n,s){
			$("#pageNo").val(n);
			$("#pageSize").val(s);
			$("#searchForm").submit();
        	return false;
        }
	</script>
</head>
<body>
	<form:form id="searchForm" modelAttribute="timersInfo" action="${ctx}/timers/timersInfo/" method="post" class="breadcrumb form-search">
		<input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
		<input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
		<ul class="ul-form">
		<li><label style="width: 85px;">定时器名称 :</label>
			<form:input path="timesName" htmlEscape="false"
					maxlength="50" class="input-medium" /></li>
			<li><label style="width: 70px;">所属地区:</label> <sys:treeselect
					id="company" name="regionId" value="${office.id}"
					labelName="office.name" labelValue="${office.name}" title="归属区域"
					url="/sys/office/treeData2?type=1" cssClass="input-small"
					allowClear="true" notAllowSelectParent="true" /></li>
			<li class="btns"><input id="btnSubmit" class="btn btn-primary" type="submit" value="查询" />
			</li>
		<shiro:hasPermission name="timers:timersInfo:edit">
			<li class="btns"><input id="btnSave" class="btn btn-primary" type="button" value="添加"/></li>
	        <!-- <li class="btns"><input id="btnUpdate" class="btn btn-primary" type="button" value="修改"/></li>
			<li class="btns"><input id="btnDelete" class="btn btn-primary" type="button" value="删除"/></li> -->
		</shiro:hasPermission>
		</ul>
	</form:form>
	<sys:message content="${message}"/>
	<table id="contentTable" class="table table-striped table-bordered table-condensed">
		<thead>
			<tr>
				<th>定时器名称</th>
				<th>所属地区</th>
				<th>定时任务状态</th>
				<th>执行时间</th>
				<shiro:hasPermission name="timers:timersInfo:edit"><th>操作</th></shiro:hasPermission>
			</tr>
		</thead>
		<tbody>
		<c:forEach items="${page.list}" var="timersInfo">
			<tr>
				<td>
					<c:if test="${timersInfo.timerStatus ne '1'}">
						<a href="${ctx}/timers/timersInfo/form?id=${timersInfo.id}">
							${timersInfo.timesName}
						</a>
					</c:if>
					<c:if test="${timersInfo.timerStatus eq '1'}">
						${timersInfo.timesName}
					</c:if>
				</td>
				<td>
					    ${timersInfo.regionName}
				</td>
				<td>
						<c:if test="${timersInfo.timerStatus eq '0'}"><c:out value="未开启"></c:out> </c:if>
						<c:if test="${timersInfo.timerStatus eq '1'}"><c:out value="开启"></c:out> </c:if>
						<c:if test="${timersInfo.timerStatus eq '2'}"><c:out value="已关闭"></c:out> </c:if>
				</td>
				<td>
					${timersInfo.execTime}
				</td>
				<shiro:hasPermission name="timers:timersInfo:edit">
					<td>
						<c:if test="${timersInfo.timerStatus ne '1'}">
							<a href="${ctx}/timers/timersInfo/form?id=${timersInfo.id}">修改</a>
							<a href="${ctx}/timers/timersInfo/delete?id=${timersInfo.id}" οnclick="return confirmx('确认要删除该系统定时任务吗?', this.href)">删除</a>
							<a href="${ctx}/timers/timersInfo/start?id=${timersInfo.id}" οnclick="return confirmx('确认要开启该系统定时任务吗?', this.href)">开启</a>
						</c:if>
						<c:if test="${timersInfo.timerStatus eq '1'}">
							<a href="${ctx}/timers/timersInfo/shutdown?id=${timersInfo.id}" οnclick="return confirmx('确认要关闭该系统定时任务吗?', this.href)">关闭</a>
						</c:if>
				</td>
				</shiro:hasPermission>
			</tr>
		</c:forEach>
		</tbody>
	</table>
	<div class="pagination">${page}</div>
</body>
</html>

8. 界面展示timesInfoForm.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/WEB-INF/views/include/taglib.jsp" %>
<html>
<head>
    <title>系统定时任务管理</title>
    <meta name="decorator" content="default"/>
    <script type="text/javascript">
        var fetch = true;
        $(document).ready(function () {
            $("#inputForm").validate({
                rules: {
                    timesName: "required",
                    execTime: "required"
                },
                messages: {
                    timesName: "请输入定时器名称",
                    execTime: "请输入执行时间"
                },
                submitHandler: function (form) {
                    $.ajax({
                        type: 'POST',
                        cache: false,
                        async: false,
                        url: ctx + "/timers/timersInfo/checkIsExist",
                        data: {"id": $("#id").val(), "regionId": $("#regionId").val()},
                        success: function (data) {
                            if (data == "false" && fetch) {
                                fetch = false;
                                $("#tree").show();
                                return false;
                            }
                        }
                    });
                    if (!fetch) {
                        fetch = true;
                        return;
                    }
                    loading('正在提交,请稍等...');
                    form.submit();
                },
                errorContainer: "#messageBox",
                errorPlacement: function (error, element) {
                    $("#messageBox").text("输入有误,请先更正。");
                    if (element.is(":checkbox") || element.is(":radio") || element.parent().is(".input-append")) {
                        error.appendTo(element.parent().parent());
                    } else {
                        error.insertAfter(element);
                    }
                }
            });
        });
    </script>
</head>
<body>
<ul class="nav nav-tabs">
    <li><a href="${ctx}/timers/timersInfo/">系统定时任务列表</a></li>
    <li class="active"><a href="${ctx}/timers/timersInfo/form?id=${timersInfo.id}">系统定时任务<shiro:hasPermission
            name="timers:timersInfo:edit">${not empty timersInfo.id?'修改':'添加'}</shiro:hasPermission><shiro:lacksPermission
            name="timers:timersInfo:edit">查看</shiro:lacksPermission></a></li>
</ul>
<br/>
<form:form id="inputForm" modelAttribute="timersInfo" action="${ctx}/timers/timersInfo/save" method="post"
           class="form-horizontal">
    <form:hidden path="id"/>
    <sys:message content="${message}"/>
    <div class="control-group">
        <label class="control-label">所属地市:</label>
        <div class="controls">
            <sys:treeselect id="region" name="regionId" value="${timersInfo.regionId}" labelName="timersInfo.regionName"
                            labelValue="${timersInfo.regionName}"
                            title="区域" url="/sys/office/treeData2?type=1" cssClass="required"/>
            <label for="regionId" class="error" style="display: none" id="tree">已存在该所属地市</label>
        </div>
    </div>
    <div class="control-group">
        <label class="control-label">定时器名称:</label>
        <div class="controls">
            <form:input path="timesName" htmlEscape="false" maxlength="64" class="input-xlarge "/>
        </div>
    </div>
    <div class="control-group">
        <label class="control-label">执行时间:</label>
        <div class="controls">
            <input id="execTime" name="execTime" type="text" readonly="readonly" maxlength="20"
                   class="input-medium Wdate"
                   value="${timersInfo.execTime}"
                   οnclick="WdatePicker({dateFmt:'HH:mm:ss',isShowClear:false});"/>
        </div>
    </div>
    <div class="form-actions">
        <shiro:hasPermission name="timers:timersInfo:edit"><input id="btnSubmit" class="btn btn-primary" type="submit"
                                                                  value="保 存"/> </shiro:hasPermission>
        <input id="btnCancel" class="btn" type="button" value="返 回" οnclick="history.go(-1)"/>
    </div>
</form:form>
</body>
</html>

cron表达式:

格式: [秒] [分] [小时] [日] [月] [周] [年]

0 0 12 * * ?          每天12点触发
0 15 10 ? * *          每天10点15分触发
0 15 10 * * ?          每天10点15分触发 
0 15 10 * * ? *        每天10点15分触发 
0 15 10 * * ? 2005     2005年每天10点15分触发
0 * 14 * * ?           每天下午的 2点到2点59分每分触发
0 0/5 14 * * ?         每天下午的 2点到2点59分(整点开始,每隔5分触发) 
0 0/5 14,18 * * ?        每天下午的 18点到18点59分(整点开始,每隔5分触发)

0 0-5 14 * * ?           每天下午的 2点到2点05分每分触发
0 10,44 14 ? 3 WED        3月分每周三下午的 2点10分和2点44分触发
0 15 10 ? * MON-FRI       从周一到周五每天上午的10点15分触发
0 15 10 15 * ?            每月15号上午10点15分触发
0 15 10 L * ?             每月最后一天的10点15分触发
0 15 10 ? * 6L            每月最后一周的星期五的10点15分触发
0 15 10 ? * 6L 2002-2005  从2002年到2005年每月最后一周的星期五的10点15分触发

0 15 10 ? * 6#3          每月的第三周的星期五开始触发
0 0 12 1/5 * ?            每月的第一个中午开始每隔5天触发一次
0 11 11 11 11 ?           每年的11月11号 11点11分触发(光棍节)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值