错误处理

ZK Web应用程序可以指定错误发生时该做什么。错误是由异常引起的,而应用程序没有捕获到这个异常。

在两种情况下可能会抛出异常:加载页面和更新页面[59]

加载页面时的错误处理

若加载ZUML页面时抛出了一个未捕获的异常,此异常会直接由Web服务器处理。换言之,这和其它页面的处理没有区别,例如JSP。

默认情况下,Web服务器会使用一个错误页面来显示错误信息及栈跟踪(stack trace)。

通过在WEB-INF/web.xml文件内指定错误页面,你可以定制错误处理,如下。细节请参考Java Servlet Specification。

<!-- web.xml -->
<error-page>
   <exception-type>java.lang.Throwable</exception-type>
   <location>/WEB-INF/sys/error.zul</location>
</error-page>

那么,当加载页面时发生一个错误,Web服务器会转向你指定的错误页面,/error/error.zul。转发之后(Upon forwarding),Web 服务器会立即将一套请求属性传递到错误页面以描述发生了什么。这些属性如下。

请求属性

类型

javax.servlet.error.status_code

java.lang.Integer

javax.servlet.error.exception_type

java.lang.Class

javax.servlet.error.message

java.lang.String

javax.servlet.error.exception

java.lang.Throwable

javax.servlet.error.request_uri

java.lang.String

javax.servlet.error.servlet_name

java.lang.String

然后,在错误页面内,通过使用这些属性,你可以显示你的定制信息。例如,

<window title="Error ${requestScope['javax.servlet.error.status_code']}">
   Cause: ${requestScope['javax.servlet.error.message']}
</window>

[提示]:错误页面可以为任何类型的 servlet。除了ZUL,可以使用JSP或任何你喜欢的页面。

[提示]:转发之后, 错误页面会被作为主页面展示,所以你不需要指定主窗口指定模态(modal)或 overlapped 模式(mode)(如果有的话)。

ZK Mobile错误处理

Servlet 2.x (web.xml)没有device类型的概念。因此,若想在相同的服务器端同时支持Ajax浏览器和移动设备,你必须转向正确的页面。这里有一个例子:

//error.zul
<zk>
   <zscript>
   if (Executions.getCurrent().isMilDevice())
      Executions.forward("error.mil");
   </zscript>
   <window>
   ....error message in ZUL
   </window>
</zk>

更新页面时的错误处理

若当更新ZUML页面(亦=一个事件监听器正在执行时)时抛出了一个未被捕获的异常,此异常会由ZK更新引擎(ZK Update Engine)处理。默认情况下,它只会要求浏览器端显示一个警告对话框来告诉用户。

你可以在WEB-INF/zk.xml文件内指定错误页面以定制错误处理,如下。参考the Developer's Reference 的附录B(Appendix B)。

<!-- zk.xml -->
<error-page>
   <exception-type>java.lang.Throwable</exception-type>
   <location>/WEB-INF/sys/error.zul</location>
</error-page>

那么,当在事件监听器内发生一个错误时,ZK更新引擎会使用你指定的错误页面,/error/error.zul,创建一个对话框。

就像加载一个页面时的错误处理,你可以指定多个<error-page>元素。其中的每个元素都与一个不同的异常类型(<exception-type>元素的值)相关联。当发生一个错误时,ZK将会逐个寻找错误页面,直到异常类型匹配。

另外,ZK将一套请求属性传递到错误页面来描述发生了什么。这些属性如下。

请求属性

类型

javax.servlet.error.exception_type

java.lang.Class

javax.servlet.error.message

java.lang.String

javax.servlet.error.exception

java.lang.Throwable

例如,你可以指定下列的内容作为错误页面。

<window title="Error ${requestScope['javax.servlet.error.status_code']}"
width="400px" border="normal" mode="modal">
   <vbox>
   KillerApp encounters a fatal error, ${requestScope['javax.servlet.error.message']}. 
   The error is recorded and we will look at it and fix it soon.
      <hbox style="margin-left:auto; margin-right:auto">
         <button label="Continue" onClick="spaceOwner.detach()"/>
         <button label="Reload" onClick="Executions.sendRedirect(null)"/>
      </hbox>
   </vbox>
   <zscript>
   org.zkoss.util.logging.Log.lookup("Fatal").log(
      requestScope.get("javax.servlet.error.exception"));
   </zscript>
</window>

[提示]: 错误页面是在引起错误的相同卓面内被创建的,所以你可以从其中获取相关的信息。

[提示]:从2.3.1开始,ZK不会自动将根窗口作为模态(modal),因为一些应用程序或许并不倾向于使用modal窗口。若你倾向于使用模态窗口,可以指定为模态 模式,就像前面所示的例子那样。

更新页面时ZK Mobile错误

每个device类型都有其自己的一套错误页面。为了为ZK mobile设备指定一个错误页面(支持MIL 的移动设备),你必须使用mil指定device-type元素,如下所示。

<!-- zk.xml -->
<error-page>

   <device-type>mil</device-type>
   <exception-type>java.lang.Throwable</exception-type>
   <location>/WEB-INF/sys/error.zul</location>
</error-page>

[提示]: 若忽略了device-type元素,则假定为ajax。换言之,为Ajax浏览器指定了一个错误页面。

<device-type>ajax</device-type> <!-- ajax is the default -->



[59] 细节请参考组件活动周期(the Component Lifecycle)一章。