在設(shè)計(jì)完API后,,我們就需要實(shí)現(xiàn)這個(gè)MVC框架。MVC框架的核心是一個(gè)DispatcherServlet,用于接收所有的HTTP請(qǐng)求,并根據(jù)URL選擇合適的Action對(duì)其進(jìn)行處理。在這里,和Struts不同的是,所有的組件均被IoC容器管理,,因此,DispatcherServlet需要實(shí)例化并持有Guice IoC容器,,此外,,DispatcherServlet還需要保存URL映射和Action的對(duì)應(yīng)關(guān)系,,一個(gè)Interceptor攔截器鏈,一個(gè)ExceptionResolver處理異常,。DispatcherServlet定義如下: package com.javaeedev.lightweight.mvc; /** private Log log = LogFactory.getLog(getClass()); private Map<String, ActionAndMethod> actionMap; private Injector injector = null; // Guice IoC容器 ... Guice的配置完全由Java 5注解完成,,而在DispatcherServlet中,我們需要主動(dòng)從容器中查找某種類型的Bean,,相對(duì)于客戶端被動(dòng)地使用IoC容器(客戶端甚至不能感覺(jué)到IoC容器的存在),,DispatcherServlet需要使用ServiceLocator模式主動(dòng)查找Bean,寫一個(gè)通用方法: private List<Key<?>> findKeysByType(Injector inj, Class<?> type) { DispatcherServlet初始化時(shí)就要首先初始化Guice IoC容器: public void init(ServletConfig config) throws ServletException { 然后,,從IoC容器中查找Action和URL的映射關(guān)系: private Map<String, ActionAndMethod> getUrlMapping(List<Key<?>> actionKeys) { 我們假定客戶端是以如下方式配置Action和URL映射的: public class MyModule implements Module { public void configure(Binder binder) { 即通過(guò)Guice提供的一個(gè)注解Names.named()指定URL,。當(dāng)然還可以用其他方法,比如標(biāo)注一個(gè)@Url注解可能更方便,,下一個(gè)版本會(huì)加上,。 Interceptor,ExceptionResolver和ViewResolver也是通過(guò)查找獲得的,。 下面討論DispatcherServlet如何真正處理用戶請(qǐng)求,。第一步是根據(jù)URL查找對(duì)應(yīng)的Action: String contextPath = request.getContextPath(); 沒(méi)找到Action就直接給個(gè)404 Not Found,找到了進(jìn)行下一步,,實(shí)例化一個(gè)Action并填充參數(shù): // init ActionContext: ActionContext.setActionContext(request, response, session, context); // 每次創(chuàng)建一個(gè)新的Action實(shí)例: 注意,,為了提高速度,所有的set方法已經(jīng)預(yù)先緩存了,,因此避免每次請(qǐng)求都用反射重復(fù)查找Action的set方法,。 然后要應(yīng)用所有的Interceptor以便攔截Action: InterceptorChainImpl chains = new InterceptorChainImpl(interceptors); 實(shí)現(xiàn)InterceptorChain看上去復(fù)雜,,其實(shí)就是一個(gè)簡(jiǎn)單的遞歸,,大家看InterceptorChainImpl代碼就知道了: package com.javaeedev.lightweight.mvc; /** private final Interceptor[] interceptors; InterceptorChainImpl(Interceptor[] interceptors) { ModelAndView getModelAndView() { public void doInterceptor(Action action) throws Exception { 把上面的代碼用try ... catch包起來(lái),,就可以應(yīng)用ExceptionResolver了。 如果得到了ModelAndView,,最后一步就是渲染View了,,這個(gè)過(guò)程極其簡(jiǎn)單: // render view: 最簡(jiǎn)單的JspViewResolver的實(shí)現(xiàn)如下: package com.javaeedev.lightweight.mvc.view; /** /** /** 至此,MVC框架的核心已經(jīng)完成,。 評(píng) 1,。在Action里現(xiàn)在的屬性set支持是基本類型和數(shù)組,但是在一般的應(yīng)用中,,可能是希望直接得到一個(gè)PO,, 這個(gè)怎么實(shí)現(xiàn)
2。一個(gè)action怎么實(shí)現(xiàn)處理多個(gè)請(qǐng)求,,打個(gè)比方,,用戶注冊(cè),,有一個(gè)方法doRegister,還有一個(gè)方法,驗(yàn)證這個(gè)用戶名是否存在,,在前臺(tái)用ajax調(diào)用一次,,doValidateUserName,這兩個(gè)方法都在一個(gè)signupAction里,我在例子和sourcecode里都沒(méi)有找到比較好的解決辦法,,請(qǐng)教樓主,。 3。Example提供的例子非常好,,但是Transaction在action的這個(gè)粒度上interceptor,,感覺(jué)不是很好,從分層的角度講,,不利于封裝,;是不是在business層會(huì)更好一點(diǎn) xuefeng發(fā)表于07-12-24 09:42
1.得到所有屬性后,就可以在execute()方法中構(gòu)造該Bean,,不想設(shè)計(jì)成Struts的FormBean,,配置特別麻煩
2.寫一個(gè)MultiAction,根據(jù)某個(gè)參數(shù)action=register用反射調(diào)用doRegister()或doValidate() 3.為了演示Interceptor的用法,,和Filter類似,,但是僅限于Action層,不包括Render View,,事務(wù)具體在哪里開(kāi)要根據(jù)具體應(yīng)用確定 bus387發(fā)表于07-12-24 11:19
1.得到所有屬性后,,就可以在execute()方法中構(gòu)造該Bean,不想設(shè)計(jì)成Struts的FormBean,,配置特別麻煩
在execute里再構(gòu)造Bean,當(dāng)然也是可以,,如可以用BeanUtils.setProperties(request, po); 要是框架能做到這些事情,就更完美了,。我相信你一定能做到0配置,,不需要再像Struts一樣有FormBean, 我當(dāng)時(shí)為了0配置到Google搜索就找到這個(gè)框架的。 “2.寫一個(gè)MultiAction,,根據(jù)某個(gè)參數(shù)action=register用反射調(diào)用doRegister()或doValidate()” Good Idea! 這樣做的話,,doRegister和doValidate需要傳入的參數(shù)和表單提交的數(shù)據(jù)是不一樣的,如果form里有20幾個(gè)參數(shù),,這20幾個(gè)參數(shù)都放在action里作為屬性,,就不好區(qū)分doRegister和doValidate方法需要的了。 xuefeng發(fā)表于07-12-24 13:33
java作為靜態(tài)語(yǔ)言和ruby還是不一樣的,,ruby可以來(lái)個(gè)execute(MyBean bean),,但是java如果這樣搞就必須用反射,而且不能利用接口調(diào)用了,,比較好的方式是定義一個(gè)setBean(MyBean bean),,效果和多個(gè)setBeanProperty1(), setBeanProperty2()效果類似
下個(gè)版本可以考慮在一個(gè)Action中定義多個(gè)executeXxx()方法,,每個(gè)execute方法可以對(duì)應(yīng)一個(gè)setXxx(MyBean bean),url默認(rèn)映射為/baseUrl/xxx?params freeren發(fā)表于07-12-28 14:53
樓主,,今天一直在研讀你的代碼
然后跟我同事談了這事,,我想問(wèn)下,velocity是不是不再發(fā)布了,,聽(tīng)說(shuō)現(xiàn)地freemarker更多人使用,,是不是這樣? mdream發(fā)表于07-12-28 14:55
velocity 最近不是已經(jīng)發(fā)了1.5版本了.貌似現(xiàn)在進(jìn)度比以前快很多.APACHE頂級(jí)項(xiàng)目.
xuefeng發(fā)表于07-12-28 15:43
freemarker就是比velocity多一個(gè)格式化功能,,其他都差不多,,主要是velocity配置比較簡(jiǎn)單
freeren發(fā)表于07-12-28 18:20
謝謝兩位的分享,看來(lái)小弟還有很多東西需要學(xué)的,。今天下午小弟測(cè)試了代碼結(jié)果,,tomcat啟動(dòng)時(shí)總是出現(xiàn)這個(gè)錯(cuò)誤:
2007-12-28 17:57:35,781 [main] ERROR org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[ /light] - Servlet /light threw load() exception java.lang.ClassNotFoundException: com.lightmvc.sample.SampleModule --小弟把目錄改了,在class目錄下也有SampleModule的class文件,,但為什么總是說(shuō)找不到呢,? freeren發(fā)表于07-12-28 18:23
對(duì)了,還有web.xml的
<filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>*.do</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping> 也出現(xiàn)了以下的報(bào)錯(cuò)信息: Multiple annotations found at this line: - The content of element type "filter-mapping" must match "(filter-name, (url-pattern|servlet-name))". - Missing end tag "filter-mapping" 小弟把<dispatcher>REQUEST</dispatcher>注釋了就沒(méi)問(wèn)題了,。請(qǐng)問(wèn)這如何解決! |
|