Java Server Faces (Basics mit JSP) (JavaEE 8)


Inhalt:

Projekt erstellen
ManagedBean "GeometricModelHandler"
Hilfsklasse "History"
JSF-Editor
JSP
"beans.xml"
JSF 2.3 aktivieren
Startseite
Troubleshooting
JSF-Facet zu bestehendem Projekt zufügen


Dieses Beispiel baut auf der gleichen Logik auf wie die JSP-Beispiel, es existiert also nur eine Web-Anwendung mit minimaler Programmlogik. Bereits durchgeführte Berechnungen werden in der Session gespeichert.
Das Beispiel baut auf JavaEE8 und WildFly 24.0 auf.

Dieses Beispiel verwendet JSF in einer JSP-Seite. Dies ist deprecated bzw. wurde in Version 4.0 des Standards entfernt. Aktuell sollten Facelets verwendet werden.

Auch die Definition des Handler als "Managed Bean" wurde mittlerweile durch CDI-Annotations ersetzt und in Version 4.0 entfernt.

Eine aktuellere Variante des Beispiels findet sich hier.


Hier gibt es das Projekt als WAR-Export-Datei: JSF.war.
Nach dem Import muss man die JSF-Facet dem Projekt zufügen, siehe JSF-Facet zu bestehendem Projekt zufügen

Für mehr Informationen zu JSF sei auf das JavaEE6-Tutorial, Part II, ab Kapitel 4 verwiesen: http://download.oracle.com/javaee/6/tutorial/doc/index.html

Projekt erstellen

Beim Erstellen des "Dynamic Web Project" wird die "Dynamic web module version" auf "4.0" gestellt.
Neues Projekt (1)
Außerdem ist es wichtig die Facet "JavaServer Faces 2.3" zuzufügen. Diese ist leider nicht in der "Configuration"-Combobox enthalten, sondern man muss zuerst auf "Modify..." klicken.

In dem erscheinenden Dialog steht bei "Configuration" vermutlich "Custom". In der darunter liegenden Tabelle der zu installierenden Facets wird jetzt ein Haken bei "JavaServer Faces" gesetzt und die Version 2.3 gewählt. Anschließend wird diese Configuration unter einem sinnvollen Namen (in meinem Fall: "WildFly 24 + JSF 2.3") gespeichert.
JavaServer Faces Configuration
Jetzt auf "OK" und weiter im Assistenten.

Im nächsten Schritt ("Java") bleibt alles bei den Defaults.

Im nächsten Schritt "Web Module" lassen wir uns einen Deploymentdescriptor "web.xml" genrieren:
Neues Projekt (2)

Im Schritt "JSF Capabilities" wählen wir die JSF-Implementierung aus, die wir verwenden wollen.
Eigentlich sollte hier die Auswahl "Library Provided by Target Runtime" ausreichen, da der Server-Adapter von JBoss Tools die JAR-Dateien der JSF-Klassen zufügt. Allerdings gibt es hier scheinbar einen Bug, durch den die JSF-Taglibraries nicht aufgelöst werden können (https://issues.redhat.com/browse/JBIDE-28265).

Deshalb gehen wir hier anders vor.

Es wird "User Library" gewählt. Beim allerersten Aufruf wird hier nur eine Fehlermeldung "Required class javax.faces.FactoryFinder does not exist in selected libraries." stehen.
Deshalb klicken wir auf den Knopf "Manage libraries" rechts neben der leeren Liste.
Neues Projekt (2)
Es öffnet sich der "User Libraries"-Karteireiter aus den Preferences. Hier klicken wir auf "New..." und geben der JSF-Library erstmal einen Namen:
JSF-Library (1)
Danach wählen die neue Library aus und klicken auf "Add External JARs...". Hier wählen wir die folgenden beiden Dateien aus: Das Ergebnis sieht so aus:
JSF-Library (2)

Die so angelegte JSF-Library wählen wir jetzt aus. Wichtig ist, dass die Checkbox "Include Libraries with this application" nicht gesetzt wird, denn ansonsten würden die JAR-Dateien als Teil unserer Anwendung deployed, und das würde zu JBoss-Fehlermeldungen führen.


Unter "URL Mapping Patterns" löschen wir die Vorgabe "/faces/*" und ersetzen sie durch "*.faces" (zumindest für mein Beispiel, ihr könnt das natürlich im Projekt anders halten).
Neues Projekt (3)
Im Verzeichnis "WEB-INF" befindet sich jetzt eine neue Datei "faces-config.xml", für die es einen schicken Editor gibt.
In "web.xml" wurde das Faces-Servlet eingebunden:
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>

Anmerkung: mittlerweile (Eclipse 3.6) werden hier zwei "context-param" ("javax.faces.STATE_SAVING_METHOD" und "javax.servlet.jsp.jstl.fmt.localizationContext") und ein "listener"-Element zugefügt. Diese Werte sind zumindest in meinem Beispiel nicht nötig, könnten also auch weggelassen werden.

Da wir die JSTL-Library verwenden wollen (Version 1.2), wird die Datei "jstl-1.2.jar" von https://repo.maven.apache.org/maven2/jstl/jstl/1.2/ heruntergeladen und nach "WEB-INF\lib" kopiert. Alternativ könnte man auch die in WildFly enthaltene Datei in "%WILDFLY_HOME%\modules\system\layers\base\javax\servlet\jstl\api\main\taglibs-standard-impl-1.2.6-RC1.jar" verwenden.
verwenden. Aber auch diese muss man wohl in "WEB-INF\lib" kopieren - tut man das nicht, kann Eclipse zumindest die Tags in der JSP-Seite nicht auflösen.

Anmerkung: Die im Beispiel "JSP3" beschriebenen zusätzlichen Schritte (c.tld aus der JAR-Datei in ein Unterverzeichnis von WEB-INF legen und ein Element <jsp-config> mit der Verbindung von URI zu TLD-Datei in "web.xml" einfügen) sind normalerweise nicht nötig, WTP und JBoss sind intelligent genug die zur URI passende TLD-Datei selbst zu finden. Nur wenn diese nicht eindeutig wäre oder (aus welchen Gründen auch immer nicht identisch ist mit der in der TLD deklarierten) müssen diese zwei Schritte erfolgen.


ManagedBean "GeometricModelHandler"

Der im Folgenden beschriebene Editor für "faces-config.xml" ist nicht durch Doppelklick auf die Datei erreichbar, da sich dort ein "JBoss Tools XML editor" vordrängelt. Deshalb Rechtsklick auf die Datei und "Open With" => "Faces Config Editor" aufrufen:
Faces Config Editor


Achtung: dieser Editor läßt sich nur aufrufen, wenn wir im Projekt die Face "Java Server Faces" konfiguriert haben, siehe oben bzw. die Import-Anleitung.


Zuallererst fügen wir die ManagedBean "GeometricModelHandler" zu, die die Anwendungslogik enthält.
Dazu öffnen wir "faces-config.xml" und gehen auf der Karteikarte "Managed Beans" auf "Add" (falls hier nur ein XML-Editor aufgeht: Rechtsklick auf "faces-config.xml" und im Kontextmenü den Punkt "Open With" => "Faces Config Editor" wählen).
Wir wählen die Option "Create a new Java class".
Managed Bean zufügen (1)
Package und Klassenname werden eingegeben.
Managed Bean zufügen (2)
Als "scope" wählen wir "session" da in dieser Bean unsere letzten Berechnungen gespeichert werden sollen.
Managed Bean zufügen (3)
Im letzten Schritt werden die Eingaben nochmals zusammengefaßt angezeigt, hier gibt es nichts weiter für uns zu tun.
Das Ergebnis sieht so aus:
Managed Bean zufügen (4)
In "faces-config.xml" wurde folgendes zugefügt:
	<managed-bean>
		<description>
		This Managed Bean performs the calculation of surface and volume of the cube.
		It stores a list of all user inputs for the current session.</description>
		<managed-bean-name>geometricModelHandler</managed-bean-name>
		<managed-bean-class>de.fhw.komponentenarchitekturen.knauf.jsf.GeometricModelHandler</managed-bean-class>
		<managed-bean-scope>session</managed-bean-scope>
	</managed-bean>

Alternativ könnten auch Annotations auf der Bean-Klasse definiert werden:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="geometricModelHandler")
@SessionScoped()
public class GeometricModelHandler 
{


Jetzt werden der Managed Bean Properties zugefügt:
  private double dblA = 0;
  private double dblB = 0;
  private double dblC = 0;
  
  public double getA()
  {
    return dblA;
  }
  public void setA(double dblA)
  {
    this.dblA = dblA;
  }

  public double getB()
  {
    return dblB;
  }
  public void setB(double dblB)
  {
    this.dblB = dblB;
  }

  public double getC()
  {
    return dblC;
  }
  public void setC(double dblC)
  {
    this.dblC = dblC;
  }  

Es gibt get-Properties für die aktuell berechneten Werte sowie die Historie:
  private double dblOberflaeche = 0;
  private double dblVolumen = 0;
  
  private History history = new History();

  public History getHistory()
  {
    return this.history;
  }
  
  public double getVolume()
  {
    return this.dblVolume;
  }
  
  public double getSurface()
  {
    return this.dblSurface;
  } 

Schließlich wird die Methode calculate zugefügt, die beim Klick auf "Submit" aufgerufen wird und die Berechnung durchführt sowie die aktuelle Berechnung der Historie zufügt.
  public String calculate()
  {
    //Calculate the values and store in member variables:
    this.dblVolume = this.dblA * this.dblB * this.dblC;
    this.dblSurface = 2 * (this.dblA * this.dblB) + 2 * (this.dblA * this.dblC) + 2 * (this.dblB * this.dblC);
    
    //Add to history
    SideLengths sideLengthCurrent = new SideLengths();
    sideLengthCurrent.setA(this.dblA);
    sideLengthCurrent.setB(this.dblB);
    sideLengthCurrent.setC(this.dblC);
    this.history.addSideLength(sideLengthCurrent );
    
    //Return value does not matter, because this simple sample has no navigation rules.
    return null;
  } 
Die Rückgabe einer solchen Submit-Methode ist normalerweise eine Navigationsregel die die Zielseite zurückgibt. Kommt dabei null zurück so gelangt man automatisch wieder zu der Seite die das Formular abgeschickt hat.


Hilfsklasse "History"

In der Klasse "History", in der die bereits durchgeführten Berechnungen abgelegt werden, ergeben sich zwei kleine Änderungen:
  public List<SideLengths> getSideLengths()
  {
    return this.vectorSideLengths;
  }
  
  public int getSize()
  {
    return this.vectorBerechnungen.size();
  } 
Die Methode getSize ist nötig um mittels <c:if>-Tag auf das Vorhandensein von Elementen zu prüfen (nur dann wird die Tabelle der bereits durchgeführten Berechnungen angezeigt).

getSideLengths liefert die SideLengths-Objekte als generic Liste zurück. Diese wird später über das JSF-Tag <h:dataTable> durchlaufen.


JSF-Editor

Da ich in meinen Beispielen den JBoss Tools-Plugin verwendet habe, "drängelt" sich ein JSP-Editor aus den JBoss Tools vor den Default-Editor der Web Tools Platform. Während dieser Editor JSF unterstützt, bietet der JBoss Tools-Editor diese Möglichkeit nicht. Man merkt das fehlende Feature vor allem daran, dass Code Completion in JSF-Tags nicht klappt.

Also Rechtsklick auf die JSF-Seite und unter "Open With" den Punkt "JSP Editor" wählen (nicht "JBoss Tools JSP Editor"):
JSP Editor


JSP

Wir fügen eine JSP-Seite "geometricmodel.jsp" zu. Warum ich sie nicht "index.jsp" nenne wird im nächsten Abschnitt erklärt !
Die Seite verwendet die JSTL-Core-Library.
Sie sieht so aus:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Simple JSF sample</title>
</head>
<body>
<f:view>
  <h:form id="formGeometricModelInput">
    <h:panelGrid columns="3">
      
      <c:if test="${sessionScope.geometricModelHandler.volume > 0.0}">
        <h:outputText value="Volume:"/>
        <h:outputText id="volume" value="#{geometricModelHandler.volume}"></h:outputText>
        <h:outputText value=""></h:outputText>
      
        <h:outputText value="Surface:"/>
        <h:outputText id="surface" value="#{geometricModelHandler.surface}"></h:outputText>
        <h:outputText value=""></h:outputText>
      </c:if>
      
      <h:outputText value="Side a:"></h:outputText>
      <h:inputText label="Side A" id="a" value="#{geometricModelHandler.a}"></h:inputText>
      <h:message for="a"></h:message>
      
      <h:outputText value="Side b:"></h:outputText>
      <h:inputText label="Side B" id="b" value="#{geometricModelHandler.b}"></h:inputText>
      <h:message for="b"></h:message>
      
      <h:outputText value="Side c:"></h:outputText>
      <h:inputText label="Side C" id="c" value="#{geometricModelHandler.c}"></h:inputText>
      <h:message for="c"></h:message>
      
      <h:commandButton id="calculate" value="Calculate" action="#{geometricModelHandler.calculate}"></h:commandButton>
      <h:outputText value=""></h:outputText>
      <h:outputText value=""></h:outputText>
      
      <%--Print history: --%>
      <c:if test="${geometricModelHandler.history.size > 0}">
        <%--A DataTable with three columns will contain all calculations of the current session.
         The current iteration element will be put in a variable named "sideLengthCurrent" --%>
        <h:dataTable value="#{geometricModelHandler.history.sideLengths}" var="sideLengthCurrent">
          <h:column>
            <f:facet name="header">
              <h:outputText value="A"/>
            </f:facet>
            <h:outputText value="#{sideLengthCurrent.a}"></h:outputText>
          </h:column>
          <h:column>
            <f:facet name="header">
              <h:outputText value="B"/>
            </f:facet>
            <h:outputText value="#{sideLengthCurrent.b}"></h:outputText>
          </h:column>
          <h:column>
            <f:facet name="header">
              <h:outputText value="C"/>
            </f:facet>
            <h:outputText value="#{sideLengthCurrent.c}"></h:outputText>
          </h:column>
        </h:dataTable>
      </c:if>
    </h:panelGrid>
  </h:form>
</f:view>
</body>
</html>

Die Elemente im Einzelnen:


"beans.xml"

Beim Deploy wird die Anwendung folgende Fehlermeldung anzeigen:
21:28:51,922 ERROR [stderr] (ServerService Thread Pool -- 57) javax.faces.FacesException: Unable to find CDI BeanManager
21:28:51,922 ERROR [stderr] (ServerService Thread Pool -- 57) 	at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.application.applicationimpl.Version.isJsf23(Version.java:62)
21:28:51,922 ERROR [stderr] (ServerService Thread Pool -- 57) 	at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.application.applicationimpl.ExpressionLanguage.addELResolver(ExpressionLanguage.java:140)
...
Lösung:
Es muss eine Datei "WEB-INF\beans.xml" mit folgendem Inhalt angelegt werden:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
    version="2.0" bean-discovery-mode="annotated">
</beans>


JSF 2.3 aktivieren

Siehe https://github.com/eclipse-ee4j/mojarra/blob/2.3/README.md#user-content-activating-cdi-in-jakarta-faces-23: Auch wenn in "faces-config.xml" die Version 2.3 eingetragen ist, läuft JSF trotzdem teilweise im 2.2-Modus. Um dies zu umgehen, muss irgendwo bei einer Klasse die entsprechende JSF-Version per Annotation deklariert werden.
Der Übersichtlichkeit halber habe ich das auf einer eigenen Klasse "Jsf23Activator" getan:

package de.fhw.komponentenarchitekturen.knauf.jsf;

import javax.enterprise.context.ApplicationScoped;
import javax.faces.annotation.FacesConfig;

@ApplicationScoped
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class Jsf23Activator {
}
Meine Beispiel nutzen zwar keine Features, für die dies nötig wäre, aber ich erkläre diese Lösung trotzdem.


Startseite

Eine Besonderheit gibt es bei der Initialisierung der Session: bevor die erste JSP aufgerufen wird, die JSF-Tags enthält, MUSS das FacesServlet initialisiert werden.
Was dies bedeutet erkennt man, wenn oben angelegte JSP direkt über die URL
http://localhost:8080/JSF/geometricmodel.jsp aufgerufen wird:

Fehlermeldung von WildFly 8
21:42:08,009 ERROR [io.undertow.request] (default task-14) UT005023: Exception handling request to /JSF/geometricmodel.jsp: org.apache.jasper.JasperException: java.lang.NullPointerException
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:410) [jastow-1.0.0.Final.jar:1.0.0.Final]
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:326) [jastow-1.0.0.Final.jar:1.0.0.Final]
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:259) [jastow-1.0.0.Final.jar:1.0.0.Final]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [rt.jar:1.7.0_51]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [rt.jar:1.7.0_51]
	at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_51]
Caused by: java.lang.NullPointerException
	at javax.faces.webapp.UIComponentClassicTagBase.setJspId(UIComponentClassicTagBase.java:1856) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
	at org.apache.jsp.geometricmodel_jsp._jspx_meth_f_005fview_005f0(geometricmodel_jsp.java:128)
	at org.apache.jsp.geometricmodel_jsp._jspService(geometricmodel_jsp.java:103)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:69) [jastow-1.0.0.Final.jar:1.0.0.Final]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:366) [jastow-1.0.0.Final.jar:1.0.0.Final]
	... 27 more

Fehlermeldung von JBoss 6
Die Fehlermeldung von JBoss 6 wird hier gezeigt, da sie aussagekräftiger ist als ihr WildFly8-Pendant (hier nur der RootCause der Exception da dieser aussagekräftiger ist als die eigentliche Exception):
java.lang.RuntimeException: Cannot find FacesContext
	javax.faces.webapp.UIComponentClassicTagBase.getFacesContext(UIComponentClassicTagBase.java:1763)
	javax.faces.webapp.UIComponentClassicTagBase.isIncluded(UIComponentClassicTagBase.java:1647)
	javax.faces.webapp.UIComponentClassicTagBase.setJspId(UIComponentClassicTagBase.java:1575)
	org.apache.jsp.geometricmodel_jsp._jspx_meth_f_005fview_005f0(geometricmodel_jsp.java:109)
	org.apache.jsp.geometricmodel_jsp._jspService(geometricmodel_jsp.java:83)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:384)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96) 
Die einfachste Lösung wäre, nicht die JSP-Seite aufzurufen, sondern einen Alias der über das Faces-Servlet führt. Das Faces-Servlet behandelt (siehe obiger Auszug aus "web.xml") alle URLs mit der Endung ".faces", und leitet diese auf die gleichnamige JSP-Seite weiter. Wir könnten also mittels http://localhost:8080/JSF/geometricmodel.faces auf die Seite zugreifen.
Da dies nicht wirklich komfortabel ist habe ich eine Startseite "index.jsp" vorgeschaltet die einen Link zur Faces-Seite bietet. Wichtig bei dieser Seite ist, dass sie nicht an einer Session teilnimmt:
	<?xml version="1.0" encoding="ISO-8859-1" ?>
	<%@ page session="false" language="java" contentType="text/html; charset=ISO-8859-1"%>
	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
	<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
	<title>Test für JSF</title>
	</head>
	<body>
	
	<h1>JSF-Basics</h1>
	
	<a href="geometricmodel.faces">Zur Startseite</a>
	
	</body>
	</html> 
Eine Alternative wäre ein direktes Redirect auf die Faces-Seite (kompletter Code der Seite):
	<%@ page session="false" language="java" contentType="text/html; charset=ISO-8859-1"%>
	<% response.sendRedirect("geometricmodel.faces"); %>


Die Anwendung findet sich unter dieser URL: http://localhost:8080/JSF/index.jsp.


Troubleshooting

Nach dem Redeploy einer JSF-Anwendung kann es im Browser zu folgendem Fehler kommen:
21:22:26,194 ERROR [io.undertow.request] (default task-5) UT005023: Exception handling request to /JSF/geometricmodel.faces: javax.servlet.ServletException: 
  viewId:/geometricmodel.faces - Ansicht /geometricmodel.faces konnte nicht wiederhergestellt werden.
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [rt.jar:1.7.0_51]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [rt.jar:1.7.0_51]
	at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_51]
Caused by: javax.faces.application.ViewExpiredException: viewId:/geometricmodel.faces - Ansicht /geometricmodel.faces konnte nicht wiederhergestellt werden.
	at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:210) [jsf-impl-2.2.5-jbossorg-3.jar:]
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.2.5-jbossorg-3.jar:]
	at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:121) [jsf-impl-2.2.5-jbossorg-3.jar:]
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) [jsf-impl-2.2.5-jbossorg-3.jar:]
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
	... 24 more
Dies tritt immer dann auf, wenn man vorher eine Seite offen hatte, die über JSF erzeugt wurde, und diese Seite nach dem Reploy direkt wieder an den Server abschickt (also z.B. im obigen Beispiel erneut auf den Submit-Button klickt).
Lösung: nach jedem Redeploy über die Indexseite in die Anwendung einsteigen.


JSF-Facet zu bestehendem Projekt zufügen

Falls man bereits ein Webprojekt ohne JSF-Unterstützung hat (z.B. nach dem Import der WAR-Datei dieses Beispiels), lässt sich dies leicht nachtragen.
Man geht in die Properties des Projekts in den Punkt "Project Facets". Dort aktiviert man die Facet "JavaServer Faces" und setzt die Version auf "2.3". Außerdem passt man die Facet "Dynamic Web Project" an.
Facet zufügen (1)
Man sollte außerdem generell links unten auf "Further Configuration available" klicken, um die Checkbox "Include Libraries with this application" zurückzusetzen. Falls es bereits eine "faces-config.xml" im Projekt gibt, sollte man außerdem die Checkbox "Configure JSF servlet in deployent descriptor" zurücksetzen.
Facet zufügen (2)



Stand 04.01.2023
Historie:
08.08.2011: Erstellt aus JavaEE5-Beispiel, angepaßt an Eclipse 3.6 / JBoss 6.0 (vor allem Konfiguration der JSF-Library in Eclipse).
08.09.2011: code translated to english
12.03.2014: Angepasst an Eclipse 4.3, WildFly 8, JavaEE7. Hinweis zu "JSTL und JSF" und "Unified EL"
08.01.2022: Angepasst an WildFly 24, JavaEE8, JSF 2.3.
25.12.2022: JSP ist deprecated - Hinweis auf Facelets-Beispiel
04.01.2023: Managed Bean-Deklaration durch Annotations