Каков хороший подход для пересылки исключения из сервлетов на страницу JSP?

Я знаю, что могу положить что-то в web.xml, как это

<error-page>  
   <exception-type>java.lang.Throwable</exception-type>  
   <location>/error.jsp</location>  
</error-page>

Однако страница jsp не будет показывать никакой конструктивной информации, поскольку она не получит, что именно является исключением. Я знаю, что у нас могут быть разные исключения, перенаправленные на разные страницы разными exception-type но это слишком много, чтобы написать в web.xml. Я надеюсь, что одной страницы достаточно, а другую для обработки ошибок, таких как 404.

Так как мне передать информацию об исключении на страницу JSP? Использовать сессию?

Идеальной ситуацией может быть то, что страница получает информацию об исключении и показывает некоторые соответствующие сообщения об этом, не раскрывая исключение пользователям. Вместо этого он может войти в файл для дальнейшего использования. Каков наилучший подход для достижения этого? Благодарю.

2 ответа

Решение

Информация об исключении уже доступна по нескольким атрибутам запроса. Вы можете найти имена всех этих атрибутов в RequestDispatcher Javadoc:

  • ERROR_EXCEPTION - javax.servlet.error.exeption
  • ERROR_EXCEPTION_TYPE - javax.servlet.error.exception_type
  • ERROR_MESSAGE - javax.servlet.error.message
  • ERROR_REQUEST_URI - javax.servlet.error.request_uri
  • ERROR_SERVLET_NAME - javax.servlet.error.servlet_name
  • ERROR_STATUS_CODE - javax.servlet.error.status_code

Итак, в двух словах, этот пример JSP должен отображать все возможные детали исключения:

<%@ 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>
</ul>

Кроме того, вы также можете показать эту полезную информацию:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<jsp:useBean id="date" class="java.util.Date" />
...
<ul>
    <li>Timestamp: <fmt:formatDate value="${date}" type="both" dateStyle="long" timeStyle="long" /></li>
    <li>User agent: <c:out value="${header['user-agent']}" /></li>
</ul>

Бетон Exception Сам экземпляр в JSP доступен только как ${exception} когда вы помечаете страницу как страницу ошибки:

<%@ page isErrorPage="true" %>
...
${exception}

Только если вы используете EL 2.2 или новее, вы можете напечатать его трассировку стека, как показано ниже:

<%@ page isErrorPage="true" %>
...
<pre>${pageContext.out.flush()}${exception.printStackTrace(pageContext.response.writer)}</pre>

Или, если вы еще не используете EL 2.2, создайте для этого собственную функцию EL:

public final class Functions {

    private Functions() {}

    public static String printStackTrace(Throwable exception) {
        StringWriter stringWriter = new StringWriter();
        exception.printStackTrace(new PrintWriter(stringWriter, true));
        return stringWriter.toString();
    }

}

Который зарегистрирован в /WEB-INF/functions.tld:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <display-name>Custom Functions</display-name>    
    <tlib-version>1.0</tlib-version>
    <uri>http://example.com/functions</uri>

    <function>
        <name>printStackTrace</name>
        <function-class>com.example.Functions</function-class>
        <function-signature>java.lang.String printStackTrace(java.lang.Throwable)</function-signature>
    </function>
</taglib>

И может быть использован как

<%@ taglib prefix="my" uri="http://example.com/functions" %>
...
<pre>${my:printStackTrace(exception)}</pre>

Что касается регистрации исключений, самым простым местом будет фильтр, который сопоставляется с шаблоном URL /* и делает в основном следующее:

try {
    chain.doFilter(request, response);
} catch (ServletException e) {
    log(e.getRootCause());
    throw e;
} catch (IOException e) { // If necessary? Usually not thrown by business code.
    log(e);
    throw e;
}

Да, по моему мнению, сессия является хорошим местом для хранения исключений, связанных с текущим запросом.

Не забудьте очистить исключение после завершения обработки.

Кроме того, вы можете передать вместо исключения код ошибки из вашего кода поддержки на уровень представления, где он может быть переведен с помощью файлов свойств в какое-то значение, означающее полную ошибку для пользователя.

Другие вопросы по тегам