Содержание
- Учебное пособие по проверке JSF: обработка ошибок в JSF
- Отображение сообщений об ошибках при просмотре
- Встроенные компоненты проверки
- Проверка с использованием методов Backing Bean
- Пользовательские компоненты проверки с использованием интерфейса Validator
- JSF Validation Tutorial: Error Handling in JSF
- Showing Error Messages on View
- Built-in validation components
- Validation using Backing Bean methods
- Custom validation components using Validator interface
- JSF Custom Error Pages
- 1. The Deployment Descriptor
- 2. Faces Configuration File
- 3. The Error Page
- JavaBeat JSF 2.2 Examples
- JSF2 – Error Handling
- 4. ErrorHandler RequestScoped Bean
- 5. Error Prone Page
- JavaBeat JSF 2.2 Examples
- JSF2 – Error Handling
- 6. Error Prone Managed Bean
- 7. JSF Error Handling Demo
- 8. JSF Without Custom Error Page
Учебное пособие по проверке JSF: обработка ошибок в JSF
В продолжение моей предыдущей статьи о создании JSF-приложения JavaServer Faces в Eclipse я публикую следующую статью из этой серии. На этот раз мы расскажем подробнее о модели проверки JSF и обработке ошибок в JSF.
Технология JavaServer Faces поддерживает механизм проверки данных редактируемых компонентов. Каждый компонент в JavaServer Faces создает сообщения об ошибках в течение жизненного цикла JSF и присоединяет их к объекту FacesContext. Следовательно, каждое сообщение присоединяется к компоненту в дереве компонентов, и сообщение отображается в представлении в конце жизненного цикла JSF.
Отображение сообщений об ошибках при просмотре
JSF предоставляет различные теги для обработки и отображения сообщений в представлении. В эталонной реализации Sun библиотеки JSF HTML есть два тега сообщения:
h: messages используется для отображения всех сообщений одновременно. Вы можете разместить тег h: messages в начале вашей формы. Вам может потребоваться отображать только глобальные сообщения, используя тег h: messages. Для отображения только глобальных сообщений установите для атрибута globleOnly значения h: messages значение true.
Используйте h: message для отображения сообщения, прикрепленного к одному компоненту. Атрибут at = «» может использоваться для указания идентификатора компонента, чьи сообщения об ошибках нам нужно отобразить. H: сообщение используется для отображения сообщения об ошибке рядом с компонентом, который сгенерировал ошибку. Если к сообщению прикреплено более одного сообщения этот компонент, h: message будет отображать последнее сообщение.
Каждое сообщение может иметь краткое описание и подробное описание. При использовании тега h: message по умолчанию показывается подробное сообщение. При использовании тега h: messages по умолчанию отображаются сводные описания. Чтобы изменить значения по умолчанию, измените логические атрибуты showSummary и showDetail .
Вы также можете включить отображение подробного сообщения компонента в виде всплывающей подсказки. Для этого установите для атрибута подсказки тега сообщения значение true. Обратите внимание, что для включения этой опции для showDetail и showSummary должно быть установлено значение true.
Существует четыре формы проверки JSF:
1. Встроенные компоненты проверки
2. Проверка уровня приложения
3. Пользовательские компоненты проверки с использованием интерфейса Validator
4. Методы проверки в компонентах поддержки
Встроенные компоненты проверки
Эталонная реализация Sun JSF предоставляет некоторые компоненты проверки по умолчанию, которые можно использовать для проверки любого пользовательского ввода. Базовая библиотека JSF предоставляет теги для проверки ввода. Ниже приведены несколько тегов, которые можно использовать для проверки ввода.
f: validateDoubleRange : этот тег проверяет значение компонента в указанном диапазоне. Значение должно быть преобразовано в тип с плавающей точкой или саму плавающую точку.
f: validateLength : этот тег проверяет длину значения и ограничивает его в пределах указанного диапазона. Значение должно иметь тип java.lang.String.
f: validateLongRange : Проверяет, находится ли значение компонента в указанном диапазоне. Значение должно иметь числовой тип или строку, конвертируемую в long.
Пример:
Проверка с использованием методов Backing Bean
Метод базового компонента может использоваться для проверки любого поля ввода. Сначала нам нужно создать метод вспомогательного компонента, который будет вызываться в процессе проверки. Подпись метода может быть:
Как только метод вспомогательного компонента будет готов, мы можем связать его с компонентом, используя тег f: validator .
В приведенном выше фрагменте мы связали метод userBean checkUsername () с компонентом inputText. Можно связать более одного валидатора с одним компонентом.
Метод проверки базового компонента прост в реализации, но этот метод специфичен для одного приложения и не может быть повторно использован для другого приложения. Для создания универсальных валидаторов, которые можно использовать в разных приложениях, можно использовать интерфейс Validator.
Пользовательские компоненты проверки с использованием интерфейса Validator
Интерфейс Validator может быть расширен, и может быть создан специальный валидатор, который можно повторно использовать в различных приложениях в JSF. Чтобы создать собственный валидатор, нам нужно создать класс Java, который реализует интерфейс javax.faces.validator.Validator . Интерфейс Validator предоставляет метод validate (), который необходимо реализовать. Ниже приведена подпись метода validate ().
После того, как Валидатор реализован, нам нужно зарегистрировать этот валидатор в файлеface-config.xml. Для этого скопируйте следующий код вface-config.xml, предполагая, что наше имя класса валидатора — net.viralpatel.jsf.helloworld.EmailValidator.
Мы можем связать этот валидатор с любым компонентом, используя тег f: validator.
Обратите внимание, что в приведенном выше фрагменте кода атрибут validatorId тега f: validator указывает на идентификатор валидатора, который зарегистрирован в файлеface-config.xml.
Для проверки адреса электронной почты мы можем создать класс Validator как:
Таким образом, используя платформу JSF Validation, можно легко проверить вводимые пользователем данные. Мы видели разные способы проверки в JSF: валидаторы по умолчанию, методы поддержки bean-компонентов и валидация через интерфейс валидатора.
Дайте мне знать ваши комментарии об этом уроке.
Источник
JSF Validation Tutorial: Error Handling in JSF
Join the DZone community and get the full member experience.
In a continuation of my previous article on Creating JavaServer Faces JSF application in Eclipse , I am posting the next article in the series. This time we will cover details about JSF Validation Model and Handling Errors in JSF.
JavaServer Faces technology supports a mechanism for validating the data of editable components. Each component in JavaServer Faces creates Error Messages during the life cycle of JSF and attaches them to FacesContext object. Hence each message is attached to a component in the component tree and the message is displayed into the view at the end of JSF life cycle.
Showing Error Messages on View
JSF provides different tags to handle and display messages on the view. There are two message tags in Sun’s reference implementation of JSF HTML library:
h:messages is used to display all messages at once. You can place h:messages tag in start of your form. You may need to display only global messages using h:messages tag. For displaying only global messages set globleOnly attribute of h:messages to true.
Use h:message to display message attached to one component. An attibute for=”» can be used to specify the id of a component whose error messages we need to display. h:message is used to display error message next to the component that generated the error. If more then one message is attached to that component, h:message will display the last message.
Each message can have a summary description and a detailed description. When using the h:message tag, the default is to show the detail message. When using the h:messages tag, the default is to display the summary descriptions. To change the defaults, modify the boolean showSummary and showDetail attributes.
You can also enable a component’s detail message to appear as a tooltip. To do so, set tooltip attribute of message tag to true. Note that for enabling this option, showDetail and showSummary must be set to true.
There are four forms of JSF validation:
1. Built-in validation components
2. Application level validations
3. Custom validation components using Validator interface
4. Validation methods in backing beans
Built-in validation components
Sun’s reference implementation of JSF provides some default validation components that can be leveraged to implement validation of any user input. The JSF core library provides tags to validate input. The following are a few tags that can be used to validate the input.
f:validateDoubleRange : This tag checks the value of a component within specified range. The value must be convertible to floating-point type or a floating-point itself.
f:validateLength : This tag checks the length of a value and restricts it within a specified range. The value must be of type java.lang.String.
f:validateLongRange : Checks if a component value is within a specified range. The value must be of numeric type or string convertible to a long.
Example:
Validation using Backing Bean methods
A backing bean method can be used for doing validation of any input field. First we need to create the backing bean method that will get called during validation process. The signature of the method can be:
Once a backing bean method is ready we can bind it with a component using f:validator tag.
In above snippet, we have bound the checkUsername() method of userBean to the inputText component. It is possible to bind more than one validator to one component.
THe backing bean method of validation is easy to implement, but this method is specific for one application and may not be reused for different application. To create generic validators which can be used in different application, the Validator interface can be used.
Custom validation components using Validator interface
The Validator interface can be extended and a custom validator can be created which can be reused across different applications in JSF. To create a custom validator, we need to create a Java class that implements javax.faces.validator.Validator interface. The Validator interface provides a validate () method that needs to be implemented. The following is the signature of validate() method.
Once the Validator is implemented, we need to register this validator in faces-config.xml file. To do so copy following code in faces-config.xml assuming that our validator class name is net.viralpatel.jsf.helloworld.EmailValidator.
We can bind this validator to any component using f:validator tag.
Note that in the above code snippet, the validatorId attribute of f:validator tag points to the validator’s ID that is registered in faces-config.xml file.
For validating email address we can create a Validator class as:
Thus by using the JSF Validation framework, it is possible to validate user input easily. We saw different ways of validation in JSF: Default validators, backing bean methods and validation through validator interface.
Let me know your comments about this tutorial.
Opinions expressed by DZone contributors are their own.
Источник
JSF Custom Error Pages
When you run an application in the development project stage and you encounter an error, you get an error message in an undesirable form. You probably don’t want your users to see that message in such that ugly way.
To substitute a better error page, use error-page tag in the web.xml file, in that you can specify either a Java Exception or an HTTP error code. So in case the type of thrown exception has matched that type mentioned in the web.xml exception-type or the error code that generated by the server has matched error-code that mentioned in the web.xml, the JSF framework will handle it by forwarding the user into the desired view that you’ve defined for such those errors or exceptions.
1. The Deployment Descriptor
web.xml
[code lang=”xml”]
404
/faces/error.xhtml
500
/faces/error.xhtml
java.lang.Exception
/faces/error.xhtml
State saving method: ‘client’ or ‘server’
(=default). See JSF Specification 2.5.2
Faces Servlet
javax.faces.webapp.FacesServlet
1
Faces Servlet
/faces/*
Faces Servlet
*.xhtml
[/code]
- The error codes that being handled in that defined web.xml are 500 and 400.
- The exceptions that being handled in that defined web.xml is the root of exceptions that could be thrown java.lang.Exception.
- All of the defined error codes and exceptions must be handled in a compelling error page called error.xhtml.
2. Faces Configuration File
faces-config.xml
- No changes are made on the faces configuration to support the error page concept
3. The Error Page
error.xhtml
JavaBeat JSF 2.2 Examples
JSF2 – Error Handling
4. ErrorHandler RequestScoped Bean
ErrorHandler.java
[code lang=”java”]
package net.javabeat.jsf.error;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
@ManagedBean
@RequestScoped
public class ErrorHandler <
public String getStatusCode() <
String val = String.valueOf((Integer)FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.status_code»));
return val;
>
public String getMessage() <
String val = (String)FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.message»);
return val;
>
public String getExceptionType() <
String val = FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.exception_type»).toString();
return val;
>
public String getException() <
String val = (String)((Exception)FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.exception»)).toString();
return val;
>
public String getRequestURI() <
return (String)FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.request_uri»);
>
public String getServletName() <
return (String)FacesContext.getCurrentInstance().getExternalContext().
getRequestMap().get(«javax.servlet.error.servlet_name»);
>
- The error handler bean is defined as RequestScoped
- Several objects related to the error are placed in the Request Map and they are considered as Servlet Exception Attributes
5. Error Prone Page
index.xhtml
JavaBeat JSF 2.2 Examples
JSF2 – Error Handling
6. Error Prone Managed Bean
IndexBean.java
[code lang=”java”]
package net.javabeat.jsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class IndexBean <
private String message;
public String getMessage() <
return message;
>
public void setMessage(String message) <
this.message = message;
>
public String navigate() <
// Assume an exception has been thrown by some business logic
System.out.println(10/0);
return «anonymousView»;
>
>
[/code]
7. JSF Error Handling Demo
The below snapshots show you how could a thrown exception being handled in a compelling view.
8. JSF Without Custom Error Page
The below snapshot shows you the ugly page that might be displayed for the users while they are navigating your site.
Источник
{scrollbar}
Error handling for MyFaces Core 2.0 and later versions
Since JSF 2.0, it is possible to provide a custom javax.faces.context.ExceptionHandler or javax.faces.context.ExceptionHandlerWrapper implementation to deal with exceptions. To do that, just create your custom class, an factory that wrap/override it and add the following into your faces-config.xml:
faces-config.xml<faces-config 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-facesconfig_2_0.xsd»
version=»2.0″>
<!— … —>
<factory>
<!— … —>
<exception-handler-factory>org.apache.myfaces.context.ExceptionHandlerFactoryImpl</exception-handler-factory>
<!— … —>
</factory>
<!— … —>
</faces-config>
This is an example of an ExceptionHandlerFactory, from myfaces code:
ExceptionHandlerFactoryImpl.javapublic class ExceptionHandlerFactoryImpl extends ExceptionHandlerFactory
{
@Override
public ExceptionHandler getExceptionHandler()
{
return new SwitchAjaxExceptionHandlerWrapperImpl(
new MyFacesExceptionHandlerWrapperImpl(new ExceptionHandlerImpl()) ,
new AjaxExceptionHandlerImpl());
}
}
If you need a wrapper:
ExceptionHandlerFactoryImpl.javapublic class ExceptionHandlerFactoryImpl extends ExceptionHandlerFactory
{
@Override
public ExceptionHandler getExceptionHandler()
{
return new CustomExceptionHandlerWrapper(getWrapped().getExceptionHandler());
}
}
The most important method to override is ExceptionHandler.handle()
.
MyFacesExceptionHandlerWrapperImpl.javapublic class MyFacesExceptionHandlerWrapperImpl extends ExceptionHandlerWrapper
{
//…
public void handle() throws FacesException
{
//… some custom code goes here …
}
}
Take a look at MyFaces Core source code, to know in detail how ExceptionHandler implementations works.
MyFaces ExceptionHandler
MyFaces Core provide a custom ExceptionHandler to deal with exceptions and provide detailed information about it. Since 2.0.8/2.1.2 this is disabled on Production environments unless it enabled on web.xml file. Don’t forget to provide your custom error page in this scenario, to prevent show more information than necessary.
xml <context-param>
<param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
<param-value>true</param-value>
</context-param>
<!— if you want to use a different resource template file than
«META-INF/rsc/myfaces-dev-error.xml» this param let you configure
it. (since 1.2.4-SNAPSHOT and 1.1.6-SNAPSHOT)—>
<context-param>
<param-name>org.apache.myfaces.ERROR_TEMPLATE_RESOURCE</param-name>
<param-value>META-INF/rsc/custom-dev-error.xml</param-value>
</context-param>
Provide an error page
If org.apache.myfaces.ERROR_HANDLING is set to «false», or if it is undefined and the project stage is «Development», the default ExceptionHandler just throws an exception. So you can still setup an error page by adding something like this in your web.xml file:
xml <error-page>
<error-code>500</error-code>
<location>/somepage.jsp</location>
</error-page>
Error handling for MyFaces Core 1.2 and earlier versions
MyFaces, from version 1.2.1 and 1.1.6, includes automatic error-handling for the full JSF-Lifecycle (taken over mostly from Facelets, with a few adoptions and additions). So for most projects during development, you will have exactly what you want with these new error-handling possibilities.
If this is not what you want, though, you can always disable or modify this error-handling with the following parameters:
xml <!— if you want to disable the behaviour completely —>
<context-param>
<param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
<param-value>false</param-value>
</context-param>
<!— if you are using myfaces + facelets don’t forget to do this —>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>false</param-value>
</context-param>
<!— if you want to use a different resource template file than
«META-INF/rsc/myfaces-dev-error.xml» this param let you configure
it. (since 1.2.4-SNAPSHOT and 1.1.6-SNAPSHOT)—>
<context-param>
<param-name>org.apache.myfaces.ERROR_TEMPLATE_RESOURCE</param-name>
<param-value>META-INF/rsc/custom-dev-error.xml</param-value>
</context-param>
<!— if you want to choose a different class for handling the exception — the error-handler needs to include a method handleException(FacesContext fc, Exception ex)—>
<context-param>
<param-name>org.apache.myfaces.ERROR_HANDLER</param-name>
<param-value>my.project.ErrorHandler</param-value>
</context-param>
If you do this, you can now read on to get to general ways of handling server-errors.
Server errors such as HTTP 500 can occur for a number of reasons such as uncaught exceptions, missing JSFs or backing beans, bad URL and the list goes on. While we hope these only occur during development it is important to plan to catch and deal with these errors gracefully when running live with multiple users.
Several approaches have been discussed on the mailing list:
Use default handler
Myfaces has a default error handler (class javax.faces.webapp._ErrorPageWriter) that uses a jsp template file (META-INF/rsc/myfaces-dev-error.xml and META-INF/rsc/myfaces-dev-debug.xml) to handle errors.
For define a custom template file:
xml <context-param>
<param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ERROR_TEMPLATE_RESOURCE</param-name>
<param-value>META-INF/rsc/mycustom-template-error.xml</param-value>
</context-param>
Use sandbox org.apache.myfaces.tomahawk.util.ErrorRedirectJSFPageHandler
This handler uses myfaces error handling feature, redirecting to a jsf page when an error occurs.
An example jsf page for redirect can be found at http://issues.apache.org/jira/browse/TOMAHAWK-1297
This class is set as a config-parameter org.apache.myfaces.ERROR_HANDLER
available on myfaces core jsf. (This does not work with RI)
The idea is extends myfaces error handling feature, making possible to redirect
to a jsf page when an error occur, using navigation rules.
If this handler is not able to handle the error, an alternate error handler
could be set in the config-parameter org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER
The info of the error in the jsf page can be found using:
#{exceptionContext.cause} : Cause retrieved from the exception
#{exceptionContext.stackTrace} : Stack trace of the exception
#{exceptionContext.exception} : Exception handled by this page
#{exceptionContext.tree} : Print the component tree of the page that cause the error
#{exceptionContext.vars} : Enviroment variables from the request
Using servlets
Mert Caliskan (http://www.jroller.com/page/mert?entry=handling_errors_with_an_errror) describes an approach which wraps the JSF servlet with a new servlet which delegates to the faces servlet but handles uncaught exceptions allowing the developer to redirect to a custom error page.
Andrea Paternesi has refined this technique for MyFaces as described here:
[http://patton-prog-tips.blogspot.com/2008/10/myfaces-handling-viewexpiredexception.html]
With JSF
Another approach is described in the book ‘Core Server Faces’ which uses the servlet engine to catch the error and delegate to a JSF error page. While not as elegant as the first approach this method has several advantages for some users
1 It uses a standard JSP approach and framework<<BR>>
2 It does not require custom servlets<<BR>>
3 It can easily be customized/changed by simply changing the error handler definition in the web.xml<<BR>>
To implement this method perform the following steps
1 define an error handling web page in web.xml
xml <error-page>
<error-code>500</error-code>
<location>/ErrorDisplay.jsf</location>
</error-page>
2 Create the error handler display. Due to a problem with the JSF 1.1 specification, the error handling page cannot use a <f:view> but must use a subview.
xml<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>
<f:subview id=»error»
xmlns:f=»http://java.sun.com/jsf/core»
xmlns:t=»http://myfaces.apache.org/tomahawk»
xmlns:h=»http://java.sun.com/jsf/html»>
<html>
<head>
<meta content=»no-cache» http-equiv=»Cache-Control» />
<meta content=»no-cache» http-equiv=»Pragma» />
<title>CMS — Error</title>
<t:stylesheet path=»#{SessionBean.styleSheet}» />
</head>
<body>
<h:form>
:
: set up the normal view
:
<h:outputText styleClass=»infoMessage» escape=»false» value=»#{ErrorDisplay.infoMessage}» />
<t:htmlTag value=»br» />
<h:inputTextarea style=»width: 99%;» rows=»10″ readonly=»true» value=»#{ErrorDisplay.stackTrace}» />
:
: more view stuff
:
</h:form>
</body>
</html>
</f:subview>
3 Create a backing bean in request scope which can process the error. (don’t forget to register it on faces-config.xml)
ErrorDisplay.javaimport cms.beans.framework.AbstractUIBean;
import com.c2gl.jsf.framework.ApplicationResource;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
public class ErrorDisplay extends AbstractUIBean {
private static final long serialVersionUID = 3123969847287207137L;
private static final String BEAN_NAME = ErrorDisplay.class.getName();
public String getInfoMessage() {
return «An unexpected processing error has occurred. Please cut and paste the following information» + » into an email and send it to <b>» +
some email address + «</b>. If this error » + «continues to occur please contact our technical support staff at <b>» +
some phone number etc + «</b>.»;
}
public String getStackTrace() {
FacesContext context = FacesContext.getCurrentInstance();
Map requestMap = context.getExternalContext().getRequestMap();
Throwable ex = (Throwable) requestMap.get(«javax.servlet.error.exception»);
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
fillStackTrace(ex, pw);
return writer.toString();
}
private void fillStackTrace(Throwable ex, PrintWriter pw) {
if (null == ex) {
return;
}
ex.printStackTrace(pw);
if (ex instanceof ServletException) {
Throwable cause = ((ServletException) ex).getRootCause();
if (null != cause) {
pw.println(«Root Cause:»);
fillStackTrace(cause, pw);
}
} else {
Throwable cause = ex.getCause();
if (null != cause) {
pw.println(«Cause:»);
fillStackTrace(cause, pw);
}
}
}
}
Also have a look at our ExceptionUtils class. It encapsulates the way how to get the real root cause
java [1] List exceptions = ExceptionUtils.getExceptions(exception);
[2] Throwable throwable = (Throwable) exceptions.get(exceptions.size()-1);
[3] String exceptionMessage = ExceptionUtils.getExceptionMessage(exceptions);
1 get a list of all exceptions — using getRootCause if available or getCause<<BR>>
2 get the initial exception<<BR>>
3 get the first exception with an message starting with the initial exception
So the new fillStackTrace become
java private void fillStackTrace(Throwable ex, PrintWriter pw)
{
if (null == ex) {
return;
}
List exceptions = ExceptionUtils.getExceptions(exception);
Throwable throwable = (Throwable) exceptions.get(exceptions.size()-1);
for (int i = 0; i<exceptions.size(); i++)
{
if (i > 0)
{
pw.println(«Cause:»);
}
throwable.printStackTrace(pw);
}
}
In the backing bean we construct a message which informs the user that something we didnt’t plan for has happened with directions on who to call, what to do etc. We don’t really care if they actually do cut-and-paste the error and email it to us as it is also in Tomcat’s logs but giving the user something to do and become part of resolving the problem is always a good idea
ViewExpiredException: No saved view state could be found for the view identifier
In some configurations, you might run into this problem exception with the error handling method shown above. This will happen if an error results in a forward, rather than redirect. The »ViewHandler» will call »response.sendError()» in case of an error, which will lookup your »<error-page>» declarations in »web.xml» and forward to the error url. If the error url is picked up by the »FacesServlet» (i.e. it’s a JSF url), a new JSF lifecycle will be started. However, since this is a forward, the request object will still contain all of the request parameters, including »»javax.faces.ViewState»», which makes the request look like a postback to the »ViewHandler». Since it’s a postback, the »ViewHandler» will expect a saved view, which is clearly not going to be there, since our »viewId» is now referencing the error page.
This problem can be solved by customizing the »ViewHandler» to use »response.sendRedirect()» instead of »response.sendError()», but that will mean that we can no longer use »web.xml» for specifying the error page mappings.
Another way to handle this would be to use an intermediate step by specifying a non-JSF URL as the error page and then somehow redirecting to the JSF error page. For example, for the 404 error code you could specify »/error/404_redirect.html»:
xml<html><head><meta http-equiv=»Refresh» content=»0; URL=/DPSV4/error/404.jsf»></head></html>
This works, but requires you to hard code the context path.
The solution I ended up with involves a »RedirectServlet»:
RedirectServlet.javapublic class RedirectServlet extends HttpServlet {
private static final String URL_PREFIX = «url=»;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String query = req.getQueryString();
if ( query.contains(URL_PREFIX) ) {
String url = query.replace(URL_PREFIX, «»);
if ( !url.startsWith(req.getContextPath()) ) {
url = req.getContextPath() + url;
}
resp.sendRedirect(url);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
used like this in »web.xml»:
xml <servlet>
<servlet-name>Redirect Servlet</servlet-name>
<servlet-class>ca.gc.agr.ops.web.jsf.redirect.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Redirect Servlet</servlet-name>
<url-pattern>/redirect</url-pattern>
</servlet-mapping>
<error-page>
<error-code>403</error-code>
<location>/redirect?url=/error/403.jsf</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/redirect?url=/error/404.jsf</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/redirect?url=/error/500.jsf</location>
</error-page>
With plain JSP
If you didn’t require any JSF functionality in your JSP page it might be worth to consider using the following error.jsp
[http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/examples/simple/src/main/webapp/error.jsp?view=markup]
with this web.xml configuration
xml <error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
This reduces the number of technologies required to show the error page which might improve the availablity of this page
Custom error handler under Apache Geronimo JavaEE server
If you would use your own error handler (org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER) under Apache Geronimo, you must set properly your deployment plan (geronimo-web.xml usualy), otherwise you will have classloading problem of your class. By default the MyFaces classes are loaded to your classpath through dependencies at org.apache.geronimo.framework.jee-specs/CAR. This is OK for common cases, but if you instruct MyFaces to use your own error handler class, you get the error because MyFaces cannot find your class in calling class.forName(). Avoid this situation is quite simple — in your deployment plan specify dependencies on myfaces-api and myfaces-impl and then modify classloading via hidden-classes setting.
A fragment of your dependency plan would be like this:
xml<dep:dependencies>
.
.
<dep:dependency>
<dep:groupId>org.apache.myfaces.core</dep:groupId>
<dep:artifactId>myfaces-api</dep:artifactId>
<dep:type>jar</dep:type>
</dep:dependency>
<dep:dependency>
<dep:groupId>org.apache.myfaces.core</dep:groupId>
<dep:artifactId>myfaces-impl</dep:artifactId>
<dep:type>jar</dep:type>
</dep:dependency>
.
.
</dep:dependencies>
<dep:hidden-classes>
<dep:filter>javax.faces</dep:filter>
<dep:filter>org.apache.myfaces</dep:filter>
</dep:hidden-classes>
This solution was tested under Apache Geronimo 2.1.3., but will probably be similar in other versions.{scrollbar}
JSF Error Pages That Actually Work
Here is an annoying problem using JSF error pages for JSF requests. Everything looks just fine, HttpServletResponse.sendError() sends the error page, but JSF continues processing and starts throwing exceptions after the response is complete. This happens even if you call FacesContext.responseComplete(), and also when the error page is sent at different stages of the JSF lifecycle.
It seems like invoking the FacesServlet for sendError() breaks the state of the original FacesContext.
When sending an error during view build I get this exception:
JSF Error Pages That Actually Work
java.lang.NullPointerException at com.sun.faces.facelets.util.Resource.getResourceUrl(Resource.java:105) at com.sun.faces.facelets.impl.DefaultResourceResolver.resolveUrl(DefaultResourceResolver.java:77) at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:229) at com.sun.faces.facelets.impl.DefaultFacelet.getRelativePath(DefaultFacelet.java:273) at com.sun.faces.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:341) at com.sun.faces.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:199) at com.sun.faces.facelets.tag.ui.DecorateHandler.apply(DecorateHandler.java:145) at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93) at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:86) at com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:149) at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:838) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:100) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
and if renderView() has already started, it gets even more obscure:
java.lang.NullPointerException at org.richfaces.skin.SkinFactoryImpl.clearSkinCaches(SkinFactoryImpl.java:94) at org.richfaces.skin.SkinFactoryPreRenderViewListener.processEvent(SkinFactoryPreRenderViewListener.java:35) at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106) at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2169) at com.sun.faces.application.ApplicationImpl.invokeListenersFor(ApplicationImpl.java:2145) at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:303) at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:247) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:108) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)P
JSF continues to RENDER phase in an all messed up drunken way.
- Calling FacesContext.responseComplete() from your managed bean’s @PostConstruct method doesn’t help because rendering has already started.
- Additionally, calling FaceContext.responseComplete() from a preRenderView listener just doesn’t work. It looks like the preRenderView event is added during view construction which happens in the Render View phase anyway. Could this be a regression bug?
- Finally, throwing an exception to be caught by an error filter or exception handler doesn’t resolve the problem because JSF swallows the exception from @PostConstruct and rethrows its own.
I couldn’t believe something so basic should be so complicated.
Well it turns out there is a fairly simple solution. Calling reponse.setStatus() instead of response.sendError() does not interrupt the JSF lifecycle. This works nicely, except the original view is still rendered in spite of the error.
So all we have to do is manually render a new view (the error page) as soon as the error occurs. This doesn’t break JSF state and lets the lifecycle finish without all those random exceptions.
Here’s what I’m talking about.
/** * The standard request.sendError() breaks JSF state if it is called * too late in the lifecycle. This method does the same thing but * copes better with interrupting the current request. */ public void sendError(FacesContext faces, int code, String message) { try { faces.getExternalContext().setResponseStatus(code); faces.getExternalContext().getRequestMap().put ("javax.servlet.error.message", message); ViewHandler views = faces.getApplication().getViewHandler(); String template = "/error/" + code + ".xhtml"; UIViewRoot view = views.createView(faces, template); faces.setViewRoot(view); views.getViewDeclarationLanguage(faces, template). buildView(faces, view); views.renderView(faces, view); faces.responseComplete(); } catch (IOException ioe) { throw new RuntimeException(ioe); } }
This method works any time before the view has started rendering. Normally it should be triggered during the view build by an event or managed bean @PostConstruct method. In fact it also works during the render phase but you get a mixed up response (see the comments below).
Hope you find that useful.
NB: if you use this method yourself, don’t forget to update the code with the correct path of your error templates.
About Roger Keays
Roger Keays is an artist, an engineer, and a student of life. He has no fixed address and has left footprints on 40-something different countries around the world. Roger is addicted to surfing. His other interests are music, psychology, languages, the proper use of semicolons, and finding good food. |
For me, 3 lines was enough:
FacesContext fc = FacesContext.getCurrentInstance();
((HttpServletResponse) fc.getExternalContext().getResponse()).sendError(404);
fc.responseComplete();
Hello Roger,
I need your help, How do I implement this method in my app?
Thanks!
I just tried this little experiment:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:outputText value="Hello World!"/> <h:outputText value="${ui.sendError(facesContext, 404, 'Woah')}"/> <h:outputText value="Error Sent"/> </ui:composition>
And it returned a 404 with «Hello World», my error page AND «Error Sent». It’s all combined because everything is running in the same FacesContext, but notice that the call to responseComplete() doesn’t terminate the rendering once it has already started.
You have to make sure it happens before (or while) the view is being built to prevent the render occurring. From most Facelets and JSTL tags it will work.
Thanks for that tip! Ran into the same issue recently, too. And thought about the same «I couldn’t believe something so basic should be so complicated»
I still have one question: Will this also work if JSF has already started rendering the page? I.e. not only using this approach to handle an error that occurs in a postConstruct or preRenderView method but for an error that comes from a method that is used e.g. in some rendered attribute? Have you tested that? Or would such an exception then be caught by a JSF ExceptionHandler (where you could use your sendError method)?
Recommended
Speed up your PC today with this easy-to-use download.
If you are getting a jsf error page redirect error, this tutorial was written to help you.
posted 10 years ago
-
Maximum number of fragments to send:
Optional Thank You Note:
I am trying (using jsf) to redirect errors to error url error.jsp but the following may not work (is part of most web.xml)
because when I try to access a page that may not be in my tool, the page is rendered thanks to the codeHTTP status 404
There might be something private in the above code, which is really the best way to redirect JSF errors to an instance in the spot error pages, if possible.
posted 10 years ago
-
Number associated with the bands sent:
Recommended
Is your PC running slow? Do you have problems starting up Windows? Don’t despair! ASR Pro is the solution for you. This powerful and easy-to-use tool will diagnose and repair your PC, increasing system performance, optimizing memory, and improving security in the process. So don’t wait — download ASR Pro today!
- 1. Download ASR Pro
- 2. Follow the on-screen instructions to run a scan
- 3. Restart your computer and wait for it to finish running the scan, then follow the on-screen instructions again to remove any viruses found by scanning your computer with ASR Pro
Optional: thanks:
How does JSF redirect to a new page?
I changed the path as follows
by the way, the exact code above redirects to error.jsp if it turns out that there is an error, but the information is from the error. when the jsp is not displaying correctly, I mean only empty messages are displayed …….. ..
Can an individualReal help to help me display all contents of error.jsp correctly …………………….
Published 10 years ago
-
Number of fragments to send:
Optional note: “Thank you”
posted 10 years ago
-
Number of fragments to send:
Optional note: “Thank you”
When a dream comes true because it needs to come true – OCPJP 6.7. OCE JPA EE6. mcts
Hopefully this example shows the error information you need.
How to perform page forward in JSF server?
posted 10 years ago
-
count of all slices too
Additional Submission: “Thank you” Please note the following:
When the dream ends and plans come true – OCPJP 6.7. OCE JPA EE6. MCTS
I don’t remember telling you that if you use any of these mechanisms to display errors on the web, you will have several objects with important information that will show up in the requirements map.
Key | Value | Type |
javax.servlet.error.status_code | HTTP Error Code | Integer |
javax.servlet.error.message | Description of your current error | String |
javax.servlet.error.Exception_type | University of Exceptions | class |
javax.servlet.error.Exception | Exception object | May be thrown |
javax.servlet.error.request_uri | Development resource application path who fell on Error | line |
javax.servlet.error.servlet_name | Name of all servlets that An error occured | String |
For example, if you need to get a page that is throwing an exception, you can do this,
posted 10 years ago
-
Number of items to send:
Optional: thanks:
I have implemented your code here, but I have some error
In my application, I want to navigate to an error in the global web page every time an exception is thrownenie. The RuntimeException
is handled, tested, and continually generated again. For this, I provide a Faces config with a specific global navigation rule:
* error /error.xhtml
And in my catch
block, I’m trying to navigate like this:
FacesContext fctx implies FacesContext.getCurrentInstance ();Application application = fctx.getApplication ();NavigationHandler navHandler is the same as application.getNavigationHandler ();navHandler.handleNavigation (fctx, null, "error");
But that doesn’t seem to work. I am abruptly throwing a very exception
, but it doesn’t move to the error page I wanted.
requested on November 24, 2012 at 2:07 pm
26.7k
Not The Answer You Are Looking For? Check Out Other Questions About Java Jsf-2 Exception Handling On The Navigationfaces-config Page Or Ask Your Own Question.
I would probably suggest refocusing the error
page with ExternalContext
. You should set your exception
to positive positive web.xml
FacesContext-environment = FacesContext.getCurrentInstance ();External context extContext = context.getExternalContext ();Hyperlink string = extContext.encodeActionURL (extContext.getRequestContextPath () + "/ error");extContext.redirect (URL);
java.lang.Exception / error
When using Jboss-Seam
, it is effective to redirect the error / warning pages
to handle the exception
.
# messages ['org.jboss.seam.NotLoggedIn'] Unexpected error, please try again
answered Nov 24 12 at 14:42
8 986
Speed up your PC today with this easy-to-use download.
Przekierowanie Strony Bledu Jsf
Redirecionamento De Pagina De Erro Jsf
Jsf 오류 페이지 리디렉션
Jsf Foutpagina Omleiding
Reindirizzamento Della Pagina Di Errore Jsf
Redireccion De Pagina De Error Jsf
Jsf Fehlerseitenumleitung
Jsf Felsida Omdirigering
Perenapravlenie Stranicy Oshibki Jsf
Redirection De Page D Erreur Jsf
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
Hi All ,
I am trying ( using jsf ) to redirect the errors to the error page errors.jsp , but the following does not work ( part of web.xml)
because when i am trying to access a page which does not exist in my application it display the page with code
HTTP Status 404
is my there anything wrong in my above code , what is the best way to redirect jsf errors to error pages with example if possible.
Suresh Khant
Ranch Hand
Posts: 118
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
Hi All ,
I have changed the code as the following
error.jsp
by the way the above code redirect to error.jsp if there is error but the contents of error.jsp will not be displayed properly i mean only blank page will be displayed ……….
any one can help me to display the content of error.jsp properly…………………….
Suresh Khant
Ranch Hand
Posts: 118
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
any reply
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
Hi Suresh
Try with this example
This is the web.xml
The errorDisplay.xhtml
And the Managed Bean «error»
I hope this example will serve to show the error information that you need.
Regards
Cesar
When a dream is ending because to come true — OCPJP 6,7. OCE JPA EE6. MCTS
Cesar Loachamin
Ranch Hand
Posts: 90
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
Hi Suresh
I forgot to tell you, when you use the this mechanism to show error page you have several objects that contains important information, that objects are placed in the request map.
Key | Value | Type |
javax.servlet.error.status_code | The HTTP error code | Integer |
javax.servlet.error.message | A description of the error | String |
javax.servlet.error.exception_type | The class of the exception | Class |
javax.servlet.error.exception | The exception object | Throwable |
javax.servlet.error.request_uri | The path to the application resource that encountered the error |
String |
javax.servlet.error.servlet_name | The name of the servlet that encountered the error |
String |
For example if you need to get the page that produce the exception you can do it,
Regards
Cesar
When a dream is ending because to come true — OCPJP 6,7. OCE JPA EE6. MCTS
Suresh Khant
Ranch Hand
Posts: 118
posted 12 years ago
-
Number of slices to send:
Optional ‘thank-you’ note:
Thanks Cesar for you reply ,
I have implemented your above code but I have got new error
when redirecting to exception.jsf
Any suggestion
t’s been a while since I last blogged. I keep thinking of blogging
something technical but end up getting busy with other things. This last
week there was a very interesting discussion at the coderanch forums. It was even more interesting because it involved JBoss
Developers
familiar with Java EE web applications would know that the web
application deployment descriptor (web.xml) allows you to specify «error
pages» which the container will display when a specific exception
(class) or a error code is thrown by the server for a web request.
Here’s a quick example of how it looks like:
<web-app> ... <!-- A custom error page for error code == 500 --> <error-page> <error-code>500</error-code> <location>/my-foo-bar-500-page.html</location> </error-page> <!-- A custom error page for exception type org.myapp.foo.bar.MyException --> <error-page> <exception-type>org.myapp.foo.bar.MyException</exception-type> <location>/my-foo-bar-exception-page.html</location> </error-page> ... </web-app>
Simple enough — a couple of custom error pages defined for a
specific error code and an exception type respectively. All of this
works fine.
In current days, more and more programming models and
frameworks come into picture while developing web applications. CDI and
JSF are some of those. CDI has this concept of scopes (ex: request
scope, session scope, application scope, conversation scope). We won’t
go into the details of what those are and when those are used, but let’s
consider conversation scope in this blog since that’s what the
discussion was about in the forum thread that prompted this blog.
So
CDI allows multiple requests to be part of a «conversation scope». A
conversation has a «start» and an «end», both of which can be managed by
the application. When the application involves JSF, any conversation
(id) gets auto-propagated to the JSF request(s). Apart from an explicit
start/end demarcation of conversations, a conversation can also timeout.
A request which refers to a conversation which has ended or timed out
will run into an exception.
So we know have a bit of background
on CDI conversation scope. So let’s consider a case where the
application wants to present a good looking page when the «conversation
no longer present» exception is thrown (maybe because of a timeout). We
have seen how to write a web.xml for error-page configurations — it
would be as simple as:
<web-app> ... <!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException --> <error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>/my-foo-bar-exception-page.html</location> </error-page> ... </web-app>
Simple enough. The
org.jboss.weld.context.NonexistentConversationException is the exception
class type which gets thrown when the conversation has timed out (note
that we are assuming that the web application is relying on Weld as the
CDI spec implementation library). The above configuration works fine.
The my-foo-bar-exception-page.html gets displayed when the
org.jboss.weld.context.NonexistentConversationException is thrown.
BUT,
let’s now consider that we want to involve JSF in the error page just
like the other parts of our application. So let’s point the error-page
to a URL pattern which maps to the JSF servlet:
<web-app> ... <!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException --> <error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>/my-foo-bar-exception-page.xhtml</location> </error-page> ... </web-app>
Note that we changed the error page mapping to
my-foo-bar-exception-page.xhtml (notice the xhtml extension) from
my-foo-bar-exception-page.html. We’ll again assume that the .xhtml
resources are mapped to the JSF servlet so those requests are considered
as JSF requests.
With this change to the web.xml, you’ll notice
that the my-foo-bar-exception-page.xhtml will no longer be displayed in
you see a big stacktrace with repeatedly shows
org.jboss.weld.context.NonexistentConversationException exception in the
stacktrace thus giving an impression that the error-page configuration
went wrong.
So what did we do wrong? Well, remember that earlier I
mentioned that for JSF requests the conversation id gets propagated
automatically. That’s exactly what’s happening here. The server notices
the org.jboss.weld.context.NonexistentConversationException exception
and then tries to render the error-page which is backed by JSF and since
the conversation id gets propagated the server tries to find that
non-existent conversation and ends up failing with the same
org.jboss.weld.context.NonexistentConversationException and ultimately
fails to render the error page. It’s like going in circles to render
that error page.
So how does one get past it? Keeping aside all
the technical details, the obvious thing would be to not propagate the
non-existent conversation id while rendering the (JSF backed) error
page. So that’s what we are going to do. CDI 1.1 (and Weld 1.1.2 and
later) allows you to explicitly specify that a conversation shouldn’t be
propagated for a particular request. You can do this by passing along a
parameter named «nocid» within that request. With that knowledge, let’s
now modify our web.xml to do the necessary changes so that our error
page gets rendered properly:
<web-app> ... <!-- A custom error page for exception type org.jboss.weld.context.NonexistentConversationException. Notice the "nocid" parameter being passed to make sure that the non-existent conversation id isn't passed to the error page --> <error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>/my-foo-bar-exception-page.xhtml?nocid=true</location> </error-page> ... </web-app>
Notice that we are passing the «nocid» parameter as part of the query
string of the error page location. The value for «nocid» parameter
really doesn’t matter but for the sake of keeping that value logical, we
have used the value «true» here. Once this change is done, you’ll start
noticing that the error page (backed by JSF) now renders correctly!
It
took a while for us to get to this solution in that forum thread
because it looked so simple that it should have «just worked», but it
didnt’ Here’s the forum thread at coderanch that I’ve been talking about. Credit goes to Greg Charles for figuring out how to pass that nocid parameter.