配置對應環境,運行petstorehtml
git clone https://github.com/webx/citrus-sample.git cd citrus-sample/petstore mvn clean install cd web mvn jetty:run-war
maven是一個巨大項目的管理工具,相似於C++的makefile,回頭會具體細看maven的用法。下面是執行上面遇到的問題總結:前端
下載配置maven:下載maven連接 ,注意maven運行須要jdk,而不只僅是jre,不然會提示對應的錯誤;
mvn jetty:run-war,執行報錯,參見帖子:mvn jetty:run-war 報錯 的解決方法
jetty跑起來以後,經過以下連接訪問:http://localhost:8081/?homejava
經過上面步驟已經能夠開始分析petstore了,面對一個新框架,分析這個仍是有點棘手,因此,我仍是選擇了從hello,world工程開始。這裏,在阿里學習上,找到了一個webx學習的視頻,多聽幾遍,才慢慢聽懂,連接:阿里學習-webx分享。經過這個視頻對照快速創建的webx工程,能夠有效的來進行學習。git
new 一個maven工程
在選擇archetype界面,右下角有一個add archetype, webx-archetype信息 ,倉庫地址
至此,就能夠經過webx-archetype-quickstart來快速創建一個webx的工程了,而且有基本的學習例子,對照着前面給出的視頻教程,反覆觀看和操做能夠簡單快速的瞭解概念。github
*vm的模板文件並不可以語法高亮和自動補全,寫起來比較痛苦,一個安裝插件的地址:veloeclipse插件地址 ,在安裝過程當中會遇到錯誤:web
An error occurred while installing the items session context was:(profile=epp.package.jee, phase=org.eclipse.equinox.internal.p2.engine.phases.Install, operand=null –>spring
[R]com.googlecode.veloeclipse.ui 2.0.8, action=).數據庫
Failed to prepare partial IU: [R]com.googlecode.veloeclipse.ui 2.0.8.apache
此時,參考帖子:安裝veloeclipse遇到問題解決編程
經過前面的webx-quickstart產生的例子教程,能夠快速的入門webx。我的認爲比petstore更加適合來理解webx的概念和運行過程。可是petstore能夠稱做一個全面的項目,不少東西都涉及到了。因此這裏,仍是使用petstore來學習webx中的一些重要概念。其中不少東西都來自Webx3_Guide_Book.pdf
webx鼓勵層次化設計,框架自己也是層次化的。層次以下圖所示:
其中:
SpringExt:基於Spring,提供擴展組件的能力。它是整個框架的基礎。
Webx Framework:基於Servlet API,提供基礎的服務,例如:初始化Spring、初始化日誌、接收請求、錯誤處理、開發模式等。Webx Framework只和servlet及spring相關 ——它不關心Web框架中常見的一些服務,例如Action處理、表單處理、模板渲染等。所以,事實上,你能夠用Webx Framework來建立多種風格的Web框架。
Webx Turbine:基於Webx Framework,實現具體的網頁功能,例如:Action處理、表單處理、模板渲染等。
這個部分,還有待學習,咱們知道,SpringExt徹底兼容Spring原來schema的概念和風格,可是卻可讓schema像程序代碼同樣被擴展。Webx徹底創建在SpringExt的基礎上。這個基礎決定了Webx是一個高度可擴展的框架,其配置雖然靈活,卻又不失方便和直觀。SpringExt提供了一個通用的擴展機制。
webx Framework是第一個真正涉及web技術的層次。
在web.xml配置文件中,Webx利用WebxContextLoaderListener來初始化Spring。Webx Framework將會自動搜索/WEB-INF目錄下的XML配置文件,並建立級聯的spring容器。將一個大的應用分解成若干個小應用模塊,並使它們的配置文件相對獨立,這是一種很不錯的開發實踐。
在web.xml中,Webx利用LogConfiguratorListener來初始化日誌系統。
以下圖所示:
*. 首先,它會加強request、response、session的功能,並把它們打包成更易使用的RequestContext對象。在webx.xml中能夠配置request-contexts服務。
*. 其次,它會調用相應子應用的pipeline,用它來作進一步的處理。
*. 假如在上面的過程當中出現異常,則會觸發Webx Framework處理異常的過程。
pipline: webx Framework賦予開發者極大的自由,來定製處理請求的流程。如圖所示:
補充–WebxFrameworkFilter處理一個WEB請求的過程,以下圖所示:
Screen,表明頁面的主體。
Layout,表明頁面的佈局。
Control,表明嵌在screen和layout中的頁面片斷。
頁面的處理流程是在pipeline.xml中定義的,下面以http://localhost:8080/petstore/ 這個url來講明頁面的處理流程,Webx Framework的處理流程,從WebxFrameworkFilter接收請求,而且一路順利到達pipeline。而後Pipeline開始依次執行它的valves。:
* 1)analyzeURL - 分析URL:獲取target,這裏並無path信息,AnalyzeURL valve提供了一個可選的參數「homepage」;
* 2)進入choose- 多重分支: 這裏homepage沒有後綴,「homepage」知足了第一個所附帶的條件:target-extension-condition extension=」null」 ;
* 3)進入這個條件:performAction- 執行action,action是用來執行表單請求的,本地請求,並無action,因此跳過;
* 4)performTemplateScreen - 查找並執行screen。有一個規則去查找screen,若是找到screen類,就去執行它,Screen類的功能,一般是讀取數據庫,而後把模板所須要的對象放到context中。若是找不到,也不要緊 —— 這就是「頁面優先」:像homepage這樣的主頁,一般沒有業務邏輯,所以不須要screen類,只須要有模板就能夠了。
* 5)renderTemplate - 渲染模板。這裏用到兩個規則:target映射成screen template,以及target映射成layout template。若是沒有找到screen模板,就報404錯誤,若是找到就按照必定的規則去尋找layout模板,若是存在,就將screen嵌入到layout模板中。
* 6)breakUnlessTargetRedirected - 內部重定向。內部重定向實質上就是由breakUnlessTargetRedirected實施的 —— 若是沒有重定向標記,就退出;不然循環到loop標籤。
Webx框架:http://openwebx.org/ petstore:webx3/webx-sample/petstore/tags/3.0/petstore 編譯以後:mvn jetty:run便可, 訪問:http://localhost:8081/ Webx MVC(以webx3爲基礎) 一、webx3的入口點 <filter> <filter-name>webx</filter-name> <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class> </filter> <filter-mapping> <filter-name>webx</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> webx.xml:每一個webx應用,都須要有一個webx.xml配置文件。這個文件定義了Webx所用到的全部services的配置。 pipeline.xml:即管道,它是由一個或多個「閥門Valve」構成的。能夠看作webx框架的總控文件。 log4j.xml:日誌系統配置文件。對於程序的排錯相當重要。 典型的webx.xml配置: <?xml version="1.0" encoding="UTF-8" ?> <!-- Webx Root Context Configuration. --> <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:services="http://www.alibaba.com/schema/services" xmlns:request-contexts="http://www.alibaba.com/schema/services/request-contexts" xmlns:session-encoders="http://www.alibaba.com/schema/services/request-contexts/session/encoders" xmlns:model-encoders="http://www.alibaba.com/schema/services/request-contexts/session/model-encoders" xmlns:session-idgens="http://www.alibaba.com/schema/services/request-contexts/session/idgens" xmlns:session-stores="http://www.alibaba.com/schema/services/request-contexts/session/stores" xmlns:ml-adapters="http://www.alibaba.com/schema/services/module-loader/adapters" xmlns:ml-factories="http://www.alibaba.com/schema/services/module-loader/factories" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.alibaba.com/schema/services http://localhost:8080/schema/services.xsd http://www.alibaba.com/schema/services/request-contexts http://localhost:8080/schema/services-request-contexts.xsd http://www.alibaba.com/schema/services/request-contexts/session/encoders http://localhost:8080/schema/services-request-contexts-session-encoders.xsd http://www.alibaba.com/schema/services/request-contexts/session/idgens http://localhost:8080/schema/services-request-contexts-session-idgens.xsd http://www.alibaba.com/schema/services/request-contexts/session/stores http://localhost:8080/schema/services-request-contexts-session-stores.xsd http://www.alibaba.com/schema/services/request-contexts/session/model-encoders http://localhost:8080/schema/services-request-contexts-session-model-encoders.xsd http://www.alibaba.com/schema/services/module-loader/adapters http://localhost:8080/schema/services-module-loader-adapters.xsd http://www.alibaba.com/schema/services/module-loader/factories http://localhost:8080/schema/services-module-loader-factories.xsd http://www.springframework.org/schema/beans http://localhost:8080/schema/www.springframework.org/schema/beans/spring-beans.xsd "> <!-- 支持${xxx}替換。 --> <services:property-placeholder> <services:property key="component">common</services:property> </services:property-placeholder> <!-- 共享配置。 --> <beans:import resource="common/webx-component-and-root.xml" /> <!-- 異常管道。 --> <beans:import resource="common/pipeline-exception.xml" /> <!-- 資源裝載。 --> <beans:import resource="common/resources.xml" /> <!-- URI生成。 --> <beans:import resource="common/uris.xml" /> <!-- 綜合設置。 --> <services:webx-configuration> <!-- 默認將productionMode設爲true,建議在jetty插件中設置-DproductionMode=false。 --> <services:productionMode>${productionMode:true}</services:productionMode> <services:components defaultComponent="app1" /> </services:webx-configuration> <!-- 設置request/response/session。 --> <services:request-contexts xmlns="http://www.alibaba.com/schema/services/request-contexts"> <basic /> <buffered /> <lazy-commit /> <parser /> <set-locale defaultLocale="zh_CN" defaultCharset="UTF-8" /> <session> <id> <cookie path="/" maxAge="0" httpOnly="true" /> </id> <stores> <session-stores:cookie-store id="temporaryCookie"> <session-stores:cookie name="tmp" /> </session-stores:cookie-store> </stores> <store-mappings> <match name="*" store="temporaryCookie" /> </store-mappings> </session> </services:request-contexts> <!-- 支持上傳文件。 --> <services:upload sizeMax="5M" /> <!-- 將beans暴露給模板。這裏定義的tools可被全部components之間共享。 --> <services:pull xmlns="http://www.alibaba.com/schema/services/pull/factories"> <utils /> <page-tool /> <control-tool /> <uris-tool /> </services:pull> <!-- 裝載模塊。 --> <services:module-loader> <ml-factories:class-modules> <ml-factories:search-packages type="$1" packages="com.alibaba.webx.tutorial1.common.module.*" /> </ml-factories:class-modules> </services:module-loader> </beans:beans> 二、前端分析 全部和前臺展現有關的文件,即模板,放在templates目錄下,vm後綴的爲Velocity的模板 對應的java代碼 src/main/java/…/module。 Modules是基本編程模塊:包括screen,control,action Screen — 用來處理頁面顯示邏輯的module,主要功能就是顯示一個頁面 Control — 和screen相似,但能夠被別的screen或layout引用,甚至能夠跨越car應用 Action — 處理用戶提交表單的module Webx的頁面佈局以screen爲主導,經過screen來查找其他的頁面元素,而後經過一系列查找規則來查找頁面元素Screen和control均可以有java類來驅動,但不是必須的,也就是說能夠先寫模板,後寫類 ,也能夠只寫模板,不用構造對應類。 頁面佈局以下: 截圖 • Screen,表明頁面的主體。 • Layout,表明頁面的佈局。 • Control,表明嵌在screen和layout中的頁面片斷。 三、Webx執行的流程 可參考:http://qa.taobao.com/?p=7830,http://qa.taobao.com/?p=7604 用戶輸入URL: http://localhost:7001/petstore/user/login.htm 1)petstore稱爲Context Path。服務器把這個請求交給petstore應用來接管。 2) login.htm稱爲Servlet Path。在web.xml中把*.htm映射到Webx Controller Servlet,因此Webx Controller Servlet就接管了這個請求。 3) Webx Controller Servlet激活pipeline,繼而調用AnalyzeURLValve來分析/ login.htm是什麼意思。根據webx默認的映射規則,/ login.htm被轉換成/ login.vm。 分析URL取得target: /login.vm 根據target查找screen模板: /screen/login.vm 根據target查找screen模塊的類: com.alibaba.sample.petstore.web.user.module.screen.Login(找不到該類) com.alibaba.sample.petstore.web.user.module.screen.Default(找不到該類) com.alibaba.turbine.module.screen.TemplateScreen(默認screen類) 執行screen類,並渲染screen模板 根據target查找layout模板: /layout/login.vm(找不到) /layout/default.vm(找到) 渲染layout模板 渲染在layout模板中引用的兩個control: home:top.vm à 在home.car中查找/control/top.vm home:bottom.vm à 在home.car中查找/control/bottom.vm 四、配置文件分析 參考:http://qa.taobao.com/?p=12800 (1)Webx2 PoolToll 在velocity模板中常用到pulltool,這是一些工具類,方便咱們進行頁面輸出內容的控制,組織頁面的展現,或者是直接取得web層相關的 一些對象,直接在vm中調用。pull在概念上能夠形象的理解爲"拉動",是由頁面拉動業務邏輯,獲取並控制須要展現的內容,而非應用程序推進 (push),這很是符合webx的頁面驅動的模式。在頁面進行渲染時,pulltool對象已被預先建立好,並被放入TemplateContext 中,在渲染頁面時被調用並輸出所須要的內容。 pulltool是由PullService管理的,PullService將pulltool歸入了Service框架的範疇進行管理,理論上咱們能夠 將任意組件封裝爲一個pulltool,或者將任意代碼邏輯封裝在一個pulltool中,只要實現PullTool接口,這個類即可以被 PullService管理起來進而能夠在vm模板中直接使用,或者說,pulltool就是一些被PullService管理的組件,這些組件幫助咱們控制頁面上的內容。pulltool通常都會繼承一個抽象類PullToolSupport,這個類方便對PullTool進行配置與調用,它包含了一些 與PullTool的配置與初始化有關的邏輯,它的子類只須要專一於本身須要對外提供的方法便可。而PullService提供了一個自動組裝 TemplateContext的機制,經過這個機制,PullTool被put進TemplateContext,能夠在模板中被直接使用。 PullTool 有四種不一樣的做用範圍, Global - 全局做用域,此做用域內的tool僅在service被初始化時被建立一次,之後再也不改變 Request - 請求做用域,此做用域內的tool在每一個用戶請求到達時被建立 Session - 會話做用域,此做用域內的tool在會話的第一個請求到達時被建立,在整個會話期間再也不改變 Authorized - 驗證用戶做用域,此做用域內的tool在用戶被驗證以後建立,隨用戶的登出而消失 不一樣的做用域範圍表明了pulltool的生效範圍,global做用域的PullTool被放入一個全局的TemplateContext中(這個 Template的上下文只在PullService被初始化的時候被建立,只被建立這一次,做爲全局的TemplateContext來使用),其餘做 用域的PullTool都是在用戶請求以後建立的TemplateContext中有效,而每個顯示組件,如screens和controls,都將繼 承上述做用域中的tools,但不會相互覆蓋,即依舊在各自的做用域中生效。當screen等顯示組件所對應的模板被渲染時,調用pulltool的地方 就可以被調用了。 PullTool在Webx.xml文件中進行配置,將須要使用的pulltool做爲PullService的property,它們會做爲PullService的Configuration被讀取。如下是通常項目中經常使用到的一些pulltool的配置 <service name="PullService" class="com.alibaba.service.pull.DefaultPullService"> <property name="tool.global"> <property name="util" value="com.alibaba.service.pull.LangToolSet"/> <property name="viewTool" value="com.alibaba.intl.web.webx.pull.IntlViewPullTool"/> <property name="constantTool" value="com.alibaba.turbine.util.template.ConstantTool"/> </property> <property name="tool.request"> <property name="rundata" value="com.alibaba.turbine.util.template.RunDataTool"/> <property name="page" value="com.alibaba.turbine.util.template.HtmlPageAttributeTool"/> <property name="control" value="com.alibaba.turbine.util.template.ControlTool"/> <property name="uri" value="com.alibaba.service.uribroker.URIBrokerTool"/> <property name="form" value="com.alibaba.service.form.FormTool"/> <property name="webuser" value="com.alibaba.intl.web.webx.pull.WebUserPullTool"/> </property> </service> 全局做用域的pulltool $util,實現類是LangToolSet,它是一個pulltool的集合,包含了com.alibaba.lang包下的一系列基本工具類,如StreamUtil,StringEscapeUtil,StringUtil,ArrayUtil等,這些工具在vm模板裏可利用對應的變量名稱調用,因爲pulltool主要用來控制頁面顯示內容的,最經常使用的要數StringEscapeUtil,StringUtil。 StringUtil包含對字符串的處理函數,彷佛跟字符串判斷與字符串比較有關的功能這裏都有了,在vm裏經過$stringUtil變量調用須要的方法就能夠啦。 StringEscapeUtil,這個類的用途更大,它能夠方便的將字符串轉換成適應Java、JavaScript、HTML、XML、SQL、URL語句的形式,固然,在模板裏調用,對於HTML、JavaScript及URL的轉義確定是最多見的了。 對於頁面上要輸出的值,通常都須要進行html轉義,以防止要展現的字符串中包含html標籤或JavaScript腳本,使得顯示格式出錯甚至是存在攻擊腳本。使用$stringEscapeUtil.escapeHtml($變量名)便可調用相應轉義方法。 StringEscapeUtil類還包含了反向轉義的功能,即將轉義後的字符串還原爲原來的形式, StringEscapeUtil類提供了URL轉義的功能,將字符串按URL編碼規則轉換爲相應格式,即將一些字符轉換爲%XX的形式,如空格轉換爲%20。固然也有反向轉義的功能,對URL進行解碼。在進行URL編解碼時,須要注意所使用的編碼集,用不一樣的編碼集編解碼可能會獲得不一樣的輸出結果。在使用escapeURL()方法時能夠指定編碼集。 $viewTool,實現類是IntlViewPullTool,包含了不少國際站頁面輸出時經常使用的方法,方便國際站工程師在頁面上直接調用,避免重複開發,節省工做量。包括的方法有如下幾類 輸出值格式化,如formatDate(),formatInt(),getAdjustedString(),截取輸出值的一部分顯示,還有控制html轉義與輸出的一些方法。 業務邏輯相關的格式化,getCountryTimeZone(),encryptForAlitalk()等,爲了解決一些常見的展現需求,在頁面直接使用,方便快捷。 一些很通用的頁面輸出的控制邏輯,均可以抽取出來做爲pulltool工具來使用,提升開發效率。 request做用域的pulltool,在用戶提交請求時建立,能夠用來直接在vm中使用請求相關的一些對象 $page $control $rundata $webuser (2)Webx3 pooltool pullTool的配置 Webx3 PullTool的配置形式上發生了改變、採用的是Spring Xml Schema的配置方式、例子以下: <services:pull xmlns="http://www.alibaba.com/schema/services/pull/factories"> <!- Webx3 tools。 -> <utils /> <rundata-tool /> <csrfToken /> <form-tool /> <control-tool /> <uris-tool /> <!- Petstore tools。 -> <webx2-tool id="bundle" class="com.alibaba.sample.petstore.web.common.util.ResourceBundleTool" scope="global" /> <webx2-tool id="petstoreUser" class="com.alibaba.sample.petstore.web.common.util.PetstoreUserTool" scope="request" /> </services:pull> Webx3對PullTool的配置進行了簡化和封裝、可是若是缺乏文檔的話、上面的有些配置可能就不那麼容易理解 好比: <utils /> 這個標籤其實表示的是開發者能夠直接在Vm中使用com.alibaba.common.lang包下的一些工具類: 如ArrayUtil、StringUtil、SystemUtil等 其餘的幾個標籤相對容易理解、如:rundata-tool表明$rundata、csrfToken表明$csrfToken、uris-tool表示的是UriBrokerTool、 能夠在Vm使用Uribroker、另外webx2-tool標籤表示的是使用Web3的兼容模式集成Web2下自定義的PullTool,scope屬性表示的是 PullTool的做用級別 webx3下如何自定義一個PullTool Webx3下自定義或擴展一個PullTool要比Webx2容易且有多種方法: 一、實現ToolFactory、或者ToolSetFactory接口、實現了後者能夠建立一組pullTool 代碼示例: 接下來只要將該類配置一下便可使用 <factory id="sampleTool" class="com.alibaba.citrus.service.pull.tool.SampleTool" /> 二、採用Webx3提供的BeanTool BeanTool是能夠用於建立一個簡單bean的tool factory 你能夠將一個工具類或者簡單的Spring容器的Bean只需經過簡單的配置就能夠成爲一個PullTool, BeanTool內部使用AutowireCapableBeanFactory的initializeBean方法將指定的Class動態初始化一個 Bean並注入到Spring容器中、同時該Bean能夠做爲一個PullTool使用: 配置以下: <bean-tool id="sampleTool" class="com.alibaba.citrus.service.pull.tool.SampleTool" scope="global" /> 這種方式的好處: 1你能夠方便的將已有的一個工具類配置一下就能夠變成PullTool而不須要專門實現任何接口、去除了對原有類的沒必要要侵入, 2能夠將Spring容器的一個Bean做爲PullTool使用 (3)webx3中webx.xml中request context配置 <services:request-contexts xmlns="http://www.alibaba.com/schema/services/request-contexts"> <basic /> <buffered /> <lazy-commit /> <parser /> <set-locale defaultLocale="zh_CN" defaultCharset="UTF-8" /> <session> <id> <cookie path="/" maxAge="0" httpOnly="true" /> </id> <stores> <session-stores:cookie-store id="temporaryCookie"> <session-stores:cookie name="tmp" /> </session-stores:cookie-store> </stores> <store-mappings> <match name="*" store="temporaryCookie" /> </store-mappings> </session> </services:request-contexts>