打开opentaps任意一个有分页功能的页面*.ftl文件
其中有如下代码:
<@import location="component://opentaps-common/webapp/common/includes/lib/opentapsFormMacros.ftl"/>
<div>
<@paginate name="layerCategories" list=categories rememberPage="true" sectionName=sectionName>
<#noparse>
...
</#noparse>
</@paginate>
</div>
这里<@paginate name="layerCategories" list=categories rememberPage="true" sectionName=sectionName>,name是分页页面的名字,list是分页列表list对象(由bsh传入,可参考 lookupSuppliers.bsh),rememberPage为是否显示页码。
在 opentapsFormMacros.ftl中有对@paginate变量做解析:
<#macro paginate name list="" rememberOrderBy=true rememberPage=true params...>
<@paginateTransform name=name list=list rememberOrderBy=rememberOrderBy rememberPage=rememberPage context=context params=params><#nested></@paginateTransform>
</#macro>
变量@paginateTransform实际上是一个java类,要在ftl中使 用paginateTransform解析分页页面,就有在render此 paginateTransform.ftl之前,load进来类 paginateTransform。途径是:
通常在解析每个screen时,都包含一个头部decorator的 screen(main-application-decorator)。在此screen中有bsh脚本:main-decorator.bsh(路径 为:component://yourcomponent/webapp/yourwebapp/WEB-INF/actions/includes /main-decorator.bsh
main-decorator.bsh脚本会对全局变量做初始化,并放到 context之中:
context.put("contextPath", request.getContextPath());
loader = Thread.currentThread().getContextClassLoader();
globalContext.put("import", loader.loadClass("org.opentaps.common.template.freemarker.transform.ImportTransform").newInstance());
globalContext.put("include", loader.loadClass("org.opentaps.common.template.freemarker.transform.IncludeTransform").newInstance());
globalContext.put("paginateTransform", loader.loadClass("org.opentaps.common.webapp.transform.PaginateTransform").newInstance());
globalContext.put("layerPaginateTransform", loader.loadClass("org.opentaps.common.webapp.transform.LayerPaginateTransform").newInstance());
这 里装载了paginateTransform这个类(另外,在freemarker中,常用到的@import变量,也是在这里装载的)。
类 PaginateTransform implements TemplateTransformModel,
重载方 法:getWriter,并return FormletFactory.getFormletWriter(out, paginator, applicationName, locale);
FormletWriter即是渲染分页页面的类(内部类)。 FormletWriter将调用方法renderFormletPlaceholder,载入这样一个页面:
formletPlaceholder.ftl, 内容如下:
<div id="paginate_${paginatorName}">
<script type="text/javascript">
opentaps.addOnLoad(function(){opentaps.getCurrentPage('${paginatorName}','${opentapsApplicationName}')});
</script>
</div>
当我们访问一个带分页的页面时,在页面源码中只会看到如上的一段div和js内容。
这 段内容与opentaps.js、dojo.js结合,在页面加载完后(window.onload),调用 opentaps.getCurrentPage,获得分页的html。
阅读opentaps.js文件,找到方法 getCurrentPage,可以看到这里使用ajax,向服务器发送请求:地址为paginate,并在context中带上分页的参数(分页页面名 name,前边提到的,如:layerCategories;分页所在application name;等)。其中paginate地址在hot-deploy/opentaps-common中的请求处理文件pagination- controller.xml中定义。该文件内容如下:
<handler name="formlet" type="request" class="org.opentaps.common.event.FormletEventHandler"/>
<request-map uri="paginate">
<event type="formlet" path="org.opentaps.common.event.PaginationEvents" invoke="paginate"/>
<response name="success" type="none"/>
<response name="error" type="none"/>
</request-map>
dojo发送的请求到达后,会触发事 件:formlet(FormletEventHandler extends JavaEventHandler),其中invoke方法用于调用事件的响应方法:PaginationEvents中的paginate,并且 invoke方法中调用:
FormletFactory.renderFormlet(request, response.getWriter(), paginator, locale);
方法renderFormlet把分页页面写回到 response.getWriter()中——template.process(context, out/*response.getWriter()*/);
随笔只记下当时探寻这个问题的思路,或有不清晰的地方,请谅解