十年来,使用 JSP scriptlets 是一种不受欢迎的做法。你最好avoid它。
如果您已经使用 EL 2.2 或更新版本(Tomcat 7+、JBoss AS 6+、WildFly、GlassFish 3+ 等),并且对 ${instance.method()} 形式的方法表达式提供了新支持,那么您可以使用100% EL 为此。
首先,您需要通过JspWriter#flush() 显式刷新 JSP 编写器,以便所有前面的 JSP 模板输出真正写入 servlet 响应的编写器:
${pageContext.out.flush()}
那么你可以将ServletResponse#getWriter() 传递给Throwable#printStackTrace()。
${exception.printStackTrace(pageContext.response.writer)}
完整示例:
<%@page pageEncoding="UTF-8" isErrorPage="true" %>
...
<pre>${pageContext.out.flush()}${exception.printStackTrace(pageContext.response.writer)}</pre>
如果您已经使用 EL 3.0(Tomcat 8+、WildFly、GlassFish 4+ 等),您甚至可以使用分隔 EL 语句的新分号运算符使其成为单个表达式:
<%@page pageEncoding="UTF-8" isErrorPage="true" %>
...
<pre>${pageContext.out.flush();exception.printStackTrace(pageContext.response.writer)}</pre>
如果您由于某种原因不能使用isErrorPage="true"(因此${exception} 隐式对象不可用),则只需替换为${requestScope['javax.servlet.error.exception']}:
<%@page pageEncoding="UTF-8" %>
...
<pre>${pageContext.out.flush()}${requestScope['javax.servlet.error.exception'].printStackTrace(pageContext.response.writer)}</pre>
如果您还没有使用 EL 2.2,那么最好的办法是创建自定义 EL 函数。详情可见What is the good approach to forward the exception from servlets to a jsp page?
下面是一个更完整的错误页面示例,其中包含更多细节:
<%@page pageEncoding="UTF-8" isErrorPage="true" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<ul>
<li>Exception: <c:out value="${requestScope['javax.servlet.error.exception']}" /></li>
<li>Exception type: <c:out value="${requestScope['javax.servlet.error.exception_type']}" /></li>
<li>Exception message: <c:out value="${requestScope['javax.servlet.error.message']}" /></li>
<li>Request URI: <c:out value="${requestScope['javax.servlet.error.request_uri']}" /></li>
<li>Servlet name: <c:out value="${requestScope['javax.servlet.error.servlet_name']}" /></li>
<li>Status code: <c:out value="${requestScope['javax.servlet.error.status_code']}" /></li>
<li>Stack trace: <pre>${pageContext.out.flush()}${exception.printStackTrace(pageContext.response.writer)}</pre></li>
</ul>