批量系统原有的页面定时刷新的实现是不太合理的,以RealtimeBatchRunningOfCountwf为例:
首先在RealtimeBatchRunningOfCountwf.page中定义了属性refreshUrl:<property-specification name="refreshUrl" type="java.lang.String"/>,RealtimeBatchRunningOfCountwf.html中将refreshUrl插入head部分。实现的重点在RealtimeBatchRunningOfCountwf.java中,getRefreshUrl方法返回httpmeta头,在这个头信息中定义了刷新时间和要刷新到的页面的url:
public String getRefreshUrl() {
String t_intervalTime = getIntervalTime();
if (t_intervalTime == null) {
t_intervalTime = getRequestCycle().getRequestContext()
.getParameter("intervalTime");
}
if (t_intervalTime == null || t_intervalTime.equals("")) {
return "";
}
String url = "";
try{
url = "<meta http-equiv=\"Refresh\" content=\""
+ t_intervalTime
+ "; URL="
+ getRequestCycle().getRequestContext().getAbsoluteURL(
"batch-server/app?service=page/RealtimeBatchCountwf")
+ "&gappid=" + getGappid() + "&gfuncid=" + getGfuncid() + "&intervalTime=" + t_intervalTime
+ "&agentzoneno=" + getAgentzoneno()
+ "\"/>";
} catch(Exception e){
setMessage(e.getMessage());
return "";
}
return url;
}
可以看到getRefreshUrl的实现是非常复杂的,由于TapeStry的页面模型是比较复杂的,其中的变量都是通过页面模型来储存的,如果只是简单的刷新页面,会造成这些页面变量错误,因此在getRefreshUrl方法中将所有的变量拼接到url中,这样在页面的getGappid、getAgentzoneno等方法中首先判断页面请求(getRequestContext)中是否有此页面变量,如果有则取页面请求中的,否则再去取本对象中的变量值。这样看起来getGappid、getAgentzoneno、getRefreshUrl等方法都非常复杂,一旦页面中增加新的属性就需要去修改getRefreshUrl方法,而且这样造成视图(View)的逻辑混杂到了模型(Model)中,违反了MVC的隔离原则,最重要的是这样做违背了Tapestry页面模型设计的原意。因此我做了一个新的实现方法,可以参考BatchTaskContrlwf:
首先仍然是在BatchTaskContrlwf.java中定义getIntervalTime方法:
public String getIntervalTime()
{
if (intervalTime == null)
{
intervalTime = "60";
}
setMessage("数据每 " + intervalTime + " 秒更新一次,更新的速度可以在左上角更改");
return intervalTime;
}
getIntervalTime比以前的实现简单了。BatchTaskContrlwf.java中也没有了getRefreshUrl方法,这样保持了视图与模型的独立性。
在BatchTaskContrlwf.html中body的开头增加如下的javascript:
<script>
//intervalTime表示秒,但是在setTimeout中的单位是毫秒,所以在后边加三个零
window.setTimeout("RefreshPage()",<span jwcid="@InsertText" value="ognl:intervalTime"></span>000);
function RefreshPage()
{
document.getElementById("imgRefresh").click();
}
</script>
这里调用定时器实现每隔intervalTime秒就调用一次RefreshPage方法,在RefreshPage方法中则去模拟点击imgRefresh控件,这样就可以达到刷新页面的目的了。imgRefresh是为“刷新”这个图形按钮增加的id属性,因为图形按钮默认是只有name属性的,而且name属性生成的也是随机的,所以为“刷新”按钮增加id属性:
<img jwcid="@ImageSubmit" id="imgRefresh" hspace="20" align="middle" image="ognl:assets.refreshImage" listener="ognl:listeners.refreshAction"/>
这样就可以在RefreshPage方法中轻松的取得此控件了。
在RefreshPage方法中也使用getElementById这个技巧,因为Tapestry生成的html中的表单的名称也是不可测的,目前的名称是“$Form0”,但是这个名称是不保障的,如果我们在RefreshPage方法中使用document.$Form0.$ImageSubmit.click()方式刷新页面的话,很有可能在Tapestr实现机制改变或者在页面中加入了新的表单元素后造成代码错误。而getElementById则可以直接根据控件id来定位控件,大大提高了代码的灵活性。
注:上边的文章是我对公司原有产品进行重构的时候发的一篇文章,涉及到了公司的一些私有概念,非公司的人可能读部分章节起来有点费劲,请谅解。如果以后有时间我会整理成通用的文档的。