最近作了一個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的兄弟,但願能讓你少走一些彎路。