最近作了一个java的项目,部门领导给了一套代码让我尽快掌握,说内心话本人真心不喜欢java的这种项目方式,各类配置各类xml文件简直头都大了,下面就将我遇到的其中一个我认为是坑的地方整理出来,但愿能帮助到后面像我同样的兄弟php
功能需求说明:html
使用Jsoup编写了一套爬虫程序,用来自动录入网站的数据,以前测试都是写在页面中,手动的访问页面触发爬虫(后续一些问题就是由于这样产生的),还有就是项目须要实现自动触发也就是定时器java
开发过程:python
既然肯定是定时器,操刀子就上直接百度java定时器,发现不少quartz、spring、spring-task、Timer ,发现Timer 这东西应该是最简单粗暴的,因而在网上找到下面代码程序员
package tasklListener; import java.util.TimerTask; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import paypay.web.service.timers.ChannelDataSync; /** * 上下文监听器,须要在web.xml中进行配置,请参见<listener></listener>结点 * * @author Administrator * */ public class MyContextListener implements ServletContextListener { private java.util.Timer timer = null; private ServletContext context = null; public void contextInitialized(ServletContextEvent event) { this.context = event.getServletContext(); timer = new java.util.Timer(true); event.getServletContext().log("定时器已启动"); // 设定MyTask中任务每5秒执行一次,0表示立刻执行,能够改成2000,则表示2秒之后开始执行 // 之后都按后面指定的每5秒执行一次 timer.schedule(new MyTask(this.context), 60000, 60 * 60 * 2000); event.getServletContext().log("已经添加任务调度表"); } public void contextDestroyed(ServletContextEvent event) { timer.cancel(); this.context.log("定时器销毁"); this.context = null; } private static class MyTask extends TimerTask { private static boolean isRunning = false; private ServletContext context = null; public MyTask(ServletContext context) { this.context = context; } // 下面的方法会按以前设定的每5秒执行一次,因此,此处不须要循环 public void run() { if (!isRunning) { isRunning = true; context.log("开始执行指定任务"); // TODO 添加自定义的详细任务,如下只是示例 // 这里完成从数据库取数据,而后存放到MySQL数据库中 ChannelDataSync Dateuser=new ChannelDataSync(); java.text.DateFormat df = new java.text.SimpleDateFormat("yyyyMMdd") ; java.util.Date date = new java.util.Date() ; String datestr = df.format(new java.util.Date()); Dateuser.selectTSuserdata(datestr); isRunning = false; context.log("指定任务执行结束"); } else { context.log("上一次任务执行还未结束"); } } } }
建好了类,不对啊怎么触发啊仔细看了一下注释web
/** * 上下文监听器,须要在web.xml中进行配置,请参见<listener></listener>结点 * * @author Administrator * */
因而到web.xml中找到
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
那我就直接复制listener-class节点,而后写入本身的包名+类名spring
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> <listener-class> com.shopping.zy.MyContextListener </listener-class> </listener>
编译后报错(大神别鄙视我,我是真的java新手,对于配置什么xm文件彻底不会啊 )数据库
看了一下报错信息:cvc-complex-type.2.4.d: Invalid content was found starting with element 'listener-class'. No child element is expected at this point.设计模式
本人的英文很烂,但也大概看出来讲是子元素有问题,既然是子元素不对,那就从新写一个对象不就好了 ,因而配置文件改为:app
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> com.shopping.zy.MyContextListener </listener-class> </listener>
测试经过!
再接下来就是在MyContextListener类中作操做了 首先是在定时器的初始化方法contextInitialized中:
timer = new java.util.Timer(true); event.getServletContext().log("定时器已启动"); //1000*60*60 1秒 *60=1分钟 *2 等于开启后60分钟执行采集任务 //(1000*60*60)*12 (1000*60*60)=1个小时 *12表示没12小时执行一次 int tempint=(1000*60*60)*(Integer.parseInt(sysconfig.getAotoupdate_step())); timer.schedule(new MyTask(this.context), 1000*60*60,(1000*60*60)*(Integer.parseInt(sysconfig.getAotoupdate_step())));
具体的能够参看代码,schedule函数的参数是分别是,要调用的函数,延迟执行时间,执行间隔时间 我提供的代码中最后的的执行间隔时间是动态在数据库中取出的因此是动态的,你也能够直接写成固定的
到这了大家确定以为没什么坑啊,那么我就先来介绍一下第一个坑:
首先在MyContextListener是不能够直接使用srping的对象的,即便你声明了对应的对象,但因为MyContextListener的启动线程和spring不一致(我本身理解的,若是谁知道能够给我解释一下),在MyContextListener类中使用spring对象是不会有实例化相关的注入对象的,这就坑爹了,总不能本身把全部的数据库操做类从新作一遍吧,因而乎又是神器出山,继续百度,找了半天发现一个帖子中的解决办法:
ISysConfigService sysConfigService; WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext()); sysConfigService = (ISysConfigService) context.getBean("sysConfigService"); SysConfig sysconfig= sysConfigService.getSysConfig();
这里里面有一点是须要注意的:context.getBean("sysConfigService")中的sysConfigService为实体类是我项目中的操做类,可是经过context.getBean()方法返回的对象类型必须是其对应的ISysConfigService接口,而不是其对象类型,
虽然不知道是为何但我以为这确定跟spring的设计模式有关系,这是否是就是工厂类的设计模式啊,在此处坑了我好久也是今天我想写这篇博文的一个诱因吧。这样获得的对象是包括其自己的注入对象的。
接下来就是要实现调用我写好的爬虫函数了 ,这简单啊 ,直接实例化类对象 而后调用方法就好了 ,因为类对象中没有注入对象不须要使用上面的方法,说干就干
ManageHT mht=new ManageHT(); mht.zy_sr_cj(context);
mht.cj_start(context); mht.zy_collect_news();
三个方法分别是我对应的三个采集的函数,以前接收的是HttpServletRequest ,可是在MyContextListener中我不知道如何获取,因而我就讲context传入了,若是你知道怎么获取能够给我留言,这不是重点由于后续我使用了其余的办法,
使用上面的方式访问对应的函数会遇到和以前同样的问题,对应的注入对象没法加载,弄了半天最后决定坚持个人简单粗暴的原则,既然直接网页访问能够, MyContextListener不能够,那我就模拟一个网页请求不就好了 还研究什么注入不注入对象的
说干就干:
public static String doGet(String url, String queryString, String charset, boolean pretty) { StringBuffer response = new StringBuffer(); HttpClient client = new HttpClient(); HttpMethod method = new GetMethod(url); try { if (StringUtils.isNotBlank(queryString)) //对get请求参数作了http请求默认编码,好像没有任何问题,汉字编码后,就成为%式样的字符串 method.setQueryString(URIUtil.encodeQuery(queryString)); client.executeMethod(method); if (method.getStatusCode() == HttpStatus.SC_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(), charset)); String line; while ((line = reader.readLine()) != null) { if (pretty) response.append(line).append(System.getProperty("line.separator")); else response.append(line); } reader.close(); } } catch (URIException e) { } catch (IOException e) { } finally { method.releaseConnection(); } return response.toString(); }
模拟get请求的操做,对于个人需求来讲get/post没什么区别,直接百度一段代码,
最后的调用部分代码变成:
String sr = doGet("http://localhost:8080/shopping/admin/testsr.htm", null, "UTF-8", true); Thread thread = Thread.currentThread(); thread.sleep(1000*60*10);//暂停10分钟后程序继续执行 String mr = doGet("http://localhost:8080/shopping/admin/zy_collect_mr.htm", null, "UTF-8", true); Thread threadsecond = Thread.currentThread(); threadsecond.sleep(1000*60*10);//暂停10分钟后程序继续执行 String news = doGet("http://localhost:8080/shopping/admin/zy_collect_news.htm", null, "UTF-8", true);
运行项目:执行定时器-执行任务-调用个人爬虫页面,看着数据一条一条进入到数据库中,今天的努力没白费,做为一个新手java程序员我想两说,虽然我对java了解不深,可是java的一些机制确实致使了项目开发进度的缓慢(就是大牛你也得认可,java开发效率就是比.net、python、php)等慢多了 ,这只是我接触java项目之后遇到的比较简单的,以前焦头烂额的也没记录下来,但愿之后能把我遇到的问题总结出来,若是再有.net转java的兄弟,但愿能让你少走一些弯路。