近期由于项目需要,需要用到一个功能:在写好的web中每隔一段时间运行一段代码,检查数据状态,并及时修复数据。
刚拿到这个需求的时候并不是很懂怎么做。查询了很多资料,但是都有一定的问题。今天来Debug一下,并给出自己的解答。
功能一共分几步:
1、一个计时器,每隔一段时间运行一段代码
2、自动运行
3、检查数据库中的时间,并比较
**首先来说一下计时器的问题。**这个很简单。
//Timer TimerTask
Timer timer = new Timer();
Integer cache = 1000*3;
timer.schedule(new TimerTask() {
@Override
public void run() {
logger.info("************" + now + "*********");
}
},1000,cache);
具体的使用方法,可以查看api
java 1.8 中文API
其次,自动运行的问题。在java web里面自动运行的方法很多。先举个例子,大家能在网上都可以搜到但是可能不是很好用的:
1、添加Listener
先在xml里面配置监听器:
<listener>
<listener-class>com.test.init.InitListener</listener-class>
</listener>
编写代码
public class InitListener implements ServletContextListener {
//必不可少的
@Override
public void contextDestroyed(ServletContextEvent context) {
}
//同样必不可少
@Override
public void contextInitialized(ServletContextEvent context) {
// 上下文初始化执行
System.out.println("自动加载启动开始.");
}
}
2、添加一个servlet
配置web.xml中配置servlet
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.test.init.InitServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>test</param-value>
</init-param>
<!-- 此处指定加载顺序为2,表明还有优先级更高的Servlet要先执行 -->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>InitServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
编写代码
public class InitServlet extends HttpServlet {
@Override
public void init(ServletConfig config) {
try {
super.init();
} catch (ServletException e) {
e.printStackTrace();
}
System.out.println("自动加载启动开始.");
//实现功能
System.out.println("自动加载启动结束.");
}
}
以上这两种方法我尝试过以后,我觉得都不是最简单而且最好用的办法。特别是对新手来说,很容易出错(配置文件)。我用了一下两种方法。
1、直接添加bean
在web.xml中
<bean id="RepairOperationResultController" class="com.foundation.helloworld.controller.RepairOperationResultController" init-method="TimeStamp"></bean>
编写代码
public class RepairOperationResultController{
public void TimeStamp(){
//功能处
}
}
简单粗暴
2、ApplicationListener
这是我最后采用的方式
public class RepairOperationResultController implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent ev) {
//防止重复执行
if (ev.getApplicationContext().getParent() == null){
//要实现的功能
}
}
}
如果不加if的判断,会存在一个问题,在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)。
这种情况下,就会造成onApplicationEvent方法被执行两次。为了避免上面提到的问题,可以只在root application context初始化完成后调用逻辑代码,其他的容器的初始化完成,则不做任何处理,修改后代码。
总结:这里讲的四种方法,实际上都可以使用,但是要看自己的环境,如果是一个新手不善于配置那么多的文件,还是建议用我采用的后两种方式。
最后,就是检查数据库中的时间,并比较这个问题
目前的两种方式:Date和Calendar
看一下的代码:
long now = System.currentTimeMillis();
Date afterDate = new Date(now);
System.out.println(now);
System.out.println(afterDate);
String str="2011-04-14 13:02:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
long millionSeconds = sdf.parse(str).getTime();
System.out.println(millionSeconds);
Date now1 = new Date();
System.out.println(now1.getTime());
System.out.println("****************");
Calendar calendar = Calendar.getInstance();
System.out.println("当前时间:" + sdf.format(calendar.getTime()));
calendar.add(Calendar.SECOND,3);
System.out.print("增加三秒后的时间:" + sdf.format(calendar.getTime()));
以下是结果:
1496824800166
Wed Jun 07 16:40:00 CST 2017
1294981320000
1496824800212
****************
当前时间:2017-40-07 04:40:00
增加三秒后的时间:2017-40-07 04:40:03
在获取时间方面,可以使用Date,感觉比较方便。但是涉及到时间的变化,加减方面,使用Calendar比较方便。其中的转换如下:
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String datetime = sdf.format(Long.parseLong("1323842302")*1000);
datetime = sdf.format(1325433638000L); //毫秒转为字符串
System.out.println(datetime);
b();
}
public static void b() {
DateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
try {
Date myDate = format.parse("2012/01/02 00:00:38");
System.out.println(myDate.toString());
System.out.println(myDate.getTime()); //标准字符串转为毫秒(格林时间)
} catch (ParseException e1) {
e1.printStackTrace();
}
}
此外,检查数据库过程中,由于需要使用Date类型比较大小,但是mapper中不可以使用 >,<符号,特此记录:
< <
> >
& &
' '
" "