This page (revision-55) was last changed on 11-Mar-2016 22:39 by Dieter Käppel

This page was created on 12-Nov-2010 09:09 by Dieter Käppel

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Page revision history

Version Date Modified Size Author Changes ... Change note
55 11-Mar-2016 22:39 23 KB Dieter Käppel to previous
54 11-Mar-2016 22:39 23 KB Dieter Käppel to previous | to last
53 09-Jan-2014 11:04 23 KB Dieter Käppel to previous | to last
52 27-Jul-2013 13:25 23 KB Dieter Käppel to previous | to last
51 24-Jul-2013 19:50 23 KB Dieter Käppel to previous | to last
50 23-Jul-2013 08:35 23 KB Dieter Käppel to previous | to last
49 08-Jul-2013 19:14 21 KB Dieter Käppel to previous | to last
48 11-Jun-2013 12:50 20 KB Dieter Käppel to previous | to last
47 26-Apr-2013 11:13 19 KB Dieter Käppel to previous | to last
46 26-Apr-2013 11:11 18 KB Dieter Käppel to previous | to last
45 26-Apr-2013 07:42 16 KB Dieter Käppel to previous | to last
44 26-Feb-2013 13:12 16 KB Dieter Käppel to previous | to last
43 18-Dec-2012 12:30 16 KB Dieter Käppel to previous | to last
42 16-Dec-2012 21:18 16 KB Dieter Käppel to previous | to last
41 16-Dec-2012 14:25 15 KB Dieter Käppel to previous | to last

Page References

Incoming links Outgoing links

Version management

Difference between version and

At line 70 changed 85 lines
!!Custom UIComponent
Eine Composite Component wird normaler Weise durch eine Bean vom Typ UINamingContainer repräsentiert. Diese kann im Bedarfsfall abgeleitet werden. Dadurch kann die Einfachheit des Renderings der Composite Component mit der Mächtigkeit von Java-Code kombiniert werden:
{{{
@FacesComponent("intersult.Test")
public class TabPanel extends UINamingContainer {
public String getTest() {
return "Hello World!";
}
}
}}}
und im XHTML instantiiert:
{{{
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:e="http://java.sun.com/jsf/ext"
xmlns:ext="http://java.sun.com/jsf/composite/ext"
>
<cc:interface componentType="intersult.Test">
...
</cc:interface>
<cc:implementation>
<h:outputText value="#{cc.test}"/>
...
</cc:implementation>
</html>
}}}
__Erklärung:__ Die Custom Composite Component wird über die Variable cc ebenso wie die gewöhnliche UINamingContainer referenziert. Dazu kommen Methoden und Properties, die in der abgeleiteten Klasse implementiert werden.
!!Backing Beans
Manche Komponenten brauchen den Zugriff auf Variablen, die über Requests hinweg erhalten bleiben. Die mit <cc:attribute> definierten Attribute werden im View-Scope gespeichert und können daher dafür verwendet werden. Gleichzeitig können diese beim Verwenden der Komponente vom Benutzer durch eine EL-Expression an einen beliebigen Scope gebunden werden:
{{{
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:e="http://java.sun.com/jsf/ext"
xmlns:ext="http://java.sun.com/jsf/composite/ext"
>
<cc:interface>
<cc:attribute name="value" default="0"/>
</cc:interface>
<cc:implementation>
<div id="#{cc.clientId}">
<h:form id="header-form">
<table id="#{cc.clientId}:header" style="width: 100%;" cellpadding="0" cellspacing="0">
<tr>
<c:forEach id="repeat" items="#{cc.children}" var="tab" varStatus="tabStatus">
<e:div element="td"
styleClass="#{cc.attrs.value == tabStatus.index ? 'tab-active' : 'tab-inactive'}" style="padding-left: 5px;">
<e:ajax event="click" rendered="#{cc.attrs.value != tabStatus.index}"
render=":#{cc.clientId}">
<e:set value="#{tabStatus.index}" target="#{cc.attrs.value}"/>
</e:ajax>
<h:outputText value="#{tab.attributes.header}"/>
</e:div>
</c:forEach>
<td style="padding-right: 5px; width: 100%;"/>
</tr>
</table>
</h:form>
<e:div id="content">
<e:insert component="#{cc.children[cc.attrs.value]}"/>
</e:div>
</div>
</cc:implementation>
</html>
}}}
__Erklärung:__ Der Set-Tag weißt den aktuellen Index (tabStatus.index) dem Attribut "value" zu (cc.attrs.value). Dieses Attribut wird verwendet, um den entsprechenden Tab-Content zu laden. Die Tabs selbst sind wiederum einfache Composite Tags mit einem Attribut "header".
!!!AJAX
!!AJAX Status
!!!AJAX Status
At line 191 removed 74 lines
!!AJAX-Push
Momentan relativ einfach zu konfigurieren ist der Primefaces-Push, der seit der Version 3.4 auf Atmosphere-Framework basiert. Atmosphere-Framework ist momentan das führende Framework für alle möglichen Push-Varianten, zwischen Server und Browser, falls man sich nicht vollzeit mit diesem Thema beschäftigen möchte.
pom.xml:
{{{
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>3.4-SNAPSHOT</version>
</dependency>
...
<repositories>
<repository>
<id>prime-repo</id>
<name>Prime Technology Maven Repository</name>
<url>http://repository.primefaces.org</url>
<layout>default</layout>
</repository>
</repositories>
}}}
web.xml, es ist eine Web-App 3.0 erforderlich:
{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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-app_3_0.xsd"
version="3.0">
...
<servlet>
<servlet-name>Push Servlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Push Servlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
...
</web-app>
}}}
Java:
{{{
public void someMethod() {
PushContextFactory.getDefault().getPushContext().push("/test", null);
}
}}}
Der Eintrag "/test" ist der sogenannte Channel über dem gepusht wird.
Im XHTML wird entweder ein AJAX-Tag verwendet:
{{{
<p:socket channel="/test" autoConnect="true">
<p:ajax event="message" update=":push-form:chat"/>
</p:socket>
}}}
Oder wenn der Update manuell gemacht werden soll, kann auch Javascript verwendet werden:
{{{
<p:socket channel="/test" autoConnect="true" onMessage="someMethod"/>
}}}
Die Methode wird dann mit einem Parameter "data" aufgerufen, welches dem JSON-Serialisiertem Objekt aus dem Server-Push-Aufruf context.push("/test", data); entspricht.
!!Probleme mit AJAX-Submits
Formulare können nicht mehr abgeschickt werden, wenn diese über ein Parent-Element mit AJAX neu gerenderet wurden. Abhilfe bringt die explizite Angabe der Formular-Id beim Rerender.
Alternativ kann [JSF Ext] mit ins Projekt eingebunden werden, die Komponenten-Bibliothek enthält Javascript-Code, der das Problem transparent gelöst.
Eine weitere Ursache sind sich veränderte Client-Ids zwischen Rendering und Form Submit. Eine Lösung ist, den Naming-Containern und den Submit-Elementen Ids zu geben. Dies erleichtert generell das Debugging von Formularen, da die Ids oft in Fehlermeldungen angezeigt werden, die betreffenden Elemente werden so leicht gefunden.
At line 380 removed 8 lines
Zunächst eine Übersicht, was momentan möglich ist:
* Importieren eines Maven-WAR-Projekts in Eclipse
* Importieren von Abhänigigen JSF-JARs in Eclipse
* Nutzen von Content-Assist für Code-Completion von Tag-Librarys in XHTML-Dateien
* Ändern von XHTML- und anderen Dateien ohne Server-Neustart, sowohl im WAR- als auch in abhängigen JAR-Projekten
* Direktes Referenzieren abhängiger Maven-Artifakte, die sich im Workspace befinden
At line 404 changed one line
JSF verwendet eine Logging-Konfiguration, die über die JVM-Logging-Properties eingestellt wird. Diese befinden sich in
JSF verwendet eine Logging-Konfiguration, die über die JVM-Logging-Properties eingestellt wird. Diese befinden sich in %JAVA_HOME%/jre/lib/logging.properties konfiguriert wird. Dort können Einträge hinzugefügt werden, wie zum Beispiel
At line 406 removed 17 lines
%JAVA_HOME%/jre/lib/logging.properties
konfiguriert wird. Dort wird zunächst das Logging des java.util.logging.ConsoleHandler auf ALL gestellt, damit Logging-Events höher als INFO auch ausgegeben werden. Dann können Einträge hinzugefügt werden, wie zum Beispiel für javax.enterprise.resource.webcontainer.jsf.context, um Exceptions bei EL-Expressions auszugeben:
Den vorhandenen Eintrag auf ALL umstellen:
java.util.logging.ConsoleHandler.level = ALL
Und diesen neuen Eintrag am Ende der Datei hinzufügen:
javax.enterprise.resource.webcontainer.jsf.context.level=FINE
Eine Übersicht der möglichen Logging-Events befindet sich in der Enum com.sun.faces.util.FacesLogger
!!Project Stage
Der Project-Stage kann über den FacesContext abgefragt werden:
At line 424 changed one line
FacesContext.currentInstance().isProjectState(ProjectStage.Development)
javax.enterprise.resource.webcontainer.jsf.context.level=FINE
At line 427 changed one line
Oder im Frontend:
Eine Übersicht befindet sich in der Enum com.sun.faces.util.FacesLogger
At line 429 changed 3 lines
{{{
#{facesContext.application.projectState == 'Development'}
}}}
Allerdings sind dann noch die log4j.properties entsprechend anzupassen.
At line 433 changed 11 lines
!!!Configuration
Bei [JSF2] ist nur noch sehr wenig Konfiguration notwendig. Einige Dinge sind dennoch nützlich zu wissen, vor allem wenn etwas nicht so klappt wie es soll. Dies tritt vor allem in der Entwicklungsumgebung und beim Zugriff auf spezielle Features vor.
!!Hintergrund der Initialisierung
Leider ist die Initialisierung von [JSF2] ein komplexer Vorgang mit mehreren Einsprüngen auf dem Servlet Container. Zunächst ist es hilfreich diese zu kennen, um mit der Analyse des Source-Codes beginnen zu können:
* com.sun.faces.config.ConfigureListener.contextInitialized
* com.sun.faces.config.ConfigManager.initialize
* com.sun.faces.config.processor.FactoryConfigProcessor.process
!!Annotation Processing
!!!Annotation Processing
At line 471 changed 2 lines
!!!FacesContext manuell erzeugen
Innerhalb eines Servlet-Auftrufs kann der Kontext einfach erzeugt werden:
!!!JSF AJAX-Push
Momentan relativ einfach zu konfigurieren ist der Primefaces-Push, der seit der Version 3.4 auf Atmosphere-Framework basiert. Atmosphere-Framework ist momentan das führende Framework für alle möglichen Push-Varianten, zwischen Server und Browser, falls man sich nicht vollzeit mit diesem Thema beschäftigen möchte.
At line 279 added one line
pom.xml:
At line 475 changed 4 lines
FacesContextFactory factory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
factory.getFacesContext(servletContext, request, response, lifecycle);
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>3.4-SNAPSHOT</version>
</dependency>
...
<repositories>
<repository>
<id>prime-repo</id>
<name>Prime Technology Maven Repository</name>
<url>http://repository.primefaces.org</url>
<layout>default</layout>
</repository>
</repositories>
At line 481 changed one line
Außerhalb von Servlets braucht man den ServletContext, HttpServletRequest und HttpServletResponse, der nicht ganz einfach zu implementieren ist.
web.xml, es ist eine Web-App 3.0 erforderlich:
{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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-app_3_0.xsd"
version="3.0">
...
<servlet>
<servlet-name>Push Servlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Push Servlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
...
</web-app>
}}}
At line 483 changed 5 lines
!!!Render Kits
Die Seiten können auf unterschiedliche Arten gerendered werden, da für die Standard-Komponenten eigenständige Renderer vorhanden sind. Diese Renderer werden zu Render Kits zusammengefasst, die durch eine Render Kit Id identifiziert werden. Das standard Render Kit hat die Id "HTML_BASIC", diese Konstante ist unter RenderKitFactory.HTML_BASIC_RENDER_KIT abrufbar.
Das aktuelle Render Kit kann durch den Request-Parameter "javax.faces.RenderKitId" angesprochen werden, dieser befindet sich als Konstante unter ResponseStateManager.RENDER_KIT_ID_PARAM. Also zum Beispiel die URL:
Java:
At line 489 changed one line
http://localhost/test/faces/index.xhtml?javax.faces.RenderKitId=test.RenderKit
public void someMethod() {
PushContextFactory.getDefault().getPushContext().push("/test", null);
}
At line 492 changed one line
Dieser Parameter kann auch durch ein Hidden-Field übergeben werden, sodass zum Beispiel Tabellen-, PDF- und andere Downloads generisch für Web-Seiten entwickelt werden können.
Der Eintrag "/test" ist der sogenannte Channel über dem gepusht wird.
At line 494 changed 9 lines
!!!Doctype
!!Doctype in JSF 2.2
JSF 2.2 unterstützt HTML5 und meint daher, einen eventuell in der Page-Deklaration vorhandenen Doctype vereinfachen zu müssen auf <!DOCTYPE html>.
Üblich sind <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> oder <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Zu lösen ist das durch einen Eintrag in der faces-config.xml:
Im XHTML wird entweder ein AJAX-Tag verwendet:
At line 504 changed 15 lines
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.2"
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/web-facesconfig_2_2.xsd"
>
...
<faces-config-extension>
<facelets-processing>
<file-extension>.xhtml</file-extension>
<process-as>xhtml</process-as>
</facelets-processing>
</faces-config-extension>
...
</faces-config>
<p:socket channel="/test" autoConnect="true">
<p:ajax event="message" update=":push-form:chat"/>
</p:socket>
At line 521 changed 2 lines
!!!Download
Bei JSF ist im kein Download-Servlet erforderlich, es kann einfach über eine Action-Methode abgewickelt werden:
Oder wenn der Update manuell gemacht werden soll, kann auch Javascript verwendet werden:
At line 525 changed 2 lines
<h:commandLink value="#{fileUpload.filename}" action="#{fileUpload.download}"
rendered="#{fileUpload.file != null}"/>
<p:socket channel="/test" autoConnect="true" onMessage="someMethod"/>
At line 529 changed one line
Die zugehörige Action-Methode:
Die Methode wird dann mit einem Parameter "data" aufgerufen, welches dem JSON-Serialisiertem Objekt aus dem Server-Push-Aufruf context.push("/test", data); entspricht.
At line 343 added 3 lines
!!!FacesContext manuell erzeugen
Innerhalb eines Servlet-Auftrufs kann der Kontext einfach erzeugt werden:
At line 532 changed 9 lines
public void download() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.setResponseContentType(mimeType);
externalContext.addResponseHeader("Content-Disposition", "attachment; filename=" + filename);
externalContext.setResponseContentLength(file.length);
OutputStream outputStream = externalContext.getResponseOutputStream();
outputStream.write(file);
FacesContext.getCurrentInstance().responseComplete();
}
FacesContextFactory factory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
factory.getFacesContext(servletContext, request, response, lifecycle);
At line 543 changed one line
__Erklärung:__ Der Download wird unmittelbar durch Anklicken des Links gestartet. Es wird kein kurzzeitiger Browser-Tab oder -Fenster geöffnet, die sich ohne sinnvollen Inhalt gleich wieder schließen, wie man das oft bei Web-Seiten sieht.
Außerhalb von Servlets braucht man den ServletContext, HttpServletRequest und HttpServletResponse, der nicht ganz einfach zu implementieren ist.
At line 545 changed one line
Als Variante kann der Browser bestimmte Mime-Types direkt anzeigen, wie z.B. GIF-, PNG-, JPG-Bilder, PDF-Dateien, je nach installierter Software noch mehr. Dies erreicht man durch hinzufügen von target="_blank" beim Link und setzen der Content-Disposition auf "inline":
!!!Formulare und AJAX
Formulare können nicht mehr abgeschickt werden, wenn diese über ein Parent-Element mit AJAX neu gerenderet wurden. Abhilfe bringt die explizite Angabe der Formular-Id beim Rerender.
At line 547 changed 3 lines
{{{
<h:commandLink value="#{fileUpload.filename}" target="_blank" action="#{fileUpload.download}"
rendered="#{fileUpload.file != null}"/>
Alternativ kann [JSF Ext] mit ins Projekt eingebunden werden, die Komponenten-Bibliothek enthält Javascript-Code, der das Problem transparent gelöst.
At line 551 changed one line
}}}
!!!Render Kits
Die Seiten können auf unterschiedliche Arten gerendered werden, da für die Standard-Komponenten eigenständige Renderer vorhanden sind. Diese Renderer werden zu Render Kits zusammengefasst, die durch eine Render Kit Id identifiziert werden. Das standard Render Kit hat die Id "HTML_BASIC", diese Konstante ist unter RenderKitFactory.HTML_BASIC_RENDER_KIT abrufbar.
At line 363 added 2 lines
Das aktuelle Render Kit kann durch den Request-Parameter "javax.faces.RenderKitId" angesprochen werden, dieser befindet sich als Konstante unter ResponseStateManager.RENDER_KIT_ID_PARAM. Also zum Beispiel die URL:
At line 554 changed 8 lines
public void download() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.setResponseContentType(mimeType);
externalContext.setResponseContentLength(file.length);
OutputStream outputStream = externalContext.getResponseOutputStream();
outputStream.write(file);
FacesContext.getCurrentInstance().responseComplete();
}
http://localhost/test/faces/index.xhtml?javax.faces.RenderKitId=test.RenderKit
At line 564 changed 5 lines
!!!Navigation
Für die Navigation gibt es zwei Parameter:
* __faces-redirect:__ Sinnvoller Wert ist nur "true". Dieser Parameter führt zum ausführen eines Redirect nach der Navigation.
* __includeViewParams:__ Ebenfalls nur "true" sinnvoll. Führt zur Übernahme der vorherigen View-Parameter.
Dieser Parameter kann auch durch ein Hidden-Field übergeben werden, sodass zum Beispiel Tabellen-, PDF- und andere Downloads generisch für Web-Seiten entwickelt werden können.