如何在 JSP 页面中打印错误堆栈跟踪?
Posted
技术标签:
【中文标题】如何在 JSP 页面中打印错误堆栈跟踪?【英文标题】:How can I print error stack trace in JSP page? 【发布时间】:2011-12-29 11:25:06 【问题描述】:我在 web.xml 中设置了这样的错误页面:
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/errors/error.jsp</location>
</error-page>
现在我想在 JSP 上打印错误堆栈跟踪(当然仅在开发模式下)。如何在我的 JSP 页面上打印错误堆栈跟踪?我没有为此应用程序使用任何框架,因此我的程序只能使用默认的 servlet API。
【问题讨论】:
【参考方案1】:在错误页面上,只需:
<jsp:scriptlet>
exception.printStackTrace(response.getWriter())
</jsp:scriptlet>
尽管这引出了一个问题:用户将如何处理异常。为什么不将异常写入错误日志,这样它就会被持久化,并且在用户抱怨后您可以返回它呢?
【讨论】:
【参考方案2】:抛出的异常对象可用作名称为“javax.servlet.error.exception”的请求属性。因此,在您的 JSP 中,您可以编写:
<% request.getAttribute("javax.servlet.error.exception").printStackTrace(new java.io.PrintWriter(out); %>
【讨论】:
【参考方案3】:从内部设置的request中获取参数,用于打印和处理cause
、message
等其他信息
<c:set var="exception" value="$requestScope['javax.servlet.error.exception']"/>
并打印堆栈跟踪
<!-- Stack trace -->
<jsp:scriptlet>
exception.printStackTrace(new java.io.PrintWriter(out));
</jsp:scriptlet>
另见
JSPIntro4 - Handling Errors【讨论】:
我们如何使用 "<%@page pageEncoding="UTF-8" isErrorPage="true" %>
才能启用此功能。【参考方案4】:
可能对你有帮助.. 它将在浏览器中显示异常 StackTrace
exception.printStackTrace(response.getWriter());
或者
<%
try
int test = Integer.parseInt("hola");
catch(Exception e)
**// HERE THE MAGIC BEGINS!!**
out.println("<div id=\"error\">");
e.printStackTrace(new java.io.PrintWriter(out));
out.println("</div>");
**// THE MAGIC ENDS!!**
%>
如果您在 error.jsp 顶部声明 <% page isErrorPage="true" %>
,那么您可以访问由 $exception
抛出的异常(以及所有的 getter)
<p>Message: $exception.message
查看更多..Mapping Errors to Error Screens
【讨论】:
【参考方案5】:请求转发到错误页面时,容器会设置以下参数。
javax.servlet.error.status_code javax.servlet.error.exception javax.servlet.error.message javax.servlet.error.request_uri javax.servlet.error.servlet_name javax.servlet.error.exception_type在你的错误 JSP 中这样做,
<%request.getAttribute("javax.servlet.error.exception").printStackTrace(new java.io.PrintWriter(out))%>;
否则如果您的错误页面被定义为带有Page Directive之类的错误页面,
<%@ page isErrorPage="true" import="java.io.*"%>
exception 脚本变量将在 JSP 中声明。您可以使用 scriptlet 打印脚本变量,
exception.printStackTrace(new java.io.PrintWriter(out));
或者,
<jsp:scriptlet>
exception.printStackTrace(response.getWriter())
</jsp:scriptlet>
【讨论】:
如果使用facelets你可以#requestScope['javax.servlet.error.status_code']
。【参考方案6】:
可以使用jstl核心库
1) 在 JSP 文件之上导入 tablib
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
2) 使用标签
<c:catch var="myExceptionObject">
Code that might throw Exception
</c:catch>
<c:if test="$myExceptionObject != null">
There was an exception: $myExceptionObject.message
</c:if>
【讨论】:
【参考方案7】:或者,为了避免在您的 jsp 中使用 scriptlet,请使用 jstl:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
...
<c:set var="exception" value="$requestScope['javax.servlet.error.exception']"/>
<c:if test="$exception != null">
<h4>$exception</h4>
<c:forEach var="stackTraceElem" items="$exception.stackTrace">
<c:out value="$stackTraceElem"/><br/>
</c:forEach>
</c:if>
理想情况下,不应将 scriptlet 作为最佳实践。通过 web.xml 配置显式阻止 jsp 文件中的脚本:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
【讨论】:
【参考方案8】:十年来,使用 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>
【讨论】:
我遇到的一个问题是有时堆栈跟踪会包含 JSP 行。这些在浏览器中被解释为 html。有没有办法逃避堆栈跟踪? (通常我会使用 c:out 但这不适用于这种情况。)【参考方案9】:在 error.jsp 中添加以下行
<%Logger log = Logger.getLogger("error_jsp.class");
Exception e = (Exception)request.getAttribute("javax.servlet.error.exception");
log.debug(request.getAttribute("javax.servlet.error.message"));
e.printStackTrace();
log.debug(e.getStackTrace());%>
【讨论】:
以上是关于如何在 JSP 页面中打印错误堆栈跟踪?的主要内容,如果未能解决你的问题,请参考以下文章