【问题标题】:How can I print error stack trace in JSP page?如何在 JSP 页面中打印错误堆栈跟踪?
【发布时间】: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。

【问题讨论】:

    标签: java jsp exception servlets jstl


    【解决方案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中获取参数,用于打印和处理causemessage等其他信息

        <c:set var="exception" value="${requestScope['javax.servlet.error.exception']}"/>
        

        并打印堆栈跟踪

        <!-- Stack trace -->
        <jsp:scriptlet>
          exception.printStackTrace(new java.io.PrintWriter(out));
        </jsp:scriptlet>
        

        另见

        【讨论】:

        • 我们如何使用 "" ?它给出编译(jsp解析)异常
        • @gtiwari333 您需要在顶部添加&lt;%@page pageEncoding="UTF-8" isErrorPage="true" %&gt; 才能启用此功能。
        【解决方案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 顶部声明 &lt;% page isErrorPage="true" %&gt;,那么您可以访问由 ${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());%>
              

              【讨论】:

                猜你喜欢
                • 2011-05-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多