前段时间在做一个远程控制系统的网站开发,系统要求能够设定定时开关机功能。在网页中设定时间后,服务器将数据存储进数据库,隔一段时间从数据库中读取设定时间值与当前时间进行比较来决定是否执行程序功能。
在查阅网络资料后找到一个方法来实现这个功能:实现ServletContextListener这个接口,当创建ServletContext时,激发contextInitialized方法,在contextInitialized方法中实现你的功能。
由于我的定时开关机功能开启成功与否标志放在服务器的全局变量,即application对象中。而此时spring还没有加载,无法注入。此时就用服务器提供的监听器来实现。
MyTimer类:
package com.hust.timer;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.hust.bean.Constant;
import com.hust.bean.PumpHost;
import com.hust.bean.PviState;
import com.hust.bean.SetInfo;
import com.hust.serial.CRC16;
import com.hust.serial.SerialBean;
import com.hust.service.PumpHostService;
import com.hust.service.PviStateService;
import com.hust.service.SetInfoService;
public class MyTimer implements ServletContextListener {
private Timer timer = null;
private String aa;
private PumpHostService phService;
private PviStateService psService;
private SetInfoService siService;
private PumpHost ph;
private PviState ps;
private SetInfo si;
//ServletContextEvent atest;
@Override
public void contextDestroyed(ServletContextEvent arg0) {
timer.cancel();
}
@Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext ac = WebApplicationContextUtils
.getWebApplicationContext(sce.getServletContext());
//设置在application中
//sce.getServletContext().setAttribute("flag", 5);
//通过spring注入,配置listener监听器在spring的后面,等spring先初试化完成
//SetInfoDao siDao = (SetInfoDao)ac.getBean("siDao");
siService = (SetInfoService)ac.getBean("siService");
phService = (PumpHostService)ac.getBean("phService");
psService = (PviStateService)ac.getBean("psService");
timer = new Timer();
//设置任务计划,启动和间隔时间
timer.schedule(new MyTask(), 200, 10);
//timer.schedule(new aaTask(), 200, 1000);
timer.schedule(new turnOn(sce.getServletContext()), 200, 60*1000);
timer.schedule(new turnOff(sce.getServletContext()), 200, 60*1000);
}
private class turnOn extends TimerTask{
//采用构造函数传递application对象,从而进行参数设置
private ServletContext servletContext;
public turnOn(ServletContext servletContext){
this.servletContext = servletContext;
}
public void run(){
aa = siService.getFirsSetInfo().getSetTimeOn();
System.out.println("从数据库中读出来的开启时间: "+aa);
String bb,cc;
if(aa.length()==4){
bb = aa.substring(0, 1);
cc = aa.substring(2, 4);
}else {
bb = aa.substring(0, 2);
cc = aa.substring(3, 5);
}
int h = Integer.parseInt(bb);
int m = Integer.parseInt(cc);
System.out.println("处理后格式:"+h+"时"+m+"分");
// System.out.println("时钟: "+ b);
// System.out.println("分钟: "+ c);
Calendar xx = Calendar.getInstance();
int hour = xx.get(Calendar.HOUR_OF_DAY);
int min = xx.get(Calendar.MINUTE);
int sec = xx.get(Calendar.SECOND);
System.out.println("系统时间:"+hour+"时"+min+"分"+sec+"秒");
if(h==hour && m==min){
//要执行的程序代码
System.out.println("执行一次");
//每次取最新一条记录,所以应在函数里面
// si = siService.getFirsSetInfo();
// ph = phService.getFirstPumpHost();
// ps = psService.getFirstPviSate();
//判断数据库中读出日期时间
//发送控制协议命令
//判断总线是否空闲
if(MyTask.safeCount>=10) {
/*这里完成向串口发送控制信号数据包*/
//组装字节数组
byte[] bts = new byte[6];
byte[] bts2 = new byte[8];
bts[0] = 0x01; //第1个字节表示从机地址,这里设为1
bts[1] = 0x10; //第2个字节表示功能码,
//总开关
bts[2] = (byte) 0xee; //第3个字节表示数据类型
bts[3] = 0x02; //第4个字节表示数据长度2
//打开总开关
bts[4] = 0x00; //填充
bts[5] = 0x01; //自动
int c = CRC16.crcTable(bts);
SerialBean serialBean = new SerialBean(1);
if (serialBean.Initialize()==1) {
//发送数据
for (int i = 0; i < 6; i++) {
bts2[i] = bts[i];
}
bts2[6] = (byte) (c%256); //第5个字节表示crc检验低位
bts2[7] = (byte) (c/256); //第6个字节表示crc检验高位
serialBean.WritePortBytes(bts2);
//计数器清零
MyTask.safeCount = 0;
}else {
System.out.println("串口打开失败,请尝试重新发送!") ;
//return "error";
//设置标志位flag,用来指示自动开启是否成功,放在application对象中,全局有效。
//servletContext.setAttribute("flag",(Integer)(-1));
servletContext.setAttribute("flagOn"," 定时开启失败");
}
System.out.println("成功发送!") ;
// servletContext.setAttribute("flag", (Integer)1);
servletContext.setAttribute("flagOn", " 定时开启成功");
System.out.println("****************************") ;
//return "success";
}else {
System.out.println("串口总线被占用,请尝试重新发送!!") ;
//servletContext.setAttribute("flag", (Integer)0);
servletContext.setAttribute("flagOn", " 总线占用,开启失败");
//return "error";
}
}
}
}
private class turnOff extends TimerTask{
//采用构造函数传递application对象,从而进行参数设置
private ServletContext servletContext;
public turnOff(ServletContext servletContext){
this.servletContext = servletContext;
}
public void run(){
aa = siService.getFirsSetInfo().getSetTimeOff();
System.out.println("从数据库中读出来关闭的时间: "+aa);
String bb,cc;
if(aa.length()==4){
bb = aa.substring(0, 1);
cc = aa.substring(2, 4);
}else {
bb = aa.substring(0, 2);
cc = aa.substring(3, 5);
}
int h = Integer.parseInt(bb);
int m = Integer.parseInt(cc);
System.out.println("处理后格式:"+h+"时"+m+"分");
// System.out.println("时钟: "+ b);
// System.out.println("分钟: "+ c);
Calendar xx = Calendar.getInstance();
int hour = xx.get(Calendar.HOUR_OF_DAY);
int min = xx.get(Calendar.MINUTE);
int sec = xx.get(Calendar.SECOND);
System.out.println("系统时间:"+hour+"时"+min+"分"+sec+"秒");
if(h==hour && m==min){
//要执行的程序代码
System.out.println("执行一次");
//每次取最新一条记录,所以应在函数里面
// si = siService.getFirsSetInfo();
// ph = phService.getFirstPumpHost();
// ps = psService.getFirstPviSate();
//判断数据库中读出日期时间
//发送控制协议命令
//判断总线是否空闲
if(MyTask.safeCount>=10) {
/*这里完成向串口发送控制信号数据包*/
//组装字节数组
byte[] bts = new byte[6];
byte[] bts2 = new byte[8];
bts[0] = 0x01; //第1个字节表示从机地址,这里设为1
bts[1] = 0x10; //第2个字节表示功能码,
//总开关
bts[2] = (byte) 0xee; //第3个字节表示数据类型
bts[3] = 0x02; //第4个字节表示数据长度2
//关闭总开关
bts[4] = 0x00; //填充
bts[5] = 0x00; //自动
int c = CRC16.crcTable(bts);
SerialBean serialBean = new SerialBean(1);
if (serialBean.Initialize()==1) {
//发送数据
for (int i = 0; i < 6; i++) {
bts2[i] = bts[i];
}
bts2[6] = (byte) (c%256); //第5个字节表示crc检验低位
bts2[7] = (byte) (c/256); //第6个字节表示crc检验高位
serialBean.WritePortBytes(bts2);
//计数器清零
MyTask.safeCount = 0;
}else {
System.out.println("串口打开失败,请尝试重新发送!") ;
//return "error";
//设置标志位flag,用来指示自动开启是否成功,放在application对象中,全局有效。
//servletContext.setAttribute("flag",(Integer)(-1));
servletContext.setAttribute("flagOff"," 定时关闭失败");
}
System.out.println("成功发送!") ;
// servletContext.setAttribute("flag", (Integer)1);
servletContext.setAttribute("flagOff", " 定时开启成功");
System.out.println("****************************") ;
//return "success";
}else {
System.out.println("串口总线被占用,请尝试重新发送!!") ;
//servletContext.setAttribute("flag", (Integer)0);
servletContext.setAttribute("flagOff", " 总线占用,开启失败");
//return "error";
}
}
}
}
}
MyTask类中是具体定时要实现的功能,turnOn和turnOff是定时开关程序功能。
web.xml文件中进行监听器配置:
<!-- 开机自启动的任务监听器配置 -->
<listener>
<listener-class>com.hust.timer.MyTimer</listener-class>
</listener>