Vincent

          Vicent's blog
          隨筆 - 74, 文章 - 0, 評論 - 5, 引用 - 0
          數(shù)據(jù)加載中……

          WebWork教程-ServletDispatcher

          ServletDispatcher 是默認(rèn)的處理 Web Http 請求的調(diào)度器,它是一個(gè) JavaServlet ,是 WebWork 框架的控制器。所有對 Action 調(diào)用的請求都將通過這個(gè) ServletDispatcher 調(diào)度。它將在 web.xml 里配置 ServletDispatcher 時(shí)指定,讓所有對 WebWork Action( 默認(rèn)的是 .action 的后綴 ) 的請求都對應(yīng)到該調(diào)度的 JavaServlet 中,具體配置在前面的 WebWork-helloWorld 中有介紹。
          ?
          ServletDispatcher 接受客戶端的 HTTP 請求,將 JavaServlet 的很多相關(guān)對象進(jìn)行包裝,再傳給我們的 XWork 框架,由我們的 XWork 框架去解析我們的 xwork.xml 配置文件,根據(jù)配置文件的信息,創(chuàng)建對應(yīng)的 Action ,組裝并調(diào)用相應(yīng)的攔截器,執(zhí)行 Action ,返回執(zhí)行結(jié)果。 WebWork 使用 XWork 的核心,主要是由這個(gè) ServletDispatcher 去實(shí)現(xiàn)的
          ?
          具體調(diào)用流程: (Servlet 調(diào)用流程 )
          ?
          一、? init ()方法在 web 服務(wù)器啟動時(shí)調(diào)用。
          1 、初始化 Velocity 引擎
          ?
          2 、檢查是否支持配置文件重新載入功能。如果 webwork.configuration.xml.reload (見 webwork.properties 文件)設(shè)置為 true, 每個(gè) request 請求都將重新裝載 xwork.xml 配置文件。在開發(fā)環(huán)境使用將會非常方便,但在生產(chǎn)環(huán)境必需設(shè)置為 false
          代碼如下:
          if ("true".equalsIgnoreCase(Configuration.getString("webwork.configuration.xml.reload"))) {FileManager.setReloadingConfigs(true);}
          ?
          3 、設(shè)置一些文件上傳的信息,比如:上傳臨時(shí)目錄,上傳的最大字節(jié)等。都設(shè)置在 webwork.properties 文件里,如果在 classpath 中找不到這個(gè)屬性文件,它會去讀取默認(rèn)的 default.properties
          ?
          二、?? service ()方法,每次客戶端的請求都將調(diào)用此方法
          1、??????????? 通過 request 請求取得 action 的命名空間( namespace ,與 xwork.xml 配置文件里 package 標(biāo)簽的 name 對應(yīng))
          例如: /foo/bar/MyAction.action ,取得的命名空間為 /foo/bar xwork.xml 配置文件里應(yīng)該有這一段: <package name="foo.bar" …….
          ?
          2、??????????? 根據(jù) servlet 請求的 Path, 解析出要調(diào)用該請求的 Action 的名字( actionName ),例如:( ../foo/bar/MyAction.action -> MyAction
          xwork.xml 配置文件里應(yīng)該有:
          <package name="foo.bar" …….
          <Action name=” MyAction”……]
          ?
          3、??????????? 創(chuàng)建 Action 上下文( extraContext )。我們前面介紹的 ActionContext 上下文的對象,就是在這里設(shè)置的。它將 JavaServlet 相關(guān)的對象進(jìn)行包裝,放入到 extraContext 這個(gè) Map 對象里。
          /**
          ???? * 將所有的應(yīng)用請求和 servlet 屬性保存到一個(gè) HashMap 中,
          ???? * @param requestMap 存放所有 request 請求屬性的 Map
          ???? * @param parameterMap 存放所有 request 請求參數(shù)的 Map
          ???? * @param sessionMap 存放所有 session 屬性的 Map
          ???? * @param applicationMap 存放所有 servlet 上下文屬性的 Map
          ???? * @param request?HttpServletRequest 對象
          ???? * @param response ?HttpServletResponse 對象 .
          ???? * @param servletConfig ?ServletConfig 對象 .
          ???? * @return 代表 Action 上下文的一個(gè) HashMap
          */
          ?
          ?
          public static HashMap createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletConfig servletConfig) {
          ??????? HashMap extraContext = new HashMap();
          ??????? extraContext.put(ActionContext.PARAMETERS, parameterMap);
          ??????? extraContext.put(ActionContext.SESSION, sessionMap);
          ??????? extraContext.put(ActionContext.APPLICATION, applicationMap);
          ??????? extraContext.put(ActionContext.LOCALE, request.getLocale());
          ?
          ??????? extraContext.put(HTTP_REQUEST, request);
          ??????? extraContext.put(HTTP_RESPONSE, response);
          ??????? extraContext.put(SERVLET_CONFIG, servletConfig);
          ??????? extraContext.put(COMPONENT_MANAGER, request.getAttribute("DefaultComponentManager"));
          ?
          ??????? // helpers to get access to request/session/application scope
          ??????? extraContext.put("request", requestMap);
          ??????? extraContext.put("session", sessionMap);
          ??????? extraContext.put("application", applicationMap);
          ??????? extraContext.put("parameters", parameterMap);
          ?
          ??????? AttributeMap attrMap = new AttributeMap(extraContext);
          ??????? extraContext.put("attr", attrMap);
          ?
          ??????? return extraContext;}
          下面我們來看看它是如何將 request 請求的參數(shù)和 session 進(jìn)行包裝的:
          Request 包裝
          protected Map getParameterMap(HttpServletRequest request) throws IOException {
          ??????? return request.getParameterMap();
          }
          這個(gè)方法比較簡單,它直接調(diào)用了 HttpServletRequest 的方法 getParameterMap (),將所有 request 請求的參數(shù)封裝到一個(gè) Map
          ?
          Session 包裝
          protected Map getSessionMap(HttpServletRequest request) {
          ??????? return new SessionMap(request);
          }
          這個(gè)方法取得所有 Session 中的屬性,它調(diào)用了 com.opensymphony.webwork.dispatcher. SessionMap 類,這個(gè)類實(shí)現(xiàn)了 Map 接口,在 entrySet ()方法中列舉 Session 的所有屬性,存放在 Set 中。
          ?
          4、??????????? 根據(jù)前面獲得的 namespace actionName extraContext ,創(chuàng)建一個(gè) ActonProxy
          ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);
          默認(rèn)的 proxy com.opensymphony.xwork.DefaultActionProxy ,在它的構(gòu)造函數(shù)會進(jìn)行下面的操作:
          1 )、根據(jù) namespace actionName 讀取 xwork.xml 配置文件里這個(gè) Action 的所有配置信息
          ?
          2 )、創(chuàng)建 ActionInvocation
          invocation=ActionProxyFactory.getFactory().createActionInvocation(this, extraContext); 默認(rèn)的 invocation com.opensymphony.xwork.DefaultActionInvocation ,它的構(gòu)造函數(shù)操作有 :
          ?
          ???????????????????????? i.????????????? com.opensymphony.xwork.ObjectFactory 創(chuàng)建我們配置文件描述的 Action 對象。再將這個(gè) Action 對象存放入 OgnlValueStack 中。記得我們前面用戶注冊的例子嗎?當(dāng)用戶提交表達(dá)時(shí)它會有表達(dá)式語言向 OgnlValueStack 取得 Action 對象的字段,再把輸入框的數(shù)據(jù)設(shè)置到對應(yīng)的 Action 字段中,這個(gè) Action 對象就是在這個(gè)時(shí)候進(jìn)棧的

          ??????????????????????? ii.????????????? 傳入 extraContext 參數(shù),創(chuàng)建與 ActionInvocation 對應(yīng)的 Action 上下文( ActionContext )。記得我們在介紹 ActionContext 的最后,提出了一個(gè)需要注意的地方:不要在 Action 構(gòu)造函數(shù)中調(diào)用 ActionContext.getContext() 。現(xiàn)在應(yīng)該能明白,原來是 Action 對象實(shí)例在 ActionContext 對象實(shí)例之前創(chuàng)建的,所有這樣取得 ActionContext 容器對象就有可能會返回 null

          ????????????????????? iii.????????????? 取得這個(gè) Action 對應(yīng)的所有攔截器( Interceptor ),存放入 java.util.Iterator 對象中。
          ?
          5、??????????? 執(zhí)行 proxy execute() 方法,這個(gè)方法最核心的語句是: retCode = invocation.invoke(); invocation 對象的 invoke() 方法它遍歷并執(zhí)行這個(gè) Action 對應(yīng)的所有攔截器,執(zhí)行 Action 對應(yīng)的方法(默認(rèn)的是 execute() ),根據(jù) Action 執(zhí)行返回的值去調(diào)用執(zhí)行相應(yīng)的 Result (返回結(jié)果處理)的方法
          ?
          Action 的單元測試
          理解了 ServletDispatcher ,我們就明白了整個(gè)框架調(diào)用執(zhí)行的順序。 Action 雖然是與 Web 無關(guān),可是它的創(chuàng)建、參數(shù)設(shè)置、執(zhí)行與我們的 WebWork XWork 緊密關(guān)聯(lián)在一起,有我們的控制器 ServletDispatcher 去統(tǒng)一調(diào)度,那我們?nèi)绾稳?/span> Action 進(jìn)行獨(dú)立的單元測試呢?
          請看下面的例子:使用單元測試框架 JUnit register.User. RegisterAction 做單元測試
          example.register. RegisterActionTest testExecuteWithProxyFactory() 方法
          ?
          public void testExecuteWithProxyFactory() throws Exception{
          ???????
          ??????? // 創(chuàng)建 action 上下文( actionContext
          ??????? Map params = new HashMap();
          ??????? params.put("user.username","Moxie");
          ??????? params.put("user.password","mypassword");
          ??????? params.put("user.email","achqian@yahoo.com.cn");
          ??????? params.put("user.age",new Integer(23));
          ??????? Map extraContext = new HashMap();
          ??????? extraContext.put(ActionContext.PARAMETERS,params);
          ???????
          ??????? // 創(chuàng)建代理(找出所在的 action
          ??????? ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("example", "register", extraContext);
          ?
          ??????? // 不要執(zhí)行出現(xiàn) Success 后的代碼
          proxy.setExecuteResult(false);
          ???????
          ??????? // 測試代碼是否正確
          ??? ??? assertEquals(proxy.execute(),"success");
          ???????
          ??????? // 返回 Action ,測試 action 里面的代碼是否正確
          ??????? RegisterAction action = (RegisterAction) proxy.getAction();
          ??????? assertEquals(action.getUser().getUsername(),"Moxie");
          ??????? assertEquals(action.getUser().getAge(),23);
          ??? }
          ?
          下面解說這個(gè)方法:
          1、?? 對象 params 表示請求參數(shù)的 Map, 在它里面設(shè)置了注冊用戶的信息。 extraContext 當(dāng)然就是我們 ActionContext 上下文的容器,它里面保存了放置請求參數(shù)的對象 params
          2、?? 創(chuàng)建我們的 ActionProxy ,它傳入的參數(shù)有:“ example ”-這個(gè) Action 的命名空間,“ register ”- Action 對應(yīng)的名字, extraContext -存放 Actin 上下文里的對象,,執(zhí)行并將它返回的值與“ success ”比較,測試 Action 是否能正確執(zhí)行完成。注意: proxy.setExecuteResult(false); ,因?yàn)槲覀兪菃卧獪y試,所以 Action 執(zhí)行完成就可以了,不用再去調(diào)用結(jié)果響應(yīng)的操作,故將是否執(zhí)行結(jié)果設(shè)置為“ false ”。
          3、?? Action 正確執(zhí)行完成之后,我們也可以測試現(xiàn)在 Action 的字段里的數(shù)據(jù)是否按照我們預(yù)期的要求正確設(shè)置。從 ActionProxy 對象里取得執(zhí)行的 Action ,即 RegisterAction 對象,再取得它的 User 模型,將其數(shù)據(jù)與前面設(shè)置參數(shù)的數(shù)據(jù)進(jìn)行比較,判斷它是否等于我們預(yù)期設(shè)置的數(shù)值。
          ?
          ?
          Result Type
          前面我們學(xué)習(xí)了 ServletDispatcher ,它是 WebWork 框架機(jī)制的核心。它和 Action 在我們 MVC 模式中,扮演著控制器的角色, MVC 模式通過控制器實(shí)現(xiàn)了我們模型和視圖的分離。 WebWork 提供了多種活靈活視圖展現(xiàn)方式。
          我們先看看前面用戶注冊例子的展現(xiàn)方式:我們使用的是 Jsp WebWork 自帶的標(biāo)簽庫, Action 對應(yīng)的視圖當(dāng)然是在 xwork.xml 配置文件里設(shè)置:
          <action name="register" class="example.register.RegisterAction" >
          <result name="success" type="dispatcher">
          ?????????? <param name="location">register-result.jsp</param>
          </result>
          <interceptor-ref name="params"/>
          </action>
          ?
          Result Action 執(zhí)行完返回的一個(gè)字符串常量,它表示 Action 執(zhí)行完成的狀態(tài),比如:執(zhí)行成功、執(zhí)行失敗等。在我們前面 Action 的介紹中,詳細(xì)介紹了它默認(rèn)的標(biāo)準(zhǔn) Result ,當(dāng)然 Result 我們也可以自己定義,只要是一個(gè)字符串常量就可以了。
          ?
          Result 的值在 xwork.xml 配置文件里就是 result 標(biāo)簽里“ name ”的值, name="success" 表示 Action 執(zhí)行成功,返回“ success ”就對應(yīng)此標(biāo)簽的配置,進(jìn)行視圖輸出:
          type ”就是我們的 Result Type Result Type 是一個(gè)類,它在 Action 執(zhí)行完成并返回 Result 之后,決定采用哪一種視圖技術(shù),將執(zhí)行結(jié)果展現(xiàn)給用戶。我們輸出的類型是
          type="dispatcher" ,它對應(yīng) com.opensymphony.webwork.dispatcher.ServletDispatcherResult 這個(gè)類,它將執(zhí)行結(jié)果通過 javax.servlet.RequestDispatcher forward() include() 方法調(diào)度到 Jsp 頁面展現(xiàn)。
          我們可以自己開發(fā) Result Type ,實(shí)現(xiàn)我們需要的視圖展現(xiàn)方式。 Result Type 必需要實(shí)現(xiàn) com.opensymphony.xwork..Result 接口。在 WebWork 中,它已經(jīng)為我們提供了很多 Result Type ,實(shí)現(xiàn)了視圖部分對 JSP, Velocity, FreeMarker, JasperReports XML 等的支持,具體如下表格 :
          Result Type
          Nname
          Class
          Dispatcher
          dispatcher
          com.opensymphony.webwork.dispatcher.ServletDispatcherResult
          Redirect
          Redirect
          com.opensymphony.webwork.dispatcher.ServletRedirectResult
          Action Chaining
          Chain
          com.opensymphony.xwork.ActionChainResult
          Velocity
          Velocity
          com.opensymphony.webwork.dispatcher.VelocityResult
          FreeMarker
          freemarker
          com.opensymphony.webwork.views.freemarker.FreemarkerResult
          JasperReports
          Jasper
          com.opensymphony.webwork.views.jasperreports.JasperReportsResult
          XML/XSL
          Xslt
          com.opensymphony.webwork.views.xslt.XSLTResult
          HttpHeader
          ?
          com.opensymphony.webwork.dispatcher.HttpHeaderResult
          ?
          ?
          Dispatcher 通過 javax.servlet.RequestDispatcher forward() include() 方法調(diào)度到頁面展現(xiàn),這樣的頁面一般是 Jsp 頁面。
          ?
          參數(shù) (Parameters)
          是否必需
          ?
          location
          執(zhí)行完成之后轉(zhuǎn)向的位置
          parse
          默認(rèn)的是“ true ”,如果設(shè)置為“ false ”, location 參數(shù)將不會被 OGNL 表達(dá)式語言解析
          例子:
          <result name="success" type="dispatcher">
          ?????????? <param name="location">register-result.jsp</param>
          ???????? </result>
          也可以簡單寫成這樣:
          ?? <result name="success" type="dispatcher">register-result.jsp</result>
          ?
          ?
          Action Chaining 一種特殊的視圖結(jié)果,將 Action 執(zhí)行完之后鏈接到另一個(gè) Action 中繼續(xù)執(zhí)行。新的 Action 使用上一個(gè) Action 的上下文( ActionContext )。
          ?
          參數(shù) (Parameters)
          是否必需
          ?
          actionName
          將要被鏈接的 Action 名字
          namespace
          被鏈接的 Action 的命名空間( namespace ),如果不設(shè)置,默認(rèn)的即是當(dāng)前的命名空間
          例子:
          <result name="success" type="chain">
          ??? <param name="actionName">bar</param>
          ??? <param name="namespace">/foo</param>
          </result>
          ?
          將要調(diào)用的 Action 如下:
          <action name="bar" class="myPackage.barAction">
          ??? ...
          </action>
          ?
          Velocity 它類似 Jsp 的執(zhí)行環(huán)境(使用 JavaServlet 容器),將 Velocity 模板轉(zhuǎn)化成數(shù)據(jù)流的形式,直接通過 JavaServlet 輸出。
          ?
          參數(shù) (Parameters)
          是否必需
          ?
          location
          執(zhí)行完成之后轉(zhuǎn)向的位置 ( 一般是 .vm 頁面 )
          parse
          默認(rèn)的是“ true ”,如果設(shè)置為“ false ”, location 參數(shù)將不會被 OGNL 表達(dá)式語言解析
          例子:
          <result name="success" type="velocity">
          ??? <param name="location">foo.vm</param>
          </result>
          ?
          ?
          FreeMarker FreeMarker 是一個(gè)純 Java 模板引擎;一個(gè)普通的基于模板生成文本的工具,它只能應(yīng)用在 Web 應(yīng)用環(huán)境中。
          ?
          參數(shù) (Parameters)
          是否必需
          ?
          location
          執(zhí)行完成之后轉(zhuǎn)向的位置
          parse
          默認(rèn)的是“ true ”,如果設(shè)置為“ false ”, location 參數(shù)將不會被 OGNL 表達(dá)式語言解析
          contentType
          如果不指定,默認(rèn)的是 "text/html"
          例子:
          <result name="success" type="freemarker">foo.ftl</result>
          ?
          ?
          JasperReports Action 執(zhí)行的結(jié)果通過 JasperReports 報(bào)表形式輸出,可以指定 JasperReports 支持的輸出格式( PDF HTML XLS CSV XML 等),默認(rèn)是通過 PDF 格式輸出。
          參數(shù) (Parameters)
          是否必需
          ?
          location
          執(zhí)行完成之后轉(zhuǎn)向的位置
          parse
          默認(rèn)的是“ true ”,如果設(shè)置為“ false ”, location 參數(shù)將不會被 OGNL 表達(dá)式語言解析
          dataSource
          它是 Action 的一個(gè)字段(通常是一個(gè) List ), OGNL 表達(dá)式被用來去 value stack OgnlValueStack )重新找回這個(gè) dataSource
          format
          報(bào)表生成的數(shù)據(jù)格式,默認(rèn)的是 pdf
          例子:
          <result name="success" type="jasper">
          ??? <param name="location">foo.jasper</param>
          ??? <param name="dataSource">mySource</param>
          ??? <param name="format">CSV</param>
          </result>
          ?
          或者默認(rèn)的 pdf 格式
          <result name="success" type="jasper">
          ??? <param name="location">foo.jasper</param>
          ??? <param name="dataSource">mySource</param>
          </result>
          ????????
          XML/XSL 將結(jié)果轉(zhuǎn)換為 xml 輸出
          ?
          參數(shù) (Parameters)
          是否必需
          ?
          location
          執(zhí)行完成之后轉(zhuǎn)向的位置
          parse
          默認(rèn)的是“ true ”,如果設(shè)置為“ false ”, location 參數(shù)將不會被 OGNL 表達(dá)式語言解析
          例子:
          <result name="success" type="xslt">foo.xslt</result>??

          posted on 2006-09-01 13:41 Binary 閱讀(653) 評論(0)  編輯  收藏 所屬分類: Webwork


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 苏尼特右旗| 西丰县| 阳山县| 琼海市| 松阳县| 南宁市| 抚宁县| 藁城市| 枣强县| 普洱| 邮箱| 清涧县| 五华县| 彩票| 信阳市| 库尔勒市| 广河县| 罗山县| 苗栗市| 阜阳市| 喀什市| 全椒县| 望谟县| 林口县| 商城县| 绵竹市| 毕节市| 曲周县| 张北县| 黔西| 西丰县| 河津市| 和硕县| 金塔县| 沙河市| 岑巩县| 翁源县| 诏安县| 定州市| 鹤山市| 镇赉县|