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

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

index.jsp

1
2
3
4
5
<%@page errorPage="errorPage.jsp" %>
 
<%
     throw new Exception("exception from jsp");
%>

errorPage.jsp

1
2
3
4
5
6
<%@page isErrorPage="true" %>
<%
     out.println(exception);
 
     //根据 Exception 类型及描述显示可理解的信息
%>

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)() 中的部分代码

01
02
03
04
05
06
07
08
09
10
11
12
13
14
request.setAttribute( "javax.servlet.jsp.jspException" , t);
request.setAttribute( "javax.servlet.error.request_uri" ,
         ((HttpServletRequest) request).getRequestURI());
forward(errorPageURL);
 
Object newException = request.getAttribute( "javax.servlet.error.exception" );
 
// t==null means the attribute was not set.
if ( (newException!= null ) && (newException==t) ) {
       request.removeAttribute( "javax.servlet.error.exception" );
}
 
request.removeAttribute( "javax.servlet.error.exception" );
request.removeAttribute( "javax.servlet.jsp.jspException" );

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

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

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

1
2
3
4
5
    Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION);
    if (error == null ) {
        error = (Throwable) request.getAttribute(JSP_EXCEPTION);
if (error != null ) {
            request.setAttribute(SERVLET_EXCEPTION, error);

最终都是以 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() 方法中写上

1
2
3
4
5
Throwable t = new Exception( "exception from Struts Action." );
request.setAttribute( "javax.servlet.error.jspException" , t);
 
//或者在 struts-config.xml 中配置一个全局错误页
return new ActionForward( "/errorPage.jsp" );

进一步深入你可以自定义一个 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 啦。


转自

http://unmi.cc/jsp-errorpage-mechanism-application

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值