本文最初是为了实现定时推送功能,为推送设置一个时间,到时间后推送到云巴服务器。
所以这里会用到quartz定时任务调度,而且我新增一个定时推送,同时就要新增一个定时任务。所以这里也涉及到了任务的增删改查。
以下是代码实现:
1、定时任务管理类,实现对任务的CURD
package com.qbyy.util.yunba.task;
import java.util.Date;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
* 定时任务管理类
*
* @author FJB
* 2015年6月1日 下午3:04:10
*/
@SuppressWarnings("rawtypes")
@Component("pushQuartzManager")
public class PushQuartzManager {
@Autowired
<span style="white-space:pre"> </span>private SchedulerFactoryBean gSchedulerFactory;
private String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME"; //任务组名
private String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME"; //触发器名
@Autowired
public void setgSchedulerFactory(SchedulerFactoryBean gSchedulerFactory) {
this.gSchedulerFactory = gSchedulerFactory;
}
/**
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @param jobName 任务名
* @param cls 任务
* @param time 时间设置【我这里用的是java.util.Date,这样可以直接查询出数据库的日期,并设置为定时任务的开始时间】
*/
public void addJob(String jobName, Class cls, Date startTime) {
try {
System.out.println("新增定时任务"+jobName);
//Scheduler sched = schedulerFactoryBean.getScheduler();
Scheduler sched = gSchedulerFactory.getScheduler();
JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, cls);// 任务名,任务组,任务执行类
//jobDetail.getJobDataMap().put("targetObjectId", jobName);
// 触发器
SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, TRIGGER_GROUP_NAME);
simpleTrigger.setStartTime(startTime);
simpleTrigger.setRepeatCount(0);<span style="white-space:pre"> </span>//重复次数为0,不重复
sched.scheduleJob(jobDetail, simpleTrigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改定时任务
* @param jobName 任务名
* @param time 时间
*/
public void modifyJobTime(String jobName, Date time) {
try {
//Scheduler sched = schedulerFactoryBean.getScheduler();
Scheduler sched = gSchedulerFactory.getScheduler();
SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(jobName,TRIGGER_GROUP_NAME);
if (trigger == null) {
return;
}
Date oldTime = trigger.getStartTime();
if (!oldTime.equals(time)) {
System.out.println("时间不相等,修改时间");
JobDetail jobDetail = sched.getJobDetail(jobName,JOB_GROUP_NAME);
Class objJobClass = jobDetail.getJobClass();
removeJob(jobName);
addJob(jobName, objJobClass, time);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个定时任务
* @param jobName
*/
public void removeJob(String jobName) {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseTrigger(jobName, TRIGGER_GROUP_NAME);// 停止触发器
sched.unscheduleJob(jobName, TRIGGER_GROUP_NAME);// 移除触发器
sched.deleteJob(jobName, JOB_GROUP_NAME);// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package com.qbyy.util.yunba.task;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.wunding.service.system.PushSendServiceI;
/**
* 定时任务执行类
*
* @author FJB
* 2015年6月1日 上午11:29:31
*/
public class PushQuartzJob extends QuartzJobBean {
Logger logger = Logger.getLogger(PushQuartzJob.class);
//【关键】推送的业务类,不能直接通过spring注解注入,必须在xml文件中配置
private PushSendServiceI pushSendService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
String id="";
try {
//获取JobExecutionContext中的service对象
SchedulerContext skedCtx = context.getScheduler().getContext();
//获取SchedulerContext中的service
//这里的service就是通过配置文件 配置的
pushSendService = (PushSendServiceI)skedCtx.get("pushSendService");
id = context.getJobDetail().getName();
pushSendService.sendPush(id);
System.out.println("ID= ["+id+"] 的推送,定时发送成功");
logger.info("ID= ["+id+"] 的推送,定时发送成功");
} catch (Exception e) {
logger.info("ID= ["+id+"] 的推送,定时发送失败");
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- quartz的调度工厂 -->
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="schedulerContextAsMap">
<map>
<!-- 【关键】spring 管理的service需要放到这里,才能够注入成功<span style="font-family: Arial, Helvetica, sans-serif;">PushQuartzJob 要使用到的业务类要在这里注入才能使用</span> -->
<description>schedulerContextAsMap</description>
<entry key="pushSendService" value-ref="pushSendServiceImpl" />
</map>
</property>
</bean>
</beans>
4、业务逻辑类
@Service
@Transactional
public class PushManageServiceImpl extends BaseService implements PushManageServiceI {
@Autowired
private PushManageMapper pushManageMapper;
@Autowired
private PushQuartzManager pushQuartzManager;
@Override
public void savePush(PushManage pushManage) throws Exception {
String pushId = newId();
pushManage.setId(pushId);
//新增定时任务,这里直接将推送消息对象的ID作为jobName,这样做的好处是,在任务执行时可以直接根据jobName到数据库中查询推送信息
pushQuartzManager.addJob(pushId, PushQuartzJob.class, pushManage.getTaskpushtime());
pushManageMapper.save(pushManage);
}
}
5、每2步中,任务执行所调用的方法所在类,任务推送类
package com.wunding.service.system.impl;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.wunding.domain.system.PushManage;
import com.wunding.persistence.system.PushManageMapper;
import com.wunding.service.system.PushSendServiceI;
import com.wunding.util.yunba.YunBaPushUtil;
/**
* 推送定时发送管理类
*
* @author FJB
* 2015年6月2日 下午3:10:12
*/
@Service
@Transactional
public class PushSendServiceImpl implements PushSendServiceI {
@Autowired
private PushManageMapper pushManageMapper;
@Autowired
private YunBaPushUtil yunBaPushUtil;
@Override
public void sendPush(String id) throws Exception {
PushManage pushManage = new PushManage();
pushManage.setId(id);
Date nowDate = new Date();
pushManage.setPushtime(nowDate);
pushManage.setIsavailable(1);
pushManageMapper.update(pushManage);
PushManage push = pushManageMapper.get(id);
yunBaPublish(push);
}
/**
* 发推送到服务器
* @param push
*/
private void yunBaPublish(PushManage push){
//调研发送推送的方法
/**
* ----要推送的内容----
* 1.推送内容[msg]
* 2.内容id [contentId]
* 3.内容类型,资讯、考试等 [contentType]
* 4.推送目标人员或部门 [topic or alias]
* 5.按别名或频道推送 [pushType]
*/
try {
String pushStr = "{'topic': 'topic1', 'msg': '"+push.getMessages()+"', 'qos': 1}";
JSONObject json = new JSONObject(pushStr);
yunBaPushUtil.getSocket().emit("publish", json);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
要注意的地方:第2步中注入的service类与第4步中的业务逻辑类不能是同一个类,这也是我单独提取出第5步中的类的原因,因为如果是同一个类,会存在相互注入,也就是循环注入,会报类似如下的错误:
This means that said other beans do not use the final version of the bean. This is often the
result of S type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off,
for example.
6、特别声明:在编码过程中参考网上多个地方的代码,在这里我也提供参考的链接地址:
(1)http://blog.youkuaiyun.com/whaosy/article/details/6298686 这里参考了在Job中注入service的方法
(2)http://blog.youkuaiyun.com/pengpegv5yaya/article/details/37595889 这里参考了对定时任务的CURD
(3)http://www.ibm.com/developerworks/cn/java/j-quartz/#ibm-pcon 这里参考了SimpleTrigger