近期由于项目需要,需要用到一个功能:在写好的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中不可以使用 >,<符号,特此记录:

< <   
> >   
& &   
' '   
" "