本系列博文,將會一步一步介紹如何構建一個輕量級的web框架jbeer git地址:http://git.oschina.net/bieber/jbeer前端
本文主要分享一下在JBeer中MVC模塊的Controller解析,主要分享JBeer如何解析一個Controller,映射到各個action處理的路徑以及Request參數注入。 ###1、Controller解析### 下面列舉出簡單的Action實例<br/>java
<!-- lang: java --> @Controller(urlPattern="/first") public class FirstController extends BaseController{ @Action(urlPatterns="invoke_${id}_${name}.htm") public String pathParam(@PathParam("id")Integer id,@PathParam("name")String name){ return "view"; } }
下面對框架解析一個Controller以及分析Action進行分享:<br/> 一) 應用啓動,觸發JBeerWeb
的init()方法<br/> 二) 經過ClassUtils
的scanClassesByAnnotation方法獲取全部註解了@Controller
的類,並解析類中方法,並判斷是否被@Action
註解過。<br/> 三) 對每一個註解了@Action
的方法,生成一個ActionEntity
,該類中描述了一個Action接受的處理路徑,須要調用哪一個方法以及是哪一個controller類。下面粘貼處ActionEntity
的類定義:<br/>git
<!-- lang:java --> /** * action須要調用的方法對象 */ private Method actionInvokeMethod; /** * action須要調用的className */ private String controllerClassName; /** * 存儲當前Action的方法參數信息 */ private Collection<ActionMethodParam> methodParams; /** * 當前Action處理的請求方式 */ private RequestType requestType; /** * 當前Action能夠匹配的請求路徑集合 */ private Collection<PatternableUrl> patternedUrls;
其中定義了該Action方法觸發的上下文。上面對一些屬性進行了封裝,好比方法入參和匹配的路徑。web
一、ActionMethodParam
封裝了Action的各個入參信息,若是Action沒有入參,則methodParams
爲空,下面看看ActionMethodParam
中定義了什麼<br/>正則表達式
<!-- lang:java --> /** * 方法參數名 */ private String paramName; /** * 方法參數位置 */ private int paramIndex; private Class<?> parameterType; /** * 關聯的ID,能夠是bean的ID,也能夠是引用Properties或者IN18消息信息 */ private String refId; private String[] in18Args;
paramName
表示匹配url上面佔位符的內容,paramIndex
表示該參數是Action的第幾個位置的入參,parameterType
是參數的類型,用於進行類型轉換,上面三個屬性就能夠完成在路徑上進行佔位符配置的參數注入。而refId
則是經過配置@RefBean
,@Properties
或者@Message
註解來關聯框架內的資源,好比依賴一個bean,配置信息等。而in18Args
是當引用的是IN18的message配置信息時候,須要傳遞的參數。經過上面幾個參數,就能夠實現Action的入參的實際來源。數組
二、PatternableUrl
定義了匹配路徑的信息,具體定義以下:框架
<!-- lang:java --> /** * 匹配路徑的正則表達式 */ private String urlMatcher; /** * 配置的url路徑佔位符相關信息 */ private Collection<URLParam> urlParams;
其中urlMatcher
是待匹配的路徑正則表達式,而urlParams
則是路徑上面的參數信息。關於URLParam
定義信息以下:工具
<!-- lang:java --> /** * 佔位符參數名 */ private String paramName; /** * 佔位符參數所在的位置是第幾個,方面在請求時,肯定第幾個佔位符的值是當前參數的值 */ private int urlParamIndex;
上面經過解析配置的url,獲取佔位符中的內容賦值到paramName
中,以及記錄當前佔位符的位置(urlParamIndex
)。這裏的paramName
是和ActionMethodParam
中的paramName
保持一直的,否則沒法匹配對應的路徑參數值。url
到此,當一個請求路徑,經過匹配ActionEntity.patternedUrls
集合中的某一個來肯定當前的ActionEntity
是否可以處理當前一個請求,若是匹配經過,那麼在解析請求的路徑,從而實例化須要傳入Action方法的入參。<br/> 四)當解析完畢Controller中的Action後,那麼將會把Contrller放入到IOC容器中,後面須要引用Controller類的實體,將會從IOC中獲取。 ###2、Request參數注入### Jbeer框架的參數注入提供了兩種方式,一種是經過配置Controller非單例模式,框架自動注入到Controller類的屬性,這點相似struts2的風格。第二種是Controller單例模式,開發人員經過框架提供的工具類來獲取Request請求的參數。下面對這兩種原理進行介紹。 首先來看看JBeer是如何處理用戶一個請求的吧。 .net
上圖闡述了框架在接收到一個請求,通過哪些過程來進行處理。那麼ControllerInitialization
負責對Controller的實例化,包括對Controller對象的實例化(從IOC容器中獲取)和Action方法參數的實例化。而Request參數注入發生在generateController
方法中,而initActionMethodParams
方法則是初始化Action方法的參數。下面將主要分享這兩個方法。 ####一)、generateController####
Map<String,Object>
(其中文件上傳的文件也在其中)。<br/>Map<String,Object>
對象,咱們知道前端傳遞過來的參數是鍵值對的,好比name="bieber",user.name="bieber",names[0]="bieber0"或者users[0].name="bieber0"這種形式,這三種分別表示普通的鍵值對,對象的屬性鍵值對,數組形式鍵值對,對象數組鍵值對。上面這種層級關係,能夠經過對象引用樹來進行分析,那麼能夠假設這些對象屬性的公共父節點是Controller實體,那麼name則是這個Controller的字符串屬性,user則是Controller的對象屬性,一次類推names,users則是對象的數組屬性或者是集合。下面則給出下面樹形結構圖。 Map<String,Object>
的目的,就是把無結構Map
解析成樹形結構。經過「.」來對Map的key進行分析,以及經過正則表達式來匹配key是否存在\[[0-9]{1,}\]
結構,能夠分析每一個.
則是一個樹的分層,.
以前的是父節點,以後的是子節點。經過該步驟對Map<String,Object>
分析,會獲得樹的第一層子節點。Map<String,Object>
若是其中key對不包含.
,其value則是一個Object[]
數組,若是包含.
,則value則是一個Map<String,Object>[]
數組。這兩經過樹的深度優先遍歷,可完成整個Request參數注入。固然,這一步先只分析一個深度,並把獲得的Map<String,Object>
放到JBeerWebContext
中。<br/>Map<String,Object>
自動注入到Controller的對應屬性中。若是是單例,則完成自動注入。RequestParameterUtil
來手動獲取請求參數。下圖展現了提供的接口。 @PathParam
來指定參數名),以及系統層面的參數(好比:HttpServletRequest
,HttpServletResponse
等等)。分析規則,則是按照解析Action方法時生成的對應信息。具體可見上面內容。<br/>關於具體實現,還但願經過項目源碼進行分析,此處只是進行簡單的分享。若是有什麼意見還但願你們可以提點意見。