JSP 的 errorPage 指令异常转向错误页的实现机制及应用

如有 index.jsp 页,当出现后服务器端异异常时要转向到 errorPage.jsp,并在 errorPage.jsp 中把对应错误信息显示出来。我们需要在这两个页面分别加上指令 errorPage="errorPage.jsp"isErrorPage="true"

index.jsp

errorPage.jsp

errorPage.jsp 中必须加上 isErrorPage="true" 指令,才会存在内置变量 exception。直接访问 errorPage.jsp 没有异常时,exception 为 null。

浏览器中用 URL http://localhost:8080/test/index.jsp 访问,页面输出

java.lang.Exception: exception from index.jsp.

那实现机制是什么呢?仍在常见的 Tomcat 容器中运行结果来分析

查看 Tomcat 编译出的 index_jsp.java 进而追溯到(代码片断)

org.apache.jasper.runtime.PageContextImpl.doHandlePageException(Throwable t)() 中的部分代码

同样要翻看 Tomcat 编译出的 errorPage_jsp.java 可看到(代码片断)

Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); // JSP 中

org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request) 中的部分代码

最终都是以 SERVLET_EXCEPTION 把异常设置到 request 中

JspRuntimeLibrary 定义了这两个常量字符串

private static final String SERVLET_EXCEPTION = "javax.servlet.error.exception";
private static final String JSP_EXCEPTION = "javax.servlet.jsp.jspException";

如果要在自己的代码中,如 Servlet、Filter、Struts 的 RequestProcessor 或 Struts Action 中出现异常也能转向到 errorPage.jsp,并能复用原来的 errorPage.jsp 中显示错误信息的代码,该如何应用上面的分析成果呢?

下面以 Struts Action 为例来说明,应用于其他地方可借鉴。为什么用了 Struts 却不用 Struts 提供的异常处理模型呢?也是无奈的,维护的旧系统,框上了 Struts,其他各处只能慢慢来换。

只要在 Struts Action 中的 execute() 方法中写上

进一步深入你可以自定义一个 Struts 的异常处理类来做这个事情。
这时候还需要自已在 errorPage.jsp 的最后一行加上 java 代码:

request.removeAttribute("javax.servlet.error.exception");

去除 request 中的异常属性,不然没法用 errorPage.jsp 显示错误,而代之为的是那个常见的

HTTP Status 500 -

description The server encountered an internal error () that prevented it from fulfilling this request.

这时候浏览器中通过 URL http://localhost:8080/test/test.do 访问,页面输出

java.lang.Exception: exception from Struts Action.

最后尝试把这个项目发布到 Websphere Application Server (WAS) 5.1 下,访问 http://localhost:9080/test/test.do,页面输出 null,没取到异常!

没什么好办法,还是反编译 WAS 生成的 JSP 代码中,发现到 WAS 5.1 的 PageContext 的实现类也是 org.apache.jasper.runtime.PageContextImpl,在 WAS_HOME/lib/webcontainer.jar 包中。在这个 PageContextImpl 类中也是设置

request.setAttribute("javax.servlet.jsp.jspException", t);

但是WAS 5.1 下 errorPage.jsp 直接通过 request 来取异常:

throwable = (Throwable)httpservletrequest.getAttribute("javax.servlet.jsp.jspException");

不再理会 request 中的 javax.servlet.error.exception 属性值的。

因此只要注意一点,在 Tomcat 中,Action 里既可以设置

request.setAttribute("javax.servlet.error.exception", t);

也可以是

request.setAttribute("javax.servlet.jsp.jspException", t);

当然在 WAS 5.1 下的 errorPage.jsp 中就不需要

request.removeAttribute("javax.servlet.error.exception");

那要不要用

request.removeAttribute("javax.servlet.jsp.jspException");

移除 request 中的 javax.servlet.jsp.jspException 属性呢?也用不着啦。

Tomcat 下和 WAS 下的 jsp 页面的主要差别是在它们的基类不同,Tomcat 下的 JSP 页是继承自 org.apache.jasper.runtime.HttpJspBase,而 WAS 5.1 下的 JSP 页是继承自 com.ibm.ws.webcontainer.jsp.runtime.HttpJspBase
考虑在能兼容两种平台的做法应该是,在 Action 中统一用

request.setAttribute("javax.servlet.jsp.jspException", t);

设置异常,然后在 errorPage.jsp 补上一行

request.removeAttribute("javax.servlet.error.exception");

就 OK 啦。

本文链接 https://yanbin.blog/jsp-errorpage-mechanism-application/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

3 Comments
Inline Feedbacks
View all comments