【SSH项目实战】国税协同平台-34.quartz&CronTrigger

简介:
我们上次使用quartz任务调度框架创建了一个在后台按照时间间隔不停运行的任务,我们使用的是simpleTrigger简单触发器,为了实现我们的月末自动回复的功能,我们要设置触发器能够在某个精确时间去自动执行任务,那么使用simpleTrigger简单触发器就远远不够了,我们需要使用CronTrigger任务触发器来实现这个功能。

我们的CronTrigger设置步骤如下:
任务触发器(CronTrigger)
① 设置任务详细
② 设置执行时机(cronExpression)
cronExpression:秒 分 时 日 月 周 年(可选)

我们先在任务类中写另外一个执行方法:
package cn.edu.hpu.tax.complain;

import java.text.SimpleDateFormat;
import java.util.Date;

public class QuartzTask {
	
	public void doSimpleTriggerTask() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("doing simpleTrigger task..."+sdf.format(new Date()));
	}
	
	public void doCronTriggerTask() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("doing cronTrigger task..."+sdf.format(new Date()));
	}
}

就是上面的doCronTriggerTask()

然后修改我们的quartz的配置文件quartz-spring.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <!-- 注册一个普通bean -->
    <bean id="quartzTask" class="cn.edu.hpu.tax.complain.QuartzTask"></bean>
    
    <!-- 1.指定任务详细信息 -->
    <bean id="jobDetial1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	    <!--  ① 设置执行对象 -->
	    <property name="targetObject" ref="quartzTask"></property>
	    <!--  ② 设置执行对象中对应的执行方法 -->
	    <property name="targetMethod" value="doSimpleTriggerTask"></property>
	    <!--  ③ 是否可以同步执行(这里设置不同步执行) -->
	    <property name="concurrent" value="false"></property>
    </bean>
  
    <bean id="jobDetial2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	    <!--  ① 设置执行对象 -->
	    <property name="targetObject" ref="quartzTask"></property>
	    <!--  ② 设置执行对象中对应的执行方法 -->
	    <property name="targetMethod" value="doCronTriggerTask"></property>
	    <!--  ③ 是否可以同步执行(这里设置不同步执行) -->
	    <property name="concurrent" value="false"></property>
    </bean>
    
    <!-- 2.制定任务执行时机(任务执行触发器) -->
    <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    	<!-- ① 设置任务详细 -->
    	<property name="jobDetail" ref="jobDetial1"></property>
  	 	<!-- ② 设置任务延迟执行时间(延迟2秒) -->
  	 	<property name="startDelay" value="2000"></property>
   		<!-- ③ 设置任务执行频率(执行频率为每2秒执行一下) -->
   		<property name="repeatInterval" value="2000"></property>
    </bean>
    
    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    	<!-- 设置任务详细 -->
    	<property name="jobDetail" ref="jobDetial2"></property>
    	<!-- 设置任务执行时机,cron表达式 -->
    	<property name="cronExpression" value="0/3 * * * * ?"></property>
    </bean>
    
    <!-- 3.设置调度工厂 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    	<property name="triggers">
    		<list>
    			<!-- 第一个触发器 -->
    			<ref bean="simpleTrigger"/>
    			<!-- 第二个触发器 -->
    			<ref bean="cronTrigger"/>
    		</list>
    	</property>
    </bean>
</beans>

CronTrigger中的 cronExpression 表达式属性中接收的内容:
在表达式中时间格式间用空格隔开,每个时间表示:秒 分钟 小时 日 月 周 年(可选填)
可出现的值和符合:


'*' 字符可以用于所有字段,在“分”字段中设为"*"表示"每一分钟"的含义。

'?' 字符可以用在“日”和“周几”字段. 它用来指定 '不明确的值'. 这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。在后面的例子中可以看到其含义。

'-' 字符被用来指定一个值的范围,比如在“小时”字段中设为"10-12"表示"10点到12点".

',' 字符指定数个值。比如在“周几”字段中设为"MON,WED,FRI"表示"the days Monday, Wednesday, and Friday".

'/' 字符用来指定一个值的的增加幅度. 比如在“秒”字段中设置为"0/15"表示"第0, 15, 30, 和 45秒"。而 "5/15"则表示"第5, 20, 35, 和 50". 在'/'前加"*"字符相当于指定从0秒开始. 每个字段都有一系列可以开始或结束的数值。对于“秒”和“分”字段来说,其数值范围为0到59,对于“小时”字段来说其为0到23, 对于“日”字段来说为0到31, 而对于“月”字段来说为1到12。"/"字段仅仅只是帮助你在允许的数值范围内从开始"第n"的值。 因此对于“月”字段来说"7/6"只是表示7月被开启而不是“每六个月”, 请注意其中微妙的差别。

'L'字符可用在“日”和“周几”这两个字段。它是"last"的缩写, 但是在这两个字段中有不同的含义。例如,“日”字段中的"L"表示"一个月中的最后一天" —— 对于一月就是31号对于二月来说就是28号(非闰年)。而在“周几”字段中, 它简单的表示"7" or "SAT",但是如果在“周几”字段中使用时跟在某个数字之后, 它表示"该月最后一个星期×" —— 比如"6L"表示"该月最后一个周五"。当使用'L'选项时,指定确定的列表或者范围非常重要,否则你会被结果搞糊涂的。

'W' 可用于“日”字段。用来指定历给定日期最近的工作日(周一到周五) 。比如你将“日”字段设为"15W",意为: "离该月15号最近的工作日"。因此如果15号为周六,触发器会在14号即周五调用。如果15号为周日, 触发器会在16号也就是周一触发。如果15号为周二,那么当天就会触发。然而如果你将“日”字段设为"1W", 而一号又是周六, 触发器会于下周一也就是当月的3号触发,因为它不会越过当月的值的范围边界。'W'字符只能用于“日”字段的值为单独的一天而不是一系列值的时候。

'L'和'W'可以组合用于“日”字段表示为'LW',意为"该月最后一个工作日"。

'#' 字符可用于“周几”字段。该字符表示“该月第几个周×”,比如"6#3"表示该月第三个周五( 6表示周五而"#3"该月第三个)。再比如: "2#1" = 表示该月第一个周一而 "4#5" = 该月第五个周三。注意如果你指定"#5"该月没有第五个“周×”,该月是不会触发的。

'C' 字符可用于“日”和“周几”字段,它是"calendar"的缩写。它表示为基于相关的日历所计算出的值(如果有的话)。如果没有关联的日历, 那它等同于包含全部日历。“日”字段值为"5C"表示"日历中的第一天或者5号及其以后",“周几”字段值为"1C"则表示"日历中的第一天或者周日及其以后"。

对于“月份”字段和“周几”字段来说合法的字符都不是大小写敏感的。

官方文档示例:



我们在其中设置的是"0/3 * * * * ?"意思就是每天每时每隔3秒执行一次任务。我们和之前的simpleTrigger一起执行,来测试我们的配置是否成功:
重启服务器,发现控制台输出以下信息:
......
信息: Server startup in 16932 ms
doing simpleTrigger task...2015-12-07 09:09:44
doing cronTrigger task...2015-12-07 09:09:45
doing simpleTrigger task...2015-12-07 09:09:46
doing cronTrigger task...2015-12-07 09:09:48
doing simpleTrigger task...2015-12-07 09:09:48
doing simpleTrigger task...2015-12-07 09:09:50
doing cronTrigger task...2015-12-07 09:09:51
doing simpleTrigger task...2015-12-07 09:09:52
doing cronTrigger task...2015-12-07 09:09:54
doing simpleTrigger task...2015-12-07 09:09:54
doing simpleTrigger task...2015-12-07 09:09:56
doing cronTrigger task...2015-12-07 09:09:57
doing simpleTrigger task...2015-12-07 09:09:58
......

我们可以看到simpleTrigger和cronTrigger同时执行,而且cronTrigger是每隔3秒执行一次。
这证明我们的配置是成功的。大家可以按照上面给的配置规则来测试其他的配置,这里就不再一一测试了。

接下来我们就可以着手实现我们的需求
我们的需求是每月最后一天去自动处理尚未回复的速投请求,将没有回复的投诉设置为“已失效”。在后台管理中不能对该类型投诉进行回复。

时机:每个月月底最后一天;cronExpression:10 10 2 L * ?(凌晨2点10分10秒自动处理,为了避开工作高峰时间)
执行什么内容:对本月之前的待受理投诉进行自动处理;将投诉信息的状态改为 已失效
如何执行:
本月之前的待受理投诉:select * from Complain where 投诉时间 < 本月1号0时0分0秒


首先在我们的“投诉”模块的包下的spring配置文件中加入我们的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <!-- 继承了注入sessionFactory的抽象类,不用反复出入sessionFactory -->
    <bean id="complainDao" class="cn.edu.hpu.tax.complain.dao.impl.ComplainDaoImpl" parent="xDao"></bean>
    
    <!-- 扫描Service -->
    <context:component-scan base-package="cn.edu.hpu.tax.complain.service.impl"></context:component-scan>
    
    <!-- 1.指定任务详细信息 -->
    <bean id="complainJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	    <!--  ① 设置执行对象 -->
	    <property name="targetObject" ref="complainService"></property>
	    <!--  ② 设置执行对象中对应的执行方法 -->
	    <property name="targetMethod" value="autoDeal"></property>
	    <!--  ③ 是否可以同步执行(这里设置不同步执行) -->
	    <property name="concurrent" value="false"></property>
    </bean>
  
    <!-- 2.制定任务执行时机(任务执行触发器) -->
    <bean id="complainCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    	<!-- 设置任务详细 -->
    	<property name="jobDetail" ref="complainJobDetail"></property>
    	<!-- 设置任务执行时机,cron表达式 -->
    	<property name="cronExpression" value="10 10 2 L * ?"></property>
    </bean>
    
    <!-- 3.设置调度工厂 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    	<property name="triggers">
    		<list>
    			<!-- 触发器 -->
    			<ref bean="complainCronTrigger"/>
    		</list>
    	</property>
    </bean>
	
</beans>

然后我们可以看到,我们的任务执行类是complainService,其中任务执行方法是autoDetail方法,我们下面在complainService类中去编写autoDetail方法:
接口中定义此方法:
package cn.edu.hpu.tax.complain.service;

import cn.edu.hpu.tax.complain.entity.Complain;
import cn.edu.hpu.tax.core.service.BaseService;

public interface ComplainService extends BaseService<Complain> {

	//自动受理投诉
	public void autoDeal();
	
}


首先类中实现该方法:
package cn.edu.hpu.tax.complain.service.impl;

import java.util.Calendar;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cn.edu.hpu.tax.complain.dao.ComplainDao;
import cn.edu.hpu.tax.complain.entity.Complain;
import cn.edu.hpu.tax.complain.service.ComplainService;
import cn.edu.hpu.tax.core.service.impl.BaseServiceImpl;
import cn.edu.hpu.tax.core.util.QueryHelper;

@Service("complainService")
public class ComplainServiceImpl extends BaseServiceImpl<Complain> implements
		ComplainService {

	private ComplainDao complainDao;
	
	@Resource
	public void setComplainDao(ComplainDao complainDao) {
		super.setBaseDao(complainDao);
		this.complainDao = complainDao;
	}

	@Override
	public void autoDeal() {
		//1、查询本月之前的待受理的投诉列表
		QueryHelper queryHelper=new QueryHelper(Complain.class,"c");
		queryHelper.addCondition("c.state=?",Complain.COMPLAIN_STATE_UNDONE);
		
		Calendar cal=Calendar.getInstance();
		cal.set(Calendar.DAY_OF_MONTH, 1);//设置当前时间的日期为1号
		cal.set(Calendar.HOUR_OF_DAY, 0);//设置当前时间的日期为0时
		cal.set(Calendar.MINUTE, 0);//设置当前时间的日期为0分
		cal.set(Calendar.SECOND, 0);//设置当前时间的日期为0秒
		queryHelper.addCondition("c.compTime < ?", cal.getTime());
		
		List<Complain> list=findObjects(queryHelper);
		if(list != null && list.size()>0){
			//2、更新投诉信息的状态为已失效
			for(Complain comp:list){
				comp.setState(Complain.COMPLAIN_STATE_INVALID);
				update(comp);
			}
		}
	}
}

这样,我们每个月的月底的凌晨2点10分10秒就会自动执行complainService中的autoDeal方法,来设置本月之前的所有未回复的投诉信息为"无效的"。

然后“无效的”投诉是不能够回复的,我们在jsp中加上这个控制,使得所有无效的投诉的“回复”链接失效:
<td align="center">
     <s:if test="state != 2">
         <a href="javascript:doDeal('<s:property value='compId'/>')">受理</a>
     </s:if>
</td>
效果:


至此,我们的quartz与simpleTrigger、CronTrigger学习完毕,月底自动回复功能也已经实现。

转载请注明出处:http://blog.csdn.net/acmman/article/details/50205893

相关文章
|
3月前
|
Linux 网络安全
Linux命令(124)之ssh
Linux命令(124)之ssh
33 2
|
5月前
|
监控 数据可视化 安全
Linux——怎样使用SSH服务实现远程UI界面本地显示
需求场景 最近几天需要实现软件的远程监控,但是实际场景又不能使用向日葵、VNC、AnyDesk、以及其他的监视软件,并且软件的整体设计也没有这块的数据上行设计。
175 0
|
5月前
|
Linux 网络安全 开发工具
Linux之ssh
Linux之ssh
39 0
|
4月前
|
安全 网络协议 Linux
Linux ssh 命令详解
Linux ssh 命令详解
115 0
|
1月前
|
网络协议 Ubuntu Linux
「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接
「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接
107 0
|
1月前
|
安全 Linux Shell