天天看點

履歷群發器設計以及代碼實作JDK6HTTP+DOM4j

最近心裡非常郁悶打算換工作,但是發現一個問題,投了N多履歷,可是打電話面試的少之又少,為了能更有效的發送履歷,或者說降低我發送履歷的成本,我就開始着手寫履歷群發器,這個群發器的設計思路是,根據使用者(就是我)在資源檔案配置的想向哪個招聘網站檢索招聘資訊,然後針對不同的招聘網站,有不同的Sender,因為不同的網站裡面的網頁内容是不一樣,要使用不同的正規表達式進行比對,但是所有Sender必須實作ISender接口,這個接口裡面定義了檢索職位資訊,過濾不想投遞的公司,等等相關的方法,這個群發器的功能非常強大,現在我已經開發完成51Job網站的Sender,剩下的智聯招聘和中華英才網,會在近期陸續開發出來,從這個群發器的設計我深深體會到面向接口程式設計的好處.下面是整體的設計圖.

下面是檢索内容的接口

下面是資源檔案,看到資源檔案,你是不是覺得這個群發器功能會很強大呢?

如果覺得不強大我也沒辦法....呵呵

仔細解釋一下這個資源檔案的内容,首先是keyword關鍵字,群發器(下稱Sender)根據使用者填寫的關鍵字進行檢索,website是想要在哪個網站進行檢索(目前隻有51JobSender),再下面是城市可以包含多個城市,後面是exclud不包括,就是不想往這個公司投履歷(和我一樣,現任職的公司你肯定不想投),最後是email先關的資訊有一個有意思的地方,就是mailsubject這個是郵件的主題,可以寫成我上面寫的那樣,"JAVAEE四年應聘:XXX職位"後面的XXX職位是根據查詢結果自動擷取的.

這個Sender還要介紹兩個類一個是City類

由于各個網站對于檢索的資料是不一樣的,像51Job就是将每一個城市對應一個編碼(智聯招聘卻是直接将城市的名稱送出查詢),這個編碼使用者(我)是不知道的,使用者隻知道城市的名稱,那麼這個對照表就由我們的Sender進行維護吧.

還有一個類是Email類這個類用于封裝Email資訊

解釋一下這個類,這個類裡面的MAILHOSTNAME_MAPPING這個屬性,用于存儲各個郵箱的發送伺服器位址,因為我們要根據使用者的郵箱位址發送郵件,是以這個Mapping就由我們的Sender管理吧.^_^

下面是程式入口代碼

/*

 *太陽井軟體研發中心  版權所有 2009

 *Copyright(C) 2009 SunWell Software Develop Center. All rights reserved. 

 */

package com.sunwell.base;

import com.sunwell.base.core.SenderDispatch;

public class Main{

 public static void main(String[] args) throws Exception {

  SenderDispatch sender = new SenderDispatch();

  sender.run();

 }

}

我們的SenderDispatch

package com.sunwell.base.core;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.net.MalformedURLException;

import org.apache.commons.io.FileUtils;

import org.apache.commons.io.IOUtils;

import org.apache.log4j.Logger;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.DocumentHelper;

import com.sunwell.base.util.HttpConnection;

public class SenderDispatch {

 protected final Logger logger = Logger.getLogger(SenderDispatch.class);

 private Document document;

 private ISender sender;

 public static final HttpConnection HTTP = new HttpConnection();

 static {

  HTTP.setConnectTimeout(50000);

  HTTP.setReadTimeout(50000);

 /**

  * 

  * @throws FileNotFoundException

  * @throws IOException

  * @throws DocumentException

  */

 public SenderDispatch() throws FileNotFoundException, IOException, DocumentException{

  File configFile = new File(getClass().getClassLoader().getResource("").getPath()+"sysconfig.xml");

  String xml = IOUtils.toString(FileUtils.openInputStream(configFile));

  document = DocumentHelper.parseText(xml);

  * <pre>

  * 建立人: 王濤

  * 建立于: 2009-6-23

  * 描 述:

  *    根據使用者填寫的網址(通過逗号分隔),執行個體化url對象

  * </pre>

  * @throws DocumentException 

  * @throws IOException 

  * @throws FileNotFoundException 

 private void buildWebSite(String webSite) throws FileNotFoundException, IOException, DocumentException{

  for(String ws : webSite.split(",")){

   if("51job".equals(ws) || "51JOB".equals(ws)){

    sender = new Job51Senderimpl();

   }

   else if("智聯招聘".equals(ws) || "智聯".equals(ws) || "zhaopin".equals(ws)){

  }

  * 建立于: 2009-6-24

  *    功能入口

  * @throws Exception

 public void run() throws Exception{

  try {

   this.buildWebSite(document.selectSingleNode("ROOT/website").getText());

  } catch (MalformedURLException e) {

   e.printStackTrace();

   logger.error("建構網站位址時發生錯誤,原因[可能是資源檔案中網站位址填寫錯誤]");

裡面的代碼已經寫得很明白了,大家如果還是看不太明白,可以拷貝到Eclipse中使用Eclipse的高亮顯示,進行檢視,可能會有很大的幫助.

import java.net.URLEncoder;

import java.util.List;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

import org.dom4j.Element;

import com.sunwell.base.mail.Email;

import com.sunwell.base.mail.MailSender;

import com.sunwell.base.util.City;

public class Job51Senderimpl implements ISender{

 protected final Logger logger = Logger.getLogger(Job51Senderimpl.class);

 public Job51Senderimpl() throws IOException, DocumentException{

  * 建立于: 2009-6-26

  *    根據關鍵字和所在城市,進行職位查詢

  * @param url

 @SuppressWarnings({"unchecked"})

 public void searchResultByKeyWord(String url){

  List<Element> citys = document.selectNodes("ROOT/city/value");

  this.logger.debug(((Element)citys.get(0)).getText());

  String jobarea = "";

  for(Element e : citys){

   jobarea += City.CITY_LIST_51JOB.get(e.getText()) + ",";

  String html = null;

   html = getHTMLByUrl(url+"?fromJs=1" +

            "&jobarea="+URLEncoder.encode(jobarea.substring(0, jobarea.length()-1), "UTF-8")+"" +

            "&funtype=0000&industrytype=00" +

            "&keyword="+URLEncoder.encode(document.selectSingleNode("//ROOT/keyword").getText(),"UTF-8")+

            "&keywordtype=2&lang=c&stype=1&postchannel=0000&fromType=1");

   //this.logger.debug(html);

   this.getJobCorpInfoByHTML(html);

  }catch (FileNotFoundException e) {

   logger.error("送出查詢條件時發生錯誤,原因[可能是網站查詢位址改變或錯誤]");

  }catch (Exception e) {

  *    核心方法,首先擷取公司名稱和職位連結,并對于資源檔案中的不包括的公司名稱進行過濾,在獲得郵箱位址之後,向郵箱位址發送郵件.

  *    執行完本頁的職位清單之後,擷取下一頁連結如果有下一頁連結,将遞歸調用此方法.

  * @param html

 @SuppressWarnings("unchecked")

 public void getJobCorpInfoByHTML(String html) throws Exception{

  String theHtml = html;

  Matcher matcherJobURL = Pattern.compile("<a href=\"(.+?)\" onclick=\"zzSearch.acStatRecJob").matcher(theHtml);

  Matcher matcherCorpName = Pattern.compile("<a href=\".+?\" class=coname target=\"_blank\" >(.+?)</a></td>").matcher(theHtml);

  while(matcherJobURL.find() && matcherCorpName.find()){

   for(Element exclud : (List<Element>)document.selectNodes("ROOT/exclud/value")){

    if(matcherCorpName.group(1).indexOf(exclud.getText()) == -1){

     //logger.info("準備打開職位詳細頁面 : " + matcherJobURL.group(1));

     try {

      //打開職位詳細頁面

      Email email = buildEmailDetailByHTML(getHTMLByUrl(matcherJobURL.group(1)));//擷取郵箱資訊

      if(email != null){

       MailSender.sendHTML(email);//發送郵件

       logger.error("發送郵件: "+email.getSendTo());

      }

     } catch (Exception e) {

      logger.error("打開職位詳細頁面時發生錯誤");

      e.printStackTrace();

     }

    }else{logger.info("過濾掉公司名稱為" + exclud.getText() + "的公司");}

  String nextUrl = getNextUrlsByHtml(theHtml);

  if(nextUrl != null){

   this.getJobCorpInfoByHTML(SenderDispatch.HTTP.doGet(nextUrl).toString("GB2312"));

  *    根據html中的内容找到包含的Email位址

  * @return

 public Email buildEmailDetailByHTML(String html){

  //logger.info("擷取職位名稱和郵箱位址資訊");

  Email emailDetail = null;

  Matcher jobName = Pattern.compile("<td class=\"sr_bt\" colspan=\"2\">(.+?)</td>").matcher(html);

  if(jobName.find() && mailAddress.find()){

   emailDetail = new Email(document.selectSingleNode("ROOT/emaildetail/emailusername").getText(),

         document.selectSingleNode("ROOT/emaildetail/emailpassword").getText());

   emailDetail.setSendTo(mailAddress.group(1));

   emailDetail.setSubject(document.selectSingleNode("ROOT/emaildetail/mailsubject").getText() + " : " + jobName.group(1));

  return emailDetail;

  *    獲得下一頁的連接配接

  * @return 如果沒有比對到下一頁的連接配接,傳回null

 public String getNextUrlsByHtml(String html){

  //logger.debug(html);

  String url = "";

  Matcher matcher = Pattern.compile("</td><td><a href=\"(.+?)\"  .+?").matcher(html);

  if(!matcher.find()) //需要先find才能取

   return null;

  else{

   url = matcher.group(1);

  logger.debug("下一頁連結 : " + url);

  return url;

  *    擷取網站内容

 public String getHTMLByUrl(String url){

   html = SenderDispatch.HTTP.doGet(url.toString()).toString("GB2312");

   //logger.debug(html);

  } 

  catch (IOException e) {

   logger.error("建立連接配接時發生錯誤,原因[可能是網絡連接配接錯誤或對方伺服器無法通路]");

  } catch (Exception e) {

   logger.error("試圖連接配接時發生錯誤,原因[可能是網絡位址填寫錯誤]");

  return html;

下面是MailSender代碼

package com.sunwell.base.mail;

import org.apache.commons.mail.HtmlEmail;

public class MailSender {

 public static void sendHTML(Email email) {

   HtmlEmail semail = new HtmlEmail();

   semail.setHostName(email.getHostName());

   semail.addTo(email.getSendTo());

   semail.setAuthentication(email.getEmailUserName(), email.getEmailPassword());

   semail.setFrom(email.getEmailUserName(), email.getEmailUserName());

   semail.setSubject(email.getSubject());

   //下面這句話是插入我自己的一個Logo

   String ad = "<center><a href='http://tonyaction.blog.51cto.com/'><img src='"+imgSrc+"'></a></center>";

   semail.buildMimeMessage();

   semail.setCharset("UTF-8");

   semail.setHtmlMsg(ad + email.getContent());

   semail.send();

  } catch (Exception ex) {

   System.out.println("郵件發送失敗:" + ex.getMessage());

   ex.printStackTrace();

發送成功後的樣子

本文轉自 tony_action 51CTO部落格,原文連結:http://blog.51cto.com/tonyaction/170755,如需轉載請自行聯系原作者

繼續閱讀