Я работаю над веб-приложением JSF, в котором я должен поднять страницу "Session Expired", если представление истекает, но общая техническая ошибочная страница для всех других. Приложение только переходит к технической ошибочной странице, когда я инициировал исключение. Вот определения ошибочной страницы:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/jsps/utility/sessionExpired.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/jsps/utility/technicalError.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/jsps/utility/technicalError.jsp</location>
</error-page>
Я удалил technicalError.jsp ошибочные элементы страницы, и это хорошо работало, но когда я отложил их, я не могу добраться до sessionExpired.jsp страницы. Как я говорю веб-контейнеру порядок оценить эти теги так, чтобы правильная страница подошла?Спасибо.
Это происходит потому, что ViewExpiredException
обернуто в ServletException
согласно спецификации JSF. Вот выдержка из главы 10.2.6.2 спецификации JSF 1.2:
10.2.6.2 FacesServlet
Вызовите метод
execute()
сохраненного экземпляраLifecycle
, передав емуFacesCervlet
.
FacesContext
экземпляр для данного запроса в качестве параметра. Если методexecute()
выбрасываетFacesException
, повторно выбрасывайте его какServletException
с параметромFacesException
в качестве первопричины.
Как распределяются страницы ошибок, указано в спецификации Servlet API. Вот выдержка из главы 9.9.2 Servlet API specification 2.5:
SRV.9.9.2 Error Pages
Если нет
объявления error-page
, содержащегоexception-type
, подходит с использованием соответствие иерархии классов, а возникшее исключение являетсяServletException
или его подклассом, контейнер извлекает обернутое исключение, как определено вServletException
. методомServletException.getRootCause
. Второй проход выполняется над ошибкой объявления страницы ошибки, снова пытаясь найти соответствие странице ошибки но вместо этого используется обернутое исключение.
В иерархии классов ServletException
уже соответствует Throwable
, поэтому его первопричина не будет извлечена для второго прохода.
Чтобы доказать указанное поведение, замените javax.faces.application.ViewExpiredException
на javax.servlet.ServletException
как
и повторите попытку. Вы увидите ожидаемую страницу ошибки.
Чтобы решить эту проблему, просто удалите страницу ошибки на java.lang.Throwable
или java.lang.Exception
. Если ни одна страница ошибки, специфичная для исключения, не подходит, то она все равно вернется к той, которая предназначена для кода ошибки 500
. Итак, все, что вам нужно, это:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/jsps/utility/sessionExpired.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/jsps/utility/technicalError.jsp</location>
</error-page>
Update: согласно (удаленному) комментарию OP: чтобы надежно протестировать это, вы не можете сделать throw new ViewExpiredException()
в конструкторе или методе bean или так далее. Это, в свою очередь, будет обернуто в некоторое исключение EL. В конце концов, вы можете добавить отладочную строку, печатающую rootCause
в Filter
, чтобы увидеть это самостоятельно.
Если вы используете Eclipse/Tomcat, быстрый способ протестировать ViewExpiredException
заключается в следующем: