58招聘APP詳情頁系統架構
58APP招聘詳情頁是listing列表頁職位的落地頁 。詳情頁包含職位基本信息、工作地址、職位描述、公司信息、附近職位、推薦等模塊。本文主要講為 native提供數展示協議的服務端站點整體結構,以及如何使用velocity自定義標簽管理app端多版本模版。
1.項目總體架構
58的web站點通常使用wf框架進行搭建,整個站點結構如下所示
下圖是web端框架,后面我們將對web站點流程進行介紹
2.web端流程概述
2.1初始化過程
整個站點的初始化流程圖如下所示,下面將做主要流程介紹:
1)APIInfodetailController初始化
APIInfodetailController作為整個詳情頁入口的控制器,在服務器啟動時,會在其構造器中初始化相關配置類,讀取wf文件中相關的配置文件。其中初始化定位各業務處理類(service層)的apiconfig.xml配置文件是關鍵點,apiconfig.xml配置文件內容如下:
之后站點會調用Configuration類的getInstance()方法獲取到保存的appManagerClassMap的map時,會遍歷此map集合,并將對應的key和value的值保存到appManagerMap中。隨后,實例化一個IURLHandlerService的實例。最后,調用ResultConfig的init()方法,讀取resultconfig文件下的job.xml配置文件(配置各類別模版路徑),配置文件如下:
2)InitController
InitController控制器實現了Spirng框架的ServletContextAware類,所以會在服務器啟動的時候去調用setServletContext,在此方法中調用ScnnerTemplates的scan方法,掃描所有的模版,并將模版的文件路徑存放在map集合中。
3 業務邏輯層
這一節將主要介紹本系統的業務邏輯層所涉及的業務邏輯、自定義異常、日志寫入、以及如何去調用服務。
3.1 主要業務邏輯
詳情頁的主要業務邏輯是根據帖子的一級類別,傳入不同的參數查詢獲取一個詳情頁的實體結果,然后去構建詳情頁顯示的各個模塊:如帖子基本信息、工作地址、職位描述、公司信息等,之后利用velocity渲染協議,返回如安卓的xml格式協議,和ios的json格式協議,當然不同app版本的協議也是不同的
3.2自定義異常
在java中所有異常的跟類為Throwable,在本系統中,為了一些特殊的處理,自定義了許多異常,下圖系統匯總要到的自定義異常類圖:
從類圖中可以觀察到,自定義的異常類的根類皆屬于運行時異常(RuntimeException)。為保證系統不被異常中斷,都會在業務邏輯中進行catch處理。
3.3 日志管理
本系統日志分為一般日志信息和ROI日志信息。普通日志的級別分為info級別、error級別、debug級別、warn級別。
除了使用WF自帶的日志類 LogFactory,并自定義了BllLog類,便于操作日志。BllLog類如下所示:
3.4 枚舉
枚舉是一種規范,規范了參數的形式,這樣就可以不用考慮類型的不匹配并且顯式的替代了int型參數可能帶來的模糊概念 枚舉像一個類,又像一個數組。本系統多處使用了枚舉類,使代碼閱讀性更好,這里就不再贅述了。
4 視圖層
視圖層主要是負責提供不同格式的協議,由于app的特性,會有版本的升級,每次版本的升級,幾乎都涉及到視圖層頁面的增加或者修改。就無疑就給頁面路由帶來了一定的難度,為解決路由這一問題,采用了自定義了velocity標簽-- rewparse來實現。
4.1 設計方案原因
由于App端的發版現狀需要兼容各個版本,每一版本的代碼都要保留,所以為了讓每個版本都能正常運行,在代碼中和模板上做了很多的版本控制。目前app每月發版一次,如果每次發版都有代碼層面的變動,我們的代碼就會十分混亂,難以維護。為了讓代碼看起來更清晰,更干凈,管理不同的版本代碼更容易,我們設計了這套模板版本控制方案。
4.2 系統模板說明
Web端通過velocity渲染,并區分ios(json)和android(xml)兩套協議模版。前端以主模板+碎片的方式存在,按照幾個大的功能劃分,將大部分功能分在了碎片中。模板之間通過parse標簽引入。
改版前目錄結構如下:
4.3 優化方案
Velocity提供了自定義標簽的功能,所以本次優化從源頭重寫parse標簽開始。既然是動態選擇模板,那我們就需要知道當前系統運行中有幾個模板,每個模板分別支持哪個版本,所以我們需要規范模板的目錄,命名。這樣當一個請求到來時,我們可以根據版本號去選擇正確的模板。
1、自定義新標簽,取名為rewparse,實現功能包括原parse標簽的功能,加入根據版本號動態選擇不同版本模板的功能。
2、規范模板設計,按照一定規范創建新的版本,同一碎片不同版本之間按照規范存儲。
3、規范版本號,同一碎片不同版本之間通過規范的版本號做區分 。
4.4 具體設計方案
1、目前android使用3位版本號,ios使用4位版本號,后續native可能會統一為4位,并且每位取值范圍在0-99之間。所以,版本號規范為8位,接收到的版本號不足4位的末位補0,每位不足2位數的前邊補0,如:6.4.5會被轉化為06040500
2、按照版本號建立文件夾,版本迭代中比原來版本改動較大的碎片選擇新創建一個同名碎片,并將同名碎片放在與舊版本同級目錄的以當前版本號為名的文件夾下。如:
上圖中,nearjob.vm碎片中包含的功能是附近職位模塊,這個模塊在7.2.0版本時做了一次優化。所以將7.2.0版本的nearjob.vm放在07020000文件夾下,表示兩個nearjob.vm是有實現同一功能不同版本的關系。
1、Rewparse標簽依賴需要知道當前工程中有哪些版本的碎片,每個碎片有幾個版本。所以我們需要去掃描模板所在目錄。因為在系統運行中模板是不會變動的,所以我們不必每次請求時都去做一次掃描,只需要在工程啟動時做一個掃描模板的初始化,將結果保存在內存中即可。每個非數字構成的文件夾下的同名碎片為實現相同功能的不同版本的碎片。如:
templates/json/job/fragment/nearjob.vm
templates/json/job/fragment/07020000/nearjob.vm
按照此種格式存儲的碎片我們會認為是實現同一功能的不同版本的碎片。
上述碎片會按照(templates/json/job/fragment/nearjob.vm,[t emplates/json/job/fragment/nearjob.vm,templates/json/job/fragment/07020000/nearjob.vm])
這種key、value格式存儲,rewparse標簽會根據傳入的templates/json/job/fragment/nearjob.vm模版碎片名和當前版本號去value中尋找小于等于當前請求版本號的模版碎片(未做版本區分時,默認使用通用碎片)。
備注:目前系統中模板數量較少,后期當模板數量變多之后,可以考慮建立緩存機制,將每一個版本使用哪一個模板緩存,可以減少不必要的開銷。
2、Parse和rewparse標簽共存。
新的標簽實現了一些較為復雜的功能,為了避免不必要的開銷帶了未知的問題,我們采取了兩個標簽共存的方式,沒有多個版本的模板依然使用velocity原有標簽,只有多個模板存在的形式下才引用新的標簽。
4.4 方案小結
動態選擇模板方案,保證了各個版本模板間的獨立性,每個版本修改均不會影響其他版本。在一定程度上也減少了老版本測試工作量,有效避免了兼容問題;動態路由是在基于模板存在的情況下進行的,某一版本模板缺失,系統可以自動路由至其他版本模板,避免出現異常;如果N個版本后要放棄維護某些低版本,可以直接物理刪除這些版本即可;去掉版本判斷后的代碼也變的更加清晰簡單,維護成本大大降低。
5 總結
APP詳情頁作為服務端與native端的橋梁,既要關注業務邏輯又要關注如何去給native提供數據協議。在工作中要區分數據的是服務端的還是要給native端的,要更加細化業務層,了解從視圖到業務邏輯層是如何實現的。
來自:http://mp.weixin.qq.com/s?__biz=MzIzNzQzNjEwMw==&mid=2247484142&idx=1&sn=7c0659b0a2510ad26e2b116c41b69538&chksm=e8c9ef46dfbe6650663911bc315ddd2cee02368db3c9cca88b185a7c21d0f4f0acc8d621142e&scene=0#wechat_redirect