如有 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)() 中的部分代码
1 2 3 4 5 6 7 8 9 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 啦。
本文链接 https://yanbin.blog/jsp-errorpage-mechanism-application/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。