配置对应环境,运行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>