原文连接:http://blog.sina.com.cn/s/blog_628cc2b70102v115.htmlcss
1、Webx的层次结构(从里到外)html
(1)SpringExt:基于Spring,提供扩展组件的能力java
(2)Webx Framework:基于Servlet API,提供基础服务web
(3)Webx Turbine:基于Webx Framework,实现具体的网页功能数据库
2、Webx的初始化缓存
位置:/WEB-INF/web.xml文件服务器
<!-- Loading /WEB-INF/webx.xml, /WEB-INF/webx-*.xml --> <listener> <listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class> </listener>
结果:自动搜索/WEB-INF目录下的XML配置文件,并建立级联的Spring容器。cookie
/WEB-INF/webx.xml->/WEB-INF/web-app1.xml->/WEB-INF/webx-app2.xmlsession
3、初始化日志系统app
添加方式:
<!-- Logger --> <listener> <listener-class>com.alibaba.citrus.logconfig.LogConfiguratorListener</listener-class> </listener>
4、Webx响应请求
Webx响应请求的流程:
(1)WebxFrameworkFilter接收请求
(2)WebxRootController建立和处理request context,路由到子应用,并提供处理异常、开发模式功能。
(3)WebxController进行apps' pipeline
当一个HTTP请求到达时,WebxFrameworkFilter接收请求的模板配置(/WEB-INF/webx.xml)以下:
<filter> <filter-name>webx</filter-name> <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class> <init-param> <!--排除URL,以逗号隔开--> <param-name>excludes</param-name> <param-value>*.css, *.js, *.jpg, *.gif, *.png, *.jpeg,/sendBucSSOToken,/bucSSOLogout</param-value> </init-param> </filter> <filter-mapping> <filter-name>webx</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
为何使用filter而不是servlet?若是webx发现某个请求不该该由webx来处理,就会把控制“返还”给原来的控制器,而Servlet不具有“返还控制”的机制。
RequestContext对象的标准模板以下:
<!-- 当接受到请求后,从新设置request/response/session。 --> <services:request-contexts xmlns="http://www.alibaba.com/schema/services/request-contexts"> <rewrite> <rule pattern=".*\.htm"> <substitution uri="$0" flags="L,QSA" /> </rule> <rule pattern=".*"> <substitution flags="L,QSA" /> <handlers> <!--执行RestfuleUrlRewriter类设置request/response/session--> <rewrite-handlers:handler class="com.alibaba.dubbo.governance.web.common.interceptor.RestfuleUrlRewriter" /> </handlers> </rule> </rewrite> <basic /> <buffered /> <lazy-commit /> <parser /> <!--设置request/response/session编码--> <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>
5、Webx Turbine
它的基本准则是:约定胜于配置,即:工程师只须要根据必定的规则,将模板放在指定的目录、按照预约的方式命令module(也就是screen、action、control等),就再也不须要额外的配置。
Turbine的基本页面组成为:
(1)Screen:表明页面的主体
(2)Layout:表明页面的布局
(3)Control:表明嵌在screen和layout中的页面片断
页面布局图以下:
6、Webx Turbine处理页面的基本流程
Webx Turbine的处理流程被定义在pipeline中,pipeline推荐的配置以下:
<services:pipeline xmlns="http://www.alibaba.com/schema/services/pipeline/valves"> <!-- 初始化turbine rundata,并在pipelineContext中设置可能会用到的对象(如rundata、utils),以便valve取得。 --> <prepareForTurbine /> <!-- 设置日志系统的上下文,支持把当前请求的详情打印在日志中。 --> <setLoggingContext /> <!-- 分析URL,取得target。 --> <analyzeURL /> <!-- 检查csrf token,防止csrf攻击和重复提交。假如request和session中的token不匹配,则出错,或显示expired页面。 --> <checkCsrfToken /> <!-- 拦击器做用 --> <!-- 设置语言:显示本地语言和风格的页面 --> <valve class="com.alibaba.dubbo.governance.web.common.interceptor.LocaleValve" /> <choose> <when> <pl-conditions:path-condition name="^/servicestatus/.+|^/status$|/favicon.ico|/sysinfo/dump.htm" /> </when> <otherwise> <!-- 页面受权:根据登陆用户的权限,阻止或许可用户访问特定的页面。--> <valve class="com.alibaba.dubbo.governance.web.common.interceptor.AuthorizationValve" /> </otherwise> </choose> <loop> <choose> <when> <!-- 执行不带模板的screen,默认无layout。 --> <pl-conditions:path-condition name="/sysinfo/dump.htm|^/\w+$|^/status/.+$" /> <performTemplateScreen /> </when> <when> <!-- 执行带模板的screen,默认有layout。 --> <pl-conditions:target-extension-condition extension="null, vm, jsp, html" /> <!--执行action--> <performAction /> <!-- 执行screen--> <performTemplateScreen /> <!--渲染模板--> <renderTemplate /> </when> <otherwise> <!--把控制权还给servlet engine--> <exit /> </otherwise> </choose> <!-- 假如rundata.setRedirectTarget()被设置,则循环,不然退出循环。 --> <breakUnlessTargetRedirected /> </loop> </services:pipeline>
流程具体解读以下:
(1) 分析URL::用户访问的主页target
(2) 进入choose,进行多重分支选择
(3)performAction执行action
(4) performTemplateScreen查找并执行screen
假设target为xxx/yyy/zzz,那么Webx Turbine查找screen模块的顺序为:
Screen.xxx.yyy.zzz
Screen.xxx.yyy.Default
Screen.xxx.Default
Screen.Default
(5) 渲染模板
首先映射成screen template,以及映射成layout template
假设target为xxx/yyy/zzz,那么Webx Turbine会查找下面的screen模板:/templates/screen/xxx/yyy/zzz。Screen模板若是未找到,就会报404 Not Found错误。 找到screen模板之后,Webx Turbine还会试着查找下面的layout模板:
/templates/layout/xxx/yyy/zzz
/templates/layout/xxx/yyy/default
/templates/layout/xxx/default
/templates/layout/default
Layout模板若是找不到,就直接渲染screen模板;若是存在,则把渲染screen模板后的结果嵌入到layout模板中。
7、Filter的用途
页面受权:根据登陆用户的权限,阻止或许可用户访问特定的页面。
日志和审计:记录和检查用户访问WEB应用的状况。
图片转换:改变图片的格式、精度、尺寸等。
页面压缩:压缩页面内容,加快下载速度。
本地化:显示本地语言和风格的页面。
XSLT转换:对XML内容进行XSLT转换,使之适用于多种客户端。
高速缓存:高速缓存页面,提升响应速度。
Webx提供了Request Contexts服务以及Pipeline做为对Filter功能缺陷的补充,做用分别以下:
(1) Request Contexts:负责访问和修改request和response,但不负责改变应用执行的流程
(2) Pipeline:提供应用执行的流程,但不关心和request和response
8、Spring中依赖注入的限制
小做用域的对象不能被注入到大做用域的对象。你不能把request和response做用域的对象注入到singleton对象中。前者在每次WEB请求时,均会建立新的实例,每一个线程独享这个request/session做用域的对象;后者是在Spring初始化或第一次使用时被建立,而后被全部的线程共享。假如把某个request/session做用域的对象意外注入到singleton对象中,将可能产生致命的应用错误,甚至致使数据库的错乱。
在Webx中,这样作是能够的!奥秘在于Request Contexts服务对上表所列的这些短时间对象做了特殊的处理,使它们能够被注入到singleton对象中。事实上,被注入的只是一个“空壳”,真正的对象是在被访问到的时候才会从线程中取得的。
9、buffered缓存response中内存的实现原理
Webx支持用layout/screen/control等部件共同构成一个页面。其中,每一个layout可包含一个screen和多个control,每一个screen可包含多个control,每一个control还能够在包含其余的control。
通常页面好比经过out.println("
hello world
");就直接输出了,为了还能分开而后再一块儿显示呢。例如,一个screen中包含了一个control,那么screen能够得到它所调用的control的完整的渲染内容。
这个玄机就是靠来实现的。改变了response的输出流,包括output stream和writer,使写到输出流中的内容被暂存在内存中。当须要时,能够取得缓存中的全部内容。
Buffered机制会延迟服务器对用户的响应,因此某些场景须要关闭该服务。
10、表单验证的模板
该文件form.xml位于WEB-INF的每一个子目录中,用于表单的验证
11、Eclipse中开发Webx应用
(1)Webx工程目录结构
src\main:存放开发代码
src\test:存放开发自测代码,如单元测试代码
main\java:存放java代码
main\resources:存放资源定义文件
main\webapp:web应用配置文件
webapp目录包含(举例):
1)子应用模板目录admin、home、store、user,每一个模板目录又由layout、control、screen三个子目录组成,包含对应的模板文件(.vm文件)
2)通用模板目录common
3)WEB-INF目录
这是java web应用必备的配置目录,包含了web.xml(java web应用必备的配置文件)、webx.xml(webx配置文件)、日志配置文件(log4j.xml、logback.xml)、子应用配置文件(webx-admin.xml、webx-home.xml、webx-store.xml、webx-user.xml);另外还有对应每一个子应用的文件夹,用于存放form定义文件(form.xml)和访问权限定义文件(access.xml);common文件夹中的pipeline.xml和pipeline-exception.xml定义了相关的管道操做流程。
(2)页面获取JAVA层的数据PullTool
在velocity模板中使用pulltool方便咱们进行页面输出内容的控制,组织页面的展现,或者是直接取得web层相关的一些对象,直接在vm中调用。由页面拉动业务逻辑,获取并控制须要展现的内容,而非应用程序推进push,这符合webx的页面驱动的模式。
1)是否启动pull服务:
在webx.xml文件中进行总的控制
2)指定获取数据的JAVA处理模块
指定了获取的数据位于com.xx.web.ui.module.*
3)在/xx/templates/screen下建立testMain.vm(M须要大写)文件,内容以下:
4)在/src/main/java/com/web/ui/module/screen下建立文件TestMain.java(webx会自动匹配同名的文件),内容以下:
package com.yunos.tv.openbase.web.ui.module.screen;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.citrus.turbine.Context;
public class TestMain {
public void execute(HttpServletRequest request, HttpServletResponse response, Context context) throws Exception{
context.put("name", "Hugh");
}
}
execute方法就是专门用来处理对应请求的,是webx潜规则的地方,它是页面渲染以前处理的方法。
有些参数为:public void execute(@Param("systemVersion") String systemVersion,HttpServletRequest request, HttpServletResponse response, Context context, Navigator nav),说明以下:第一个参数为传进来的信息,context对象负责页面渲染时部分数据的修改。
(2)实现form表单功能
实现用户帐号登录的功能,若是用户不输入则提示用户输入相关信息,效果以下:
其具体代码以下:
login.vm文件:
关键点说明以下:
这表示提交以后执行的是LoginAction.java,这里的value值login_action在程序内部会被处理成 LoginAction,所以这里若是写成value="LoginAction",结果是同样的
这里提交后表示执行的方法是doUserInfoSumbit方法,若是你要执行其余方法请修改name值name="event_submit_你的方法"
3.关联form.xml:首先 #set ($group = $form.loginInfoGroup.defaultInstance)[固定写法,loginInfoGroup对应form.xml中的services:group name="loginInfoGroup"],而后
name对应到form.xml中的规则,group.username.message就是须要显示的错误信息。
4.$csrfToken.hiddenField是必需要添加的,防止跨站请求伪造攻击。若是不添加的话,数据是不会从显示层传送给JAVA层的。
(3)实现form表单往JAVA层传送数据功能
一、构造与表单对应的类LoginInfo:
package com.yunos.tv.openbase.biz.dataobject;
public class LoginInfo {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
、1q 其中username和password的值须要和form.xml中定义的保持一致,不然二者没法创建联系。
(2) 2.编辑业务功能LoginAction.java:
import com.alibaba.citrus.turbine.dataresolver.FormGroup;
import com.yunos.tv.openbase.biz.dataobject.LoginInfo;
public class LoginAction {
public void doUserInfoSumbit(@FormGroup("loginInfoGroup")LoginInfo userLoginInfo, HttpServletResponse response, Context context, Navigator nav) throws Exception{
System.out.println("hello");
System.out.println(userLoginInfo.getUsername());
3.
3.若是数据模型LoginInfo和LoginAction不在同一个工程中,则LoginAction应该探测不到LoginInfo.class,须要LoginInfo先编译生成class文件,而后LoginAction才可使用LoginInfo类。在LoginInfo所在的工程使用mvn clean install命令从新进行编译,而后在LoginAction刷新下引入该类。