??xml version="1.0" encoding="utf-8" standalone="yes"?>
1. 识别contextPath
tpl模板中的所有资源相x{N?x)自动拼接Web应用的contextPath, 例如当contextPath=myApp?br />
<script src="/a.js"></script> 最l输?<script src="/myApp/a.js" ...>
2. 识别重复装蝲
<script src="a.js" tpl:once="true"></script>
tpl:once属性将保证在页面中script标签实际只会(x)出现一?
3. 识别lg内相对\?br />
开发Weblg?我们希望所有资源文仉应该相对lg目录q行定位,但是直接输出?lt;script>{标{N是相对于最l的调用链接q行相对路径定位? 例如在page1.jsp中调用了lgA, 在组件A的实C, 输出?lt;script src="my_control.js"></script>
我们的意图一般是相对于组件A的实现文件进行定? 而不是相对于page1.jspq行定位. tpl模板引擎的相对\径解析规则ؓ(f)永远相对于当前文件进行定? 例如
<c:include src="sub.tpl" />
在sub.tpl中的所有相对\径都相对于sub.tpl文gq行定位.
4. ~译期文件有效性检?br />
在编译期, tpl引擎?x)检查所有引入的资源文g的有效? 如果发现资源文g丢失, 直接抛出异? q样׃用等CU后才发现文件命名已修改{问?
5. ~存控制
览器缺省会(x)~存css, js{文? 因此pȝ上线后如果修改资源文件可能会(x)造成与客L(fng)~存不一致的情况. 一个简单的处理方式是每ơ生成资源链接的时候都拼接文g的修Ҏ(gu)期或者版本号, q样既可利用客户端缓? 又可以保证L使用最新版? 例如
<script src="a.js"></script>会(x)输出 <script src="/myApp/myModule/a.js?344566" ...>
6. 字符集选择
Z化国际化处理, 一般提倡的最?jng)_跉|式是坚持使用UTF-8~码. 但是很多情况下可能用系l内|的GBK~码?x)更加方便一? 另外集成一些既有代码时也存在着不同字符集的问题. 在Witrixq_? 所有输出的资源标签都会(x)标明对应的字W集, 如果没有明确讄取pȝ参数中的~省字符?
例如 <script src="a.js"></script> 会(x)输出 <script ... charset="GBK"></script>
7. ~省theme支持
Z支持多种面风格, 往往不是单的替换css文g卛_实现? 它可能意味着整个lg的实C码的更换. Witrixq_中通过一pd~省判断来简化这一q程. 例如如下代码表明如果讄了ui_themepȝ参数, q且对应的特D实现存? 则用特D实? 否则pȝ~省实现.
<c:include src="${cp:ui_theme()}/ctl_my_ctl.tpl" >
<c:include src="default/ctl_my_ctl.tpl" />
</c:include>
]]>
[spring对象?Ҏ(gu)名]q种映射Ҏ(gu)比基于正则字W串匚w的方式要单明的多。spring容器本n已经实现了对象的全局理功能Qspring对象名称必然是唯一的,公开发布的,怺之间不冲H的Q没有必要再通过匚wq算重新发现出它的唯一性?br /> 对于一些确实存在的横切需求,我们可以通过Annotation机制来实现切点坐标标定,复杂的切点匚w问题重新划归为[对象?Ҏ(gu)名]?br />
针对以上对象Q在app.aop.xml文g中可以定?/p>
以上q些需求往往是系l中最易变的部? 而它们在概念上恰恰表Cؓ(f)对CRUD的一U限制性描q? 因此通过如下扩展我们可以定义BizFlow的概? BizFlow = CRUD + Filter. Ҏ(gu)q种观念, witrixq_中BizFlow被实Cؓ(f)DaoWebAction的一U无~扩?
在jsplet框架中我们通过如下url模式来访问后台的CRUD操作:
/list.jsp?objectName=MyObj&objectEvent=Query
Z实现BizFlow只需通过spring为DaoWebAction配置一个xml配置文g, 此后仍然可以通过
/list.jsp?objectName=MyObj&objectEvent=Query
来访问后台的CRUD操作,只是后台?x)自动应用配|文件中?bizId="default", bizActionId="Query-default"{配|项.
如果我们采用如下url来访?br /> /list.jsp?objectName=MyObj&objectEvent=Query&$bizId=test&$bizActionId=test
则后台将应用配置?bizId=manage, bizActionId=Query-test, ?br /> /list.jsp?objectName=MyObj&objectEvent=BizAction&$bizId=test&$bizActionId=test
则对应于配置?bizId=manage, bizActionId=BizAction-test.
应用BizFlow配置之?所有前C码都可以不做ZQ何改? 因ؓ(f)它们只是对于l定数据的展?
BizFlow可以看作是CRUD加上单的程控制和权限控制所构成, 但是它与完整的工作流模型q是有着显著区别? 工作中所x的重炚w先是程实例而不是业务对象实? 在一个流E中是否存在唯一的业务对?以及(qing)业务对象的状态是否随着程{发生变化完全是一件独立的事情,它们q不属于抽象的工作流模型本n. 理论上说,一个业务对象可以同时参与多个流E? 在工作流建模中主要通过程步骤的先后顺序的U束来描qC务进E? 处于同一状态的业务对象可能处在不同的流E步骤中. 而BizFlow可以看作是状态驱动的, 当前业务步骤直接׃务对象的状态决? 在BizFlow中因角是业务对象的状?因此我们直接面对的是大量处于同一状态的不同的业务处理过E? 而workflow中往往建模的时候强调单程实例视角,而一般缺乏对于流E实例相x的描述. 现在国内很多为工作流是状态机其实是对workflow概念的一U误?
html <--> tpl <--> java
? 意到q里html与tpl之间Q以?qing)tpl与java之间的映都不是trivial的同构关p,而是都可能存在着复杂的运过E,从而实Chtml? java映射q程中复杂性的分解与均摊。tpl与java之间的关联主要通过EL(expression language)表达式来完成Q而html与tpl的映则主要通过自定义标{?tag)机制?br> 注意到tpl所提供的中间层h独立的重大意 义,它ƈ不是臆造的或者是单的技术驱动的l果。实际上Q在web开发中除了javal构与htmll构之外q存在着W三U结构,即用L(fng)中的界面l构Q? 本来它与html所描述的结构是单的一一对应的,但是随着界面技术的发展Qhtml的描q能力逐渐被耗尽Q成Zinternet时代?汇编语言"? 现在一个简单的面片断可能对应着大量html代码Q因而׃"所写即所?的简单性。tpl通过强大的抽象能力在某种E度上恢复了E序员对于界面表 现结构的直观控制能力Qƈ在一定程度上保留了html所见即所得的Ҏ(gu)?/p>
在witrixq_中因为存在着tplq一强大的抽象层Q得我们对于ajax的支持可以采取更加灵zȝ方式?br>
ajax(Asynchronous JavaScript + XML)的标准结构是
html <--> js <==> xml <==> java
? q种l构中通过xml信道的只是数据,而界面的表达逻辑与展现逻辑完全由js来控制。这U结构发展的一个极端是所有的界面展现l构都由 javascript动态构造出来,而完全׃html静态描q的特点,丧失了所见即所得的设计。与直接实现html<-->java之间 的映情늱|直接实现 html <--> js之间的映也是困隄Q尽dom模型的支持可能得js映射的难度要低于java映射?/p>
在witrixq_中ajax的方案ؓ(f)
html <--> js <==> tpl <--> java
即tpl取代了ajax标准Ҏ(gu)中xml的位|,使得映射q程的复杂性得以分散化?/p>
l合jsplet框架的拉模式Qpull mode)Q我们定义了如下ajax讉K接口
js.ajax.load({request='objectName=/@Test&objectEvent=query',tpl:'/test.tpl:partA',targetId:'testDiv'});
1?q程服务h是一D|通的http post requestQ?避免了额外的xml~码解码需求?br> 2。请求到的数据先由tpl文g来进行处理。注意到q里tpl文g的url分成两部分,前一部分是tpl文g的虚拟\径,?Q后面的部分Q即partA指出h的是该tpl文g内的partA部分Q而不是整个tpl文g?br> 3。返回的htmll果被填充到targetId所指定的html元素中?/p>
test.tpl文g的内?br> QhtmlQ?br> QbodyQ?/p>
Qtpl:define id="partA"Q?br> Qimg tpl:tag="ui:EditTable" /Q?br> Q?tpl:defineQ?/p>
Qdiv id="testDiv"Q?br> Qimg tpl:tag="ui:ViewTable" /Q?br> Q?divQ?/p>
Q?bodyQ?br>
Q?htmlQ?/p>
tplh强大的结构构造能力,在这里我们以非常的代h(hun)实现了tpl片断的定义,例如test.tpl中的partA部分。这里通过id讉Ktpl片断如同js中通过id来访问html片断一栗?br>
最后提一个很重要的思想Q大量零的代码片断需要集中存放,否则人的_֊?x)被耗散。一个反例就是struts中的action, 明明只干那么点事Q偏偏要占据一个单独的java文gQ占据大量单独的配置条目Q最l给E序员带来很大的困扰?img src ="http://m.tkk7.com/canonical/aggbug/32013.html" width = "1" height = "1" />
FreeMarker是一U流 行的文本模板语言Q其语法cM于xml tagQ但是命名规则不同。这实在是一Uo(h)解的设计。有意思的是,我们发现tpl的功能集也包含了FreeMarker的功能集。这实际上表明了一? 事情Qxml动态标{֭在一些必然的功能需求,无论是jsp tag, FreeMarkerq是tpl, 所不同的只是表现Ş式而已。但q种表现形式的差异却又造成了实际功能上的巨大差异?
tpl与FreeMarker具体Ҏ(gu)如下?
宏定?br>Q?macro greet personQ?br>Qfont size="+2"QHello ${person}Q?fontQ?br>Q?#macroQ]]Q?/p>
Qc:lib namespace="test"Q?br>Qgreet demandArgs="person"Q?br>Qfont size="+2"QHello ${person}Q?fontQ?br>Q?greetQ?br>Q?c:libQ?/p>
tplh更加强大的变量域控制手段Q可以通过importVars参数来指定是否用调用环境中的变量作为缺省参数。另一斚wQtplh更加灉|的参数校验规则,可以通过demandArgs, otherArgs{参数来指定对自定义标签参数的校验规则?
调用?br>Q@greet person="Fred" /Q?
Qtest:greet person="Fred" /Q?/p>
嵌套内容
Q?macro borderQ?br>Qtable border="4" cellspacing="0" cellpadding="4"Q<trQ<tdQ?br>Q?nestedQ?br>Q?nestedQ?
Q?trQ</tdQ</tableQ?br>Q?#macroQ?
Qc:lib namespace="test"Q?br>Qborder type="bodyTag"Q?br>Qtable border="4" cellspacing="0" cellpadding="4"Q<trQ<tdQ?br>Qcp:compile src="${tagBody}" /Q?br>Q?trQ</tdQ</tableQ?br>Q?borderQ?br>Q?c:libQ?/p>
tpl的<cp:compileQ指令在执行时可以指定xslt参数Q从而在~译tagBody之前应用xslt变换?
复杂嵌套
与FreeMark一?嵌套内容可以是复杂内?/p>
Q@borderQ?br>QulQ?br>Q@do_thriceQ?br>QliQ<@greet person="Joe"/Q?br>Q?a>/@do_thriceQ?br>Q?ulQ?br>Q?a>/@borderQ?
Qtest:borderQ?br>QulQ?br>Qtest:do_thriceQ?br>QliQ<test:greet person="Joe" /Q</liQ?br>Q?test:do_thriceQ?br>Q?ulQ?br>Q?test:borderQ?/p>
导入?br>Q?import "/lib/my_test.ftl" as myQ?
Qc:lib src="/lib/my_test.ftl" namespace="my" /Q?/p>
创徏或替代变?br>Q?assign mail="jsmith@other.com" /Q?
Qc:set var="mail" value="jsmith@other.com" default="xx"/Q?/p>
判断
Q?if animals.python.price Q?animals.elephant.priceQ?br>Pythons are cheaper than elephants today.
Q?#ifQ?
Qc:if test="${lt(animals.python.price,animals.elephant.price)}"Q?br>Pythons are cheaper than elephants today.
Q?c:ifQ?/p>
tpl因ؓ(f)是xml语法Q算术操作符Q和Q必{义后才能使用Q用v来很不方便,因而最l决定tpl不支持操作符Q通过lt(), gt(){函数来实现功能?
循环
Q?list animals as beingQ?br>QtrQ<tdQ?{being.name}QtdQ?{being.price} Euros
Q?#listQ?
Qc:forEach var="being" items="${animals}" Q?br>QtrQ<tdQ?{being.name}QtdQ?{being.price} Euros
Q?c:forEachQ?/p>
tpl提供Qc:tileQ等多种循环方式
include指o(h)
Q?include "/copyright_footer.html"Q?
Qc:include src="/copyright_footer.html" /Q?/p>
tpl强大的模板功能加上jsplet框架面向对象的能力,使得我们可以L的封装复杂的界面lg。而且q种装能力q不需要Tapestry那种复杂的配|文件。tpl对portal应用的支持也是一个自然的发展q程?/p>
Q后来看到Bruce Eckel的文?a >Does Java need Checked ExceptionQ发现大家在对待checked exception的态度上倒是心有戚戚焉。)
一般用自定义的异常类g是要类名作为错误返回码使用Q利用java~译器可以做所谓的强类型检查,q实在是一U概念上的浪贏V毕竟创建ƈl护一? javac还是有一定的代h(hun)的,特别是错误码l常变动而且数量不菲。实际上Qjavacd的设计中也是量重用已有的异常类Q例如整个jdbc包只抛出 SQLException异常Qxml包只抛出SAXException异常?/p>
使用异常Q常见的Ҏ(gu)是抛Z个字W串消息Q例?throw new
MyException("the object manager does not contains the object :" +
objectName);
q种做法的主要问题是Q字W串异常消息无法q行q一步的处理Q因而只能直接显C给最l用Pq一斚w限制了错误显C的格式和方式,另一斚w也不利于E序的多语言支持?br>
witrixq_中抛出异常的标准Ҏ(gu)?
throw Exceptions.code(errorCode).param(paramValue).param(paramName,paramValue);
例如
throw Exceptions.code("web.CAN_err_missing_object_in_manager").param(objectName).param(objectManager);
class Exceptions{
public static CommonException code(String errorCode){
return new CommonException(code);
}
}
class CommonException extends RuntimeException{
public CommonException param(Object paramValue){
...
return this;
}
}
Exceptions规定只用规范格式的错误码而不是Q意格式的异常消息。这样在捕获异常之后Q就可以Ҏ(gu)错误码和当时的语aLocale讄来决定最l显C的消息格式?br>
同时CommonException采用式设计来支持Q意数量的自定义参数。这一斚w减少了自定义异常cȝ需求,另一斚w也避免了参C错误码合的們Q即我们׃?x)們?
使用 throw Exceptions.code("the object manager does not contains the object :" + objectName);
注意到^面表l构只具有一个可延展的维度,而join可以看作是该l度上的q接操作。因此我们可以将交叉表看作是多个单^面表l构q置的结果。即分解?br>
A:
productA
districtA sellNum
districtB sellNum
B:
productB
districtA sellNum
districtB sellNum
横向l度的扩展在E序中表达?/p>
SqlInfol构装了这U简单^面表的分解片断?br>
class SqlInfo{
List fieldNames;
SQL sql;
String keyField;
}
我们在程序中通过JoinBuilder来实现横向维度的构?br>
JoinBuilder.begin(sqlInfoA)
.join(sqlInfB)
.leftJoin(sqlInfoC)
.end();
生成的sql语句CZ如下
select sqlInfoA.fieldNames, sqlInfoB.fieldNames
from sqlInfoA.sql join sqlInfoB.sql
on sqlInfoA.keyField = sqlInfoB.keyField
public Object process(ITableVisitor visitor){
Pager pager = new Pager(viewer, pageSize);
Iterator it = pager.itemIterator();
visitor.visitBegin(headers);
while(it.hasNext()){
Object row = it.next();
if(!visitor.visitRow(row))
break;
}
return visitor.visitEnd();
}
}
interface ITableVisitor{
void visitBegin(List headers);
boolean visitRow(Object row);
Object visitEnd();
}
Tree׃部分l成: 属性,| 子节?/p>
class TreeNode implements IVariant{
List getChildren();
int getChildCount();
TreeNode child(int index);
/** 当name对应的节点不存在时将?x)自动创节?*/
TreeNode child(String name);
/** 当name对应的节点不存在时返回null */
TreeNode existingChild(String name);
Map getAttributes();
IVariant attribute(String name);
void setAttribute(String name, Object attrValue);
}
TreeNode.attribute(name)q回的是IVariant接口Q例?br>
boolean defaultValue = true;
boolean b = node.child("subA").attribute("attrB").booleanValue(defaultValue);
TreeNode本n也是IVariant接口的一个实?例如
int i = ode.intValue();
2. 抽象能力
获得抽象能力Q首要的一Ҏ(gu)使得创徏新概늚成本极低。很有人大量开发jsp tagQ原因就是开发tagq于ȝQ而且调整不方ѝ另外开发出的tag如果_度太小Q大量用的时候是Ҏ(gu)能的致命伤実?br> tpl首先需要经q编译,而不是象jsp tag那样完全动态运行,而且tpl~译出的l果是无状态的Q因此解决了性能上的问题?br> 在tpl中导入外部模板的语法非常单,可以实现基本的分?br> <c:include src="xxx.tpl" />
更重要的是,tpl中定义了完善的库机制?br>使用?br> <!-- 导入外部? 导入时指定名字空间ؓ(f)demo?br> 注意tpl中ƈ没有完整的名字空间支持,只能作ؓ(f)qName使用
-->
<c:lib src="demo_lib.xml" namespace="demo" />
<!-- 对具有cache:timeout属性的节点应用cache修饰Q即该节点的q行内容被缓?-->
<c:decorator type="cache" match="//@[cache:timeout]" />
<div id="blockA">
<p>通过tpl:tag属性可以设定宿L{真实标签名。这U做法可以方便可视化设计Q?lt;/p>
<input tpl:tag="demo:文本? value="in block A"
otherValue="${varInJsp}" onclick="clickOnBtn()"/>
</div>
<div id="blockB">
<p>分页表格:</p>
<img tpl:tag="demo:分页表格" headers="fieldA,fieldB" pager="${pager}" />
</div>
<div id="blockC">
<p>bodyTag标签的调?</p>
<demo:循环data>
<input type="text" value="${row}" /> <br/>
</demo:循环data>
</div>
<div id="blockD" cache:timeout="1000s" >
<p>条g标签的调?</p>
<demo:当Num_?gt;
<p>?thisObj中的变量 'num' 的值大?的时候显C句话 </p>
</demo:当Num_?gt;
</div>
定义库文件demo_lib.xml
<!--
自定义标{属性:(x)
type: simpleTag, bodyTag 或?conditionTag, ~省为simpleTag
importVars : 每个自定义标{օ有自q变量I间Q需要通过importVars来明指定从外部变量I间中导入的变量?br> demandArgs: 调用时必L给些参数的?br> otherArgs: 如果指定了该参数Q则调用自定义标{时能够使用的参数就必须在demandArgs和otherArgs指定的范围之内?br>-->
<demo>
<!-- 一个简单的tagCZQ?直接输出变量。这里demandArgs指定调用时必L供的变量?-->
<文本?demandArgs="value" otherArgs="otherValue,onclick" type="simpleTag" >
<p> ----------------------------------- </p>
<!-- 可以使用调用时提供的其他变量Q如otherValue-->
<input size="40" type="text" value="${value} * ${otherValue}" onclick="${onclick}"/>
<p> -----------------------------------</p>
</文本?gt;
<!-- 一个自动分表|要求传入headers(Listcd)指定表头Qpager(Pagercd)提供数据 -->
<分页表格 demandArgs="headers,pager">
<!-- 从外部导入tpl文g -->
<c:include src="flex_table.tpl" />
</分页表格>
<!-- 一个bodyTagCZ: 循环处理thisObj中的变量data中的每一行?br> importVars从调用环境中自动导入变量而不需要通过调用参数直接指定?br> 当然如果调用参数中指定的变量与importVars中指定的变量重复Q则调用参数?x)覆盖importVars.
-->
<循环data importVars="thisObj" type="bodyTag">
<c:forEach var="row" items="${data}">
<!-- tagBody用时标签的内?-->
<cp:compile src="${tagBody}" />
</c:forEach>
</循环data>
<!-- 一个条件标{CZ.
条g标签一般不应该输出文本Q而是q回一个bool倹{仅当返回true的时候,调用时标{内容才会(x)被运行?br> -->
<当Num_?importVars="thisObj" type="conditionTag">
<l:gt name="num" value="3" />
</当Num_?gt;
</demo>
? 意到bodyTag和conditionTag使得我们可以@环(容器Q逻辑和判断逻辑抽象成有意义的概念,而不再是一些执行的指o(h)。这U抽象能力的? 用非怾赖于xml的自描述Ҏ(gu),我们不需要付出太大的努力Q就可以在lib中封装出一个有意义的概忉|! 而且tag的参数可以指定,可以~省Q存在多U选择Q也对应着多种逻辑模型?br>通过<c:decorator>的用法可以看刎ͼ因ؓ(f)xml明确定义了结构,使得我们可以L的实施类似AOP的功能?/font>
3. 集成能力
首先Qtpl完全W合xml规范Q与xml世界接轨Q可以自q使用xslt。例如,?br> M标签中都可以指定tpl:xdecorator属? tpl在编译之前首先会(x)应用指定的xslt文gq行变换Q对变换后的l果再进行编译?br> <anyTagName tpl:xdecorator="some_xslt.xslt">
...
</anyTagName>
其次Qtpl可以使用属性标讎ͼ即tpl标签不仅仅可以通过标签名来标识Q而且可以通过tpl:tag属性来标识。例?
<input tpl:decorator="demo:文本? />
?<demo:文本?/>{效?br> q种做法避免了tpl侵入html模型Q得我们可以利用现有工具对tplq行所见即所?WISIWIG)的设计?/font>
再次, 在tpl中用EL(Expression Language)语言Q集成java数据模型?/font>
W四, 在tpl中可以采用如下方式实现强cd化,完成与java的接口?br> interface ITest{
void test(String name, int value);
}
<o:class name="MyClass" implements="ITest">
<test args="name,value" >
...
</test>
</o:class>
q种能力可以在数据源的filter中用?/font>
引用: |
Action Centric 实比较ȝQ必d时传入角色列??用户列表?分页信息?JSPLet对于q个问题是怎么处理的? |
很简单包含两个子面
list_both.jsp
<jsp:include page="role_list.jsp?objectName=/@RoleManager" />
<jsp:include page="user_list.jsp?objectName=/@UserManager"/>
?
讉K的时候通过指定eventTarget参数卛_事件\由到合适的对象Q没有响应事件的对象thisObj里的内容不变Q因为前台view昄内容?
不变。注意这里role_list.jsp和RoleManager, UserManager对象都是独立开发的?
引用: |
q个时候,role_list.jsp ?user_list.jsp里面都有一?thisObj。而且q两个thisObj的scope都是 sesession ? |
?
意所有的对象模型都需要状态保持机Ӟ所以thisObj实被保持在session中。在webwork2中如果希望在多个action之间协调Q则?
d某个对象保留在session中,否则是采用无状态模型,所有的状态数据都持久化在数据库中Q每ơ输出的面都和某个action产生l定Q一U行
为相养IQ则Ҏ(gu)无法实现上述例子中的分解q程Q因为在action模型中状态与行ؓ(f)无法抽象C起ƈ重用Q?
当页面显C逻辑比较复杂的情况下Q页面本w也有一些(f)时状态需要保持,MVCq不是意味着所有的状态都是需要持久化到数据库中的关键业务数据。在每个层次
上都可能需要保持状态,MVC只是说某些状态变量更加重要,可以驱动其它层次而已?
另外说thisObj的scope是session也是?
准确的。首先注意到jsplet通过对象化实C状态和行ؓ(f)抽象CP此后E序拥有了对这个整体的控制权,在jsplet中存在着对象的生命周期控
Ӟ对象的scope是自定义的,对象的生命周期是session的子部分Q而不是整个session生命周期范围内都存在。请注意一下这U控制策略带?
的可扩展性。我们拥有了对象生命周期的控制权Q依然可以采用无状态设计,但在需要保持状态的时候,可以做到。而在webworkq样的action模型?
是没有这U选择权的?/p>
引用: |
sessionq度使用是不好的 |
thisObj只是允许使用session,是否使用session可以自行军_Q这是一U能技术,而没有object支持Q结果是无法有效的用。另外,请仔l看清楚QobjectScope是一U非常精l的资源使用控制手段?
?
外不要把设计理念和性能混ؓ(f)一谈。设计体现的是对概念的把握,能够辑ֈ合适的抽象Q而性能是实际实现过E中的限制。在概念能够支持的情况下Q可以采用技?
手段解决性能问题Q或者退化到较低的层ơ,q是一U选择权。而概忉|法支持的情况下,需要各U穿墙打z的Ҏ(gu)来实现?
thisObj重要的是概念Q如果需要,它可以把状态序列化到cookie或者dotNet那种参数中,q只是个实现问题?br>
引用: |
JSPLet Action 必须?JSP ? |
当然可以是Q何javac, JSP Action只是IEventListener接口的一个实?。在jsplet最初的版本中,action只能写在java文g中。稍后改为可以写在jsp中也可以写在java?br>
引用: |
WebWork的Action本n是模型对象 |
q是WebWorkq地方Q它因ؓ(f)是基于action的,没有对象化,所以只有以action作ؓ(f)模型对象的蝲体,无法捕获多个action之间的状态相x?
完全无状态的设计正是因ؓ(f)没有合适蝲体造成的。而jsplet中thisObj可以看作是对session的局域化Q是对session的分解。jsplet中的很多概念在webworkq种面向action的框架中都能扑ֈ对应Q只是加上了很多限制q且变得模糊了?/p>
引用: 没有model1?jstl+javabean) 没有struts?优雅" 定位模糊.
jsplet
是以非常_的方式实现对象化。再说一ơ,不要把jsplet的定位向那些开源框架上靠。jsplet的开发时间大概与那些开源框架同时进行的。仔l看?
设计中的可扩展性。xwork的所有特性jsplet都可以实玎ͼ而且jsplet多提供的部分是对象化?
?
本h从未应用qModel2模式Q但与我们的jsplet框架Ҏ(gu)Q我认ؓ(f)q种推送方式在大多数情况下q不是什么优炏V如果将一ơweb讉K看作是一ơ函
数调用,则按照Model2模式Q这个函数的q回情况是不定的,需要由一个额外的配置文g来确定。而我们知道,一个返回情况不定的函C般不是什么良
好的设计。在我们的框架设计中Q一个基本的观点是尽量将自由度暴露给实际控制它的人。实际上Q在大多数情况下Q页面编制h员知道应该用哪个页面来昄?
据,他们q不需要一个额外的配置文g。Jsplet使用如下的url格式:
视图jsp?objectName=模型对象?amp;objectEvent=响应事g?amp;其他参数
举一个具体的例子:
http://my.com/demo_view.jsp?objectName=/@Demo&objectEvent=test
demo_view.jsp是指定的昄面, 其代码如?
[code]
<%@ include file = "/engine.jsp" %>
<!-- 相当于在jsp模型中增加了一个新的变量thisObjQ从而实现jsp面的对象化 -->
<c:out>${thisObj.testVar}</c:out>
[/code]
objectName被WebEngine映射到session中的一个对象,在demo_view.jsp中成为thisObjq个变量Q这q当于java语言中的this指针Q从而实Cjsp面的对象化?/font>
WebEngineq将objectEvent映射C个Action响应函数q自动调用它Q具体的Action代码写在一个独立的java文g或者jsp文g中?br>DemoAction.jsp
[code]
<%@ include file = "/jsp_action_begin.jsp" %>
<%!
//
// objectName映射为thisObj, objectEvent=test映射对actTest的调?br> // 在这里增加一个actXXX函数之后Q即可通过objectEvent=XXX来访问,不需要Q何配|?br> public Object actTest(){
// thisObj中的变量可以在视图中使用
thisObj.set("testVar","hello");
return success();
}
// 如果存在actBeforeAction函数Q则该函数在所有action函数之前调用
public Object actBeforeAction(){
return success();
}
// 如果存在actAfterAction函数Q则该函数在所有action函数之后调用
public Object actAfterAction(){
return success();
}
%>
<%@ include file="/jsp_action_end.jsp" %>
[/code]
在Jsplet框架中只需要注册对象,而不需要单独注册每个action?br>register.jsp
[code]
<%
WebEngine.registerType("Demo", new WebActionType("/demo/action/DemoAction.jsp"),pageContext);
%>
[/code]
与Jsplet
框架Ҏ(gu)QModel2是对action的徏模而不是对object的徏模,卛_相当于将objectName,objectEvent?
view.jspl定在一起定义ؓ(f)一个访问点action.do,l定q程中需要一个配|文件来固化view.jsp和action之间的联pR因?
Model2q没有完全分view和modelQ它隐含假定着objectName只具有一个objectEvent,
q且l定了一个具体的view(出错面除外)?br>例如, 我们需要两个不同的view来显C同一个数据,则在Model2E序中可能需要配|两个独立的讉K点,而在我们的框架中只需要用两个不同的url:
a_view.jsp?objectName=/@Demo&objectEvent=test
b_view.jsp?objectName=/@Demo&objectEvent=test
同样的webE序甚至可以在前台通过XMLHTTP方式来调用而不需要额外配|?
在Jsplet框架中采用的是对象化的方式而不是Action化的方式Q因此存在着多种面向对象的扩?而所有的扩展都直接体现在url格式的细化上Q一切都在阳光下?br> 在Jsplet中objectName是WebObject的名Uͼ在全pȝ内唯一Q其格式定义? objectScope@objectType$objectInstanceId
1. 对象cdobjectType
我们需要注册的是对象类型而不是完整的对象名,一个对象类型可以对应于无数个完整的对象名,例如我们注册了Democd的WebObject, ?/font>objectName=/@Demo?/font>objectName=/left/@Demo对应的处理文仉是DemoAction.jsp?br>2. 对象生命周期控制objectScope
objectScope为WebObject所在的域,其格式符合Unix路径命名规范。JSP模型本n支持一些预定义的对象域Q包括page,
request, session,
application{。但Z能够反映现实世界中的对象l织l构Q对象域必须是允许自定义的。objectScope被组l成一个树(wi)形结构,q是一?
基本的控制结构,其控制策略ؓ(f)
同时存在的对象域之间必须存在U性序关系(order)
当系l访问某一对象Ӟ如果该对象所在的对象域不能和现有对象的域处在同一"路径"?卛_对象域之间不能徏立父子关pL)Q系l就?x)自动销毁不兼容路径
分支下的所有对象?q种_的控制策略保证了pȝ的可扩展性,因ؓ(f)模型上可以保证始l只有一部分对象被创建?br>对象转移
pȝ动作
/main/@MyObject ==> /main/left/@OtherObject
?
/main/left/@OtherObject ==> /main/@MyObject
?
/main/left/@OtherObject ==> /main/left/@MyObject ?
/main/left/@OtherObject ==> /main/right/@MyObject 自动销?main/left子域下的对象Q如/main/left/@OtherObject
3. 对象实例标识 objectInstanceId
如果在某一对象域中需要包含多个同一cd的对象,可以通过objectInstanceId来加以区分,q样在同一个页面上我们可以使用多个同样cd的对象?/font>
Jsplet中另外一个扩展是通过事g路由来支持jsp子页面的对象化。例?br>http://my.com/demo_main.jsp?objectName=/@Main&eventTarget=/@Sub&objectEvent=test
如果指定了eventTarget参数Q则objectEvent由eventTarget对应的对象来响应?br>在jsp文g内部我们可以通过include语法来引入子对象Q例?br> <jsp:include page="sub_view.jsp?objectName=/@Sub" />
Q注Q我不是非常清楚Tapestry具体是如何实现对象化的,熟?zhn)Tapestry的朋友可以介l一下)
在Jsplet中可以通过配置文g来支持对Action的interception, 例如
[code]
<factory>
<listener-filter class="global.LogFilter" />
<post-listener class="global.CommonActions"/>
<type name="Demo">
<!-- 如果未指定object, 则缺省ؓ(f)WebObjectcd -->
<object class="demo.MyWebObject" />
<listener>
<filter event="query*|select*" class="demo.LogFilter" />
<url-listener url="/demo/DemoAction.jsp" />
<url-listener url="/demo/DemoAction2.jsp" />
</listener>
</type>
</factory>
[/code]
在上面这个配|文件中QDemoAction.jsp和DemoAction2.jsp是chain关系Q即事g响应的传播模型中Q如果event没有被标Cؓ(f)stopPropagation,׃(x)传递到下一个listener?/font>
lg所qͼ可以看到在目前多变的需求环境下QModel 2已不是一U非常完善的WebE序模式Q一些重要的设计需求在Model 2模式的推方式中很隑־到合适的表达?/font>