Webx Turbine建立在Webx Framework的基础上,实现了页面渲染、布局、数据验证、数据提交等一系列工作。
Webx Turbine所遵循下面的设计理念包括:
页面驱动
约定胜于配置
页面布局:
Screen,代表页面的主体。
Layout,代表页面的布局。
Control,代表嵌在screen和layout中的页面片段
1.webx设计理念:
页面驱动:
在程序员介入以前,让界面设计师可以直接创建模板,并展示模板的效果。页面驱动的反面,是程序驱动,或者是Action驱动 —— 这是多数WEB框架的模式。
页面驱动提高了开发的效率,也使界面设计师在早期可以利用框架所提供的工具,做一些页面跳转、简单的表单验证、字符串操作等工作。这些工具是通过Webx Turbine中的一个服务来完成的:pull tools。
约定胜于配置:
“约定”即规则。规则是预先定义的,工程师只需要按着规则来做事,就不需要额外的“配置”。对比其它一些框架 —— 往往每增加一个页面,都需要在配置文件中增加若干行内容。Webx Turbine的规则主要是指一系列映射规则。
Webx Turbine映射规则
映射规则 | 说明 |
---|---|
将URL映射成target | target是一个抽象的概念,指明当前请求要完成的任务。Target由pipeline来解释,它可能被解释成模板名,也可能被解释成别的东西。 |
将target转换成模板名 | 模板用来展现页面的内容。Velocity、Freemarker、JSP都可以作为模板的格式,但在Webx建议使用velocity模板。 |
将target转换成layout布局 | 你可以为一组页面选择相同的布局(菜单、导航栏、版权信息等),为另一组页面选择另一种布局。 |
将target转换成module | 在Webx Turbine中,module是指screen、action、control等,大致相当于其它框架中的action或者controller。 |
工程师只需要根据上述规则,将模板放在指定的目录、按照预定的方式命名module(也就是screen、action、control等),就不再需要额外的配置。
2 页面布局
Webx Turbine的页面,由以下几个部分组成:
图 4.2. Webx Turbine页面的构成
其中:
- Screen,代表页面的主体。
- Layout,代表页面的布局。
- Control,代表嵌在screen和layout中的页面片段。
3. 处理页面的基本流程
Webx Turbine的处理流程被定义在pipeline中。Webx Framework没有规定Pipeline的内容,但Webx Turbine却定义了一系列valves。下面是一个Webx Turbine推荐的pipeline配置:
Webx Turbine推荐的pipeline配置 - pipeline.xml
<services:pipeline xmlns="http://www.alibaba.com/schema/services/pipeline/valves"> <!-- 初始化turbine rundata,并在pipelineContext中设置可能会用到的对象(如rundata、utils),以便valve取得。 --> <prepareForTurbine /> <!-- 设置日志系统的上下文,支持把当前请求的详情打印在日志中。 --> <setLoggingContext /> <!-- 分析URL,取得target。 --> <analyzeURL homepage="homepage" /> <!-- 检查csrf token,防止csrf攻击和重复提交。假如request和session中的token不匹配,则出错,或显示expired页面。 --> <checkCsrfToken /> <loop> <choose> <when> <!-- 执行带模板的screen,默认有layout。 --> <pl-conditions:target-extension-condition extension="null, vm, jsp" /> <performAction /> <performTemplateScreen /> <renderTemplate /> </when> <when> <!-- 执行不带模板的screen,默认无layout。 --> <pl-conditions:target-extension-condition extension="do" /> <performAction /> <performScreen /> </when> <otherwise> <!-- 将控制交还给servlet engine。 --> <exit /> </otherwise> </choose> <!-- 假如rundata.setRedirectTarget()被设置,则循环,否则退出循环。 --> <breakUnlessTargetRedirected /> </loop> </services:pipeline>
假设用户以URL:http://localhost:8081/
来访问Webx应用。域名和端口不重要,取决于应用服务器的配置,这里假设为localhost:8081
。Webx Framework的处理流程,从WebxFrameworkFilter
接收请求,并且一路顺利到达pipeline。然后Pipeline开始依次执行它的valves。(下面的描述略过一些相对次要的步骤。)
<analyzeURL>
- 分析URL分析URL的目的是取得target。由于用户访问的URL中并没有提供path信息,通常被理解为:用户想要访问“主页”。
AnalyzeURL
valve提供了一个可选的参数“homepage
”,即是在这种情况下起作用 ——http://localhost:8081/
对应的target为“homepage
”。需要注意的是,target不代表模板名,也不代表类名。Target只是一个抽象的概念 —— 当前页面需要达成的目标。Target可能被后续的valves解释成模板名、类名或者其它东西。
- 进入
<choose>
- 多重分支很明显,“
homepage
”满足了第一个<when>
所附带的条件:<target-extension-condition extension="null, vm, jsp">
,意思是target的后缀不存在(null
)或为“jsp
”或为“vm
”。 <performAction>
- 执行action和其它框架中的action概念不同,在Webx Turbine中,action是用来处理用户提交的表单的。
因为本次请求未提供action参数,所以跳过该步骤。
<performTemplateScreen>
- 查找并执行screen。这里要用到一个规则:target映射成screen module类名的规则。
假设target为
xxx/yyy/zzz
,那么Webx Turbine会依次查找下面的screen模块:screen.xxx.yyy.Zzz
,screen.xxx.yyy.Default
,screen.xxx.Default
,screen.Default
。
本次请求的target为
homepage
,因此它会尝试查找screen.Homepage
和screen.Default
这两个类。如果找到screen类,Webx Turbine就会执行它。Screen类的功能,通常是读取数据库,然后把模板所需要的对象放到context中。
如果找不到,也没关系 —— 这就是“页面优先”:像
homepage
这样的主页,通常没有业务逻辑,因此不需要screen类,只需要有模板就可以了。<renderTemplate>
- 渲染模板这里用到两个规则:target映射成screen template,以及target映射成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模板中。
Layout模板和screen模板中,都可以调用control。每个页面只有一个screen,却可以有任意多个controls。
<breakUnlessTargetRedirected>
- 内部重定向在screen和action中,可以进行“内部重定向”。内部重定向实质上就是由
<breakUnlessTargetRedirected>
实施的 —— 如果没有重定向标记,就退出;否则循环到<loop>
标签。和外部重定向不同,外部重定向是向浏览器返回一个
302
或303
response,其中包含Location
header,浏览器看到这样的response以后,就会发出第二个请求。而内部重定向发生在pipeline内部,浏览器并不了解内部重定向。
4 依赖注入
Spring原生注入手段
依赖注入是Spring的重要特性,Webx既然建立在Spring基础上,支持Spring原有的依赖注入手段,例如,可以在Screen/control/action module类中这样写:
通过@Autowired
annotation注入(UserManager
是在spring context中配置的bean)
public class LoginAction { @Autowired private UserManager userManager; ... }
在使用Spring原生注入手段时,需要注意beans的scope。你只能注入相同scope或较大的scope中的bean。例如,screen/action/control的scope为singleton,因此用@Autowired
注入时,只能注入singleton的对象,不能注入诸如request、session等较小的scope对象。
注入request、response和session对象
在Webx Framework中,你可以这样做:
注入request、response和session对象
public class LoginAction { @Autowired private HttpServletRequest request; @Autowired private HttpServletResponse response; @Autowired private HttpSession session; ... }
虽说不能把request scope的对象,注入到singleton scope的对象中。但在Webx中,可以将HttpServletRequest
、HttpServletResponse
和HttpSession
对象注入到singleton对象中,原因是<request-contexts>
对这几个常用对象进行了特殊处理,将它们转化成了singleton对象。
参数注入
有一些对象,是无法通过Spring的bean来注入的,例如:用户提交的参数、表单等。好在Webx Turbine提供了一种可扩展的机制(DataResolver
service),通过它,我们可以在screen/control/action的方法中注入任意对象。
参数注入
功能 | 代码示例 | 适用于module类型 |
---|---|---|
注入一个query参数 |
void doGetInt(@Param("aaa") int i) |
screen、 action、 control |
将query参数注入bean properties |
void doSetData(@Params MyData data) |
screen、 action、 control |
注入框架对象 |
void doGetNavigator(Navigator nav) |
screen、 action |
void doGetContext(Context context) |
screen、 action、 control | |
void execute(ControlParameters params) |
control | |
注入context和control参数 |
void execute(@ContextValue("myvalue") int value) |
screen、 action、 control |
注入表单对象 |
void doGetGroup(@FormGroup("myGroup1") Group group) |
action |
void doGetGroups(@FormGroups("myGroup1") Group[] groups) |
action | |
将表单值注入bean properties |
void doGetGroupsBeans(@FormGroups("myGroup1") MyData[] data) |
action |
5. 定制Webx Turbine
通过改进pipeline中的valves改变webx turbine的行为。
最常见的一种需求,是要对页面进行授权 —— 只有符合条件的用户才能访问相应的页面。在pipeline中,很容易添加这样的逻辑:
改进pipeline,增加页面授权功能 - pipeline.xml,
插入用于验证权限的valve。
<services:pipeline xmlns="http://www.alibaba.com/schema/services/pipeline/valves"> <prepareForTurbine /> <setLoggingContext /> <analyzeURL homepage="homepage" /> <checkCsrfToken /> <valve class="com.mycompany.auth.PageAuthorizationValve" /> ... </services:pipeline>
甚至可以重写整个pipeline,以实现另一种风格的WEB框架。
Webx Turbine建立在pipeline的基础上,基于页面驱动和约定胜于配置的理念,定义了一组处理页面的流程。Webx Turbine的灵活性在于,你可以轻易定制pipeline,以改变它的任何一个方面。
http://blog.csdn.net/hollis_chuang/article/details/41120839