1Struts2攔截器簡介
攔截器(Interceptor)是Struts2框架的核心功能之一,主要完成請求參數(shù)的解析、將頁面表單參數(shù)賦給值棧中相應(yīng)屬性、執(zhí)行功能檢驗(yàn)、程序異常調(diào)試等工作。Struts2攔截器是一種可插拔策略,實(shí)現(xiàn)了面向切面的組件開發(fā),當(dāng)需要擴(kuò)展功能時(shí),只需要提供對應(yīng)攔截器,并將它配置在Struts2容器中即可,如果不需要該功能時(shí),也只需要在配置文件取消該攔截器的設(shè)置,整個(gè)過程不需要用戶添加額外的代碼。攔截器中更為重要的概念即攔截器棧(InterceptorStack),攔截器棧就是Struts2中的攔截器按一定的順序組成的一個(gè)線性鏈,頁面發(fā)出請求,訪問Action對象或方法時(shí),棧中被設(shè)置好的攔截器就會(huì)根據(jù)堆棧的原理順序的被調(diào)用。
2系統(tǒng)分析與存在問題
2.1系統(tǒng)分析Struts2是基于MVC架構(gòu)的框架。Struts2將應(yīng)用分層,使產(chǎn)品結(jié)構(gòu)清晰,開發(fā)人員分層實(shí)現(xiàn)各自的功能模塊,Java程序員可以只專注于業(yè)務(wù)邏輯層的實(shí)現(xiàn),HTML前端程序員可以集中精力于視圖層的開發(fā),這種分層有利于縮短產(chǎn)品的開發(fā)時(shí)間,減輕產(chǎn)品的后期維護(hù)量,并且有利于各層之間的解耦。本系統(tǒng)實(shí)現(xiàn)的是數(shù)據(jù)庫增刪改查操作,充分運(yùn)用了Struts2的攔截器功能,靈活解決了傳統(tǒng)實(shí)現(xiàn)出現(xiàn)的各種問題,而且性能更為優(yōu)越,本系統(tǒng)有一個(gè)Teacher類,分別有teacherId、FirstName、LastName、Email四個(gè)屬性。系統(tǒng)主要分為4個(gè)模塊,分別是數(shù)據(jù)添加模塊,如圖1所示;數(shù)據(jù)編輯模塊,如圖2所示;全部數(shù)據(jù)顯示模塊和數(shù)據(jù)刪除模塊如圖3所示。2.2傳統(tǒng)開發(fā)存在的問題問題1:Struts2默認(rèn)采用<interceptor-stackname="defaultStack">defaultStack攔截器棧,攔截器順序?yàn)閙odelDriven->Params,在實(shí)現(xiàn)數(shù)據(jù)添加和數(shù)據(jù)編輯時(shí),都會(huì)在modelDriven攔截器的getModel方法中新建一個(gè)teacher()對象,并把它壓入到值棧棧頂,然后Params攔截器將頁面表單的值賦給值棧的teacher對象,數(shù)據(jù)添加時(shí)這種操作是可行的,但是在數(shù)據(jù)編輯時(shí),系統(tǒng)需要根據(jù)id值從數(shù)據(jù)庫獲得數(shù)據(jù),然后將數(shù)據(jù)賦給值棧的teacher對象,從而實(shí)現(xiàn)數(shù)據(jù)的回顯,系統(tǒng)沒有必要在這里新建一個(gè)teacher對象,這會(huì)導(dǎo)致系統(tǒng)的執(zhí)行效率的降低。問題2:當(dāng)執(zhí)行Delete操作的時(shí)候,系統(tǒng)檢測到teacherId不為空,就會(huì)根據(jù)teacherId的值從數(shù)據(jù)庫加載一個(gè)teacher對象,這個(gè)對象是不該加載的,增加了數(shù)據(jù)庫的訪問開銷;其次當(dāng)查詢數(shù)據(jù)庫全部信息時(shí),也會(huì)新建一個(gè)teacher對象,這個(gè)對象同樣是不必要的,造成了系統(tǒng)資源的浪費(fèi)。
3系統(tǒng)設(shè)計(jì)和實(shí)現(xiàn)原理
3.1系統(tǒng)設(shè)計(jì)針對問題1的解決方案,系統(tǒng)采取更改默認(rèn)的defaultStack攔截器棧的方法,在Struts2.xml文件中配置<interceptor-stackname="paramsPrepareParamsStack">,這個(gè)攔截器棧的攔截順序?yàn)镻arams->modelDriven->Params,跟默認(rèn)攔截器棧不同的是,它會(huì)先執(zhí)行Params攔截,所以可以先準(zhǔn)備請求參數(shù),例如Id的值賦給Action對象的teacherId屬性,系統(tǒng)在Action中可以根據(jù)teacherId的值決定將哪個(gè)對象壓入到值棧棧頂,最后Params攔截器會(huì)將表單參數(shù)的值賦給棧頂對象,模型驅(qū)動(dòng)方法中代碼如下所示:publicTeachergetModel(){if(teacherId==null)teacher=newTeacher();elseteacher=teacherDao.load(teacherId);returnteacher;}在添加數(shù)據(jù)時(shí),系統(tǒng)檢測到teacherId是空的,這時(shí)就會(huì)新建一個(gè)teacher對象,這符合正常的流程規(guī)范;而對數(shù)據(jù)編輯而言,用戶可以通過在頁面發(fā)送一個(gè)隱藏域的方法<s:hiddenname="teacherId"/>,系統(tǒng)檢測到此時(shí)teacherId不為空,則會(huì)根據(jù)teacherId的值從數(shù)據(jù)庫中加載對應(yīng)的teacher對象,這樣就有效的避免了總要新建一個(gè)teacher對象的問題。運(yùn)用上述這種方法,系統(tǒng)的代碼就非常干凈了,但即使把代碼處理得這么好,仍然存在一些問題,也就是上述的問題2,解決這個(gè)問題的途徑是再為業(yè)務(wù)類TeacherAction實(shí)現(xiàn)Preparable接口,這個(gè)接口提供了Prepare()方法,可以提前為系統(tǒng)處理一些業(yè)務(wù)邏輯,PrepareInterceptor攔截器將調(diào)用這些Prepare()方法。PrepareInterceptor攔截器是為模型驅(qū)動(dòng)的getModel()方法準(zhǔn)備數(shù)據(jù)的,首先要設(shè)置PrepareInterceptor的alwaysInvokePrepare屬性為False,則Struts2將不會(huì)調(diào)用TeacherAction的Prepare()方法,而是為類中的每一個(gè)方法準(zhǔn)備各自的Prepare()方法。本系統(tǒng)中在TeacherAction中部分代碼如下所示:3.2實(shí)現(xiàn)原理從Struts2的源碼分析,畫出Struts2的運(yùn)行時(shí)序圖如圖5所示。首先用戶通過瀏覽器發(fā)出請求,例如,由web.xml配置文件解析該請求,經(jīng)過一系列Servlet過濾器,到達(dá)Struts2的核心過濾器,核心過濾器首先執(zhí)行doFilter方法,在該方法中先執(zhí)行一系列準(zhǔn)備工作,比如設(shè)置和響應(yīng)相應(yīng)的編碼格式,創(chuàng)建上下文等等,然后根據(jù)名稱、命名空間、請求方法、請求參數(shù)查找業(yè)務(wù)類對應(yīng)的Action。接著創(chuàng)建一個(gè)代理類,在代理類中加載項(xiàng)目配置文件,找到所需的業(yè)務(wù)實(shí)體類,在代理類中創(chuàng)建一個(gè)Invocation對象,并通過它的invoke方法調(diào)用一系列的攔截器并到達(dá)業(yè)務(wù)類的Action,Action執(zhí)行完后會(huì)返回結(jié)果集字符串,根據(jù)模板產(chǎn)生相應(yīng)的頁面,將響應(yīng)返回給客戶端。Params攔截器負(fù)責(zé)將頁面字段賦值到valueStack中棧頂?shù)膶?yīng)屬性中,在此之前modelDriven攔截器已經(jīng)將Bean(Teacher)壓入到棧頂,所以Teacher對象將得到表單參數(shù)的賦值。在默認(rèn)的攔截器棧中,modelDriven攔截器執(zhí)行順序是在Params攔截器之前,但在一些特定情景下需要準(zhǔn)備模型對象,要求提前獲得表單傳入的參數(shù),要實(shí)現(xiàn)這個(gè)功能,系統(tǒng)必須實(shí)現(xiàn)Prepare接口,設(shè)置好Prepare攔截器。paramsPrepareParamsStack攔截器棧中的攔截器調(diào)用順序?yàn)椋篜arams->Prepare->modelDriven->Params。攔截器棧配置如圖6所示,執(zhí)行流程如下:(1)Params攔截器首先給action中的相關(guān)屬性賦值;(2)Prepare攔截器實(shí)現(xiàn)prepare接口并執(zhí)行該方法,準(zhǔn)備相應(yīng)模型對象;(3)modelDriven攔截器將模型對象壓入值棧;(4)Params攔截器再將頁面參數(shù)賦值給模型對象;(5)執(zhí)行action方法,再依次調(diào)用各攔截器。
4小結(jié)
應(yīng)用Struts2特有的攔截器功能和值棧結(jié)構(gòu),用戶可以根據(jù)需求,靈活的處理各種業(yè)務(wù)邏輯,攔截器的功能只需在配置文件中進(jìn)行設(shè)置,不需要用戶額外編寫代碼,Struts2中的攔截器是Action級別的AOP,通過攔截器,可以方便用戶對業(yè)務(wù)進(jìn)行擴(kuò)展,本文就是通過Struts2的攔截器功能解決了常見的數(shù)據(jù)庫訪問效率的問題,為JavaWeb開發(fā)者提供了一個(gè)有效的案例,這也是未來JavaWeb開發(fā)的一種趨勢。