Wie im wirklichen Leben

Zu den Vorzügen guter Web-Frameworks zählt nicht zuletzt die Berücksichtigung von Real-Life-Aspekten wie Eingabekonvertierung und -validierung, Fehlerbehandlung oder Internationalisierung. Nicht selten spielen zudem die Möglichkeiten zur Integration mit anderen Frameworks eine ausschlaggebende Rolle bei der Entscheidung für oder gegen ein Web-Framework.

In Pocket speichern vorlesen Druckansicht 5 Kommentare lesen
Lesezeit: 5 Min.
Von
  • Detlef Bartetzko
  • Arvid Hülsebus
  • Lars Röwekamp

Wie der erste Teil des JSF-Tutorials gezeigt hat, lassen sich mit Java Server Faces gut strukturierte Webanwendungen erstellen. Konzepte wie der Request-Lebenszyklus, Managed Beans, deklaratives Hinterlegen einer Navigation oder das Verwenden von Method Bindings und Value Bindings innerhalb der JSF-Seiten erleichtern dem Entwickler von Web-Anwendungen alltägliche Aufgaben. Der Vorteil liegt klar auf der Hand: Er kann sich auf das Wesentliche - die Geschäftslogik - konzentrieren.

Dieser Teil des Tutorials untersucht, ob dies auch für umfangreichere Anwendungen und die damit verbundenen komplexeren Anforderungen gilt. Thematisch im Mittelpunkt stehen Internationalisierung, Validierung und Konvertierung. Außerdem soll ein Blick über den Tellerrand hinaus zeigen, inwieweit JSF sich mit Spring und Struts - zwei im Java-Umfeld etablierten Welten - integrieren lässt.

Mehr Infos

Wie im ersten Teil wird zur Demonstration das Beispiel der Adressverwaltung, das als Bestandteil eines Customer Relationship Management (CRM) fungiert, herangezogen und Schritt für Schritt erweitert.

Nachdem der erste Teil die Bedeutung von Value Bindings und Method Bindings an Beispielen bereits kurz erläutert hat, soll an dieser Stelle eine etwas detailliertere Betrachtung erfolgen, da dieser Mechanismus die wesentliche Verbindung zwischen Model, View und Controller (MVC) darstellt.

Die Syntax der Value Bindings ist identisch mit der der JSP Expression Language (EL) Version 2.0, mit zwei Ausnahmen: Value Bindings werden nicht mit „$“ eingeleitet, sondern mit „#“. Außerdem steht der Funktionsmechanismus der JSP Expression Lan-guage nicht zur Verfügung. Für JSF 1.2 ist eine Vereinheitlichung mit der EL der Java Server Pages 2.1 geplant.

Der Server verarbeitet einen Faces Request in sechs Phasen (Abb. 1).

In der Regel kann man die meisten Eigenschaften einer JSF-UI-Komponente mit einem Value Binding assoziieren, das den Wert der Eigenschaft dynamisch an das Modell knüpft. Die JSF-Laufzeitumgebung wertet das Binding in den Phasen „Update Model Values“ und „Render Response“ aus, um den Wert einer Komponente ins Modell zu schreiben beziehungsweise den einer Eigenschaft zu lesen. Den JSF-Lebenszyklus hat bereits der erste Teil des Tutorials im Detail vorgestellt. Zur Erinnerung zeigt Abbildung 1 noch einmal die einzelnen Phasen auf. Die auf JSF-Seiten verwendeten EL-Ausdrücke haben oft eine ähnliche Form wie im Beispiel des Tutorials:

controller.addressRows

Dies ist eine verkürzte Schreibweise für die Verwendung des generalisierten Operators „[]“:

controller[‘addressRows’]

Bei der Ausdrucksauswertung löst ein Variable Resolver den Namen controller zum Controller-Objekt auf, auf dessen Property addressRows das Programm über die Methode getAddressRows zugreift. Die Aufgabe des Variable Resolvers ist es, den ersten, am weitesten links stehenden Namen innerhalb eines Ausdrucks aufzulösen. Jede JSF-Implementierung liefert eine Default-Implementierung, erlaubt aber auch dessen Austausch, wie später das Beispiel der Spring-Integration zeigen wird. In den EL-Ausdrücken sind verschiedene Operatoren möglich, um Ergebnisse zu ermitteln. Der folgende Ausdruck etwa deaktiviert mit Hilfe des empty-Operators den Delete-Button, wenn keine Adressen vorhanden sind:

<h:commandButton action=”#{...}” value=”#{...}” 
disabled=”#{empty controller.addressRows}”/>

Logische Operatoren wie and, or und not, arithmetische Operationen wie + und - sowie relationale Operatoren wie <, > und == sind ebenfalls erlaubt. Eine Besonderheit stellt der generalisierte Operator [] zum Zugriff auf Objekteigenschaften, Maps, Arrays und Listen dar.

Anders als bei JSP kann ein EL-Ausdruck in JSF zum Schreiben eines Wertes dienen. Dies geschieht für Eingabekomponenten (EditableValueHolder) in der Phase „Update Model Values“. In diesem Fall muss der Ausdruck einen schreibbaren Wert referenzieren, etwa eine Objekteigenschaft, ein Listenelement oder einen Map-Eintrag.

Stellen die Value Bindings eine Verknüpfung mit Werten aus dem Modell dar, bilden die Method Bindings ana-log die Brücke zur Geschäftslogik. Ein Method Binding referenziert mit Hilfe eines EL-Ausdrucks eine öffentliche Methode. Eine typische Verwendung ist die Eigenschaft action einer UICommand-Komponente, etwa des Button:

<h:commandButton  action=”#{controller.deleteAddresses}”
value=”...” disabled=”...”/>

Welche Signatur die aufzurufende Methode besitzen muss, also welche Parameter das Programm ihr übergibt und welchen Typ sie zurückliefert, sowie über den Zeitpunkt ihres Aufrufs entscheidet die auswertende Instanz. Im obigen Fall darf die Methode deleteAddresses des Controllers keine Parameter erwarten und muss einen String zurückliefern - den Outcome der Geschäftslogik. Der Aufruf erfolgt über die Komponente UICommand entweder in der Phase „Invoke Application“ oder „Apply Request Values“. Der zweite Fall tritt ein, wenn die Eigenschaft immediate gesetzt ist, was eine Validierung gezielt verhindern soll (beispielsweise für einen Abbruchknopf):

<h:commandButton action=”#{controller.cancel}”
value=”...” immediate=”true”/>

Was es mit Internationalisierung, Validierung und Konvertierung auf sich hat und wie JSF sich mit den Frameworks Spring und Struts integrieren lässt, erfahren Sie in der aktuellen Print-Ausgabe.

Mehr Infos

iX-TRACT

  • Über sprachspezifische Resource Bundles lassen sich Konverter und Validatoren in JSF-Anwendungen je nach Bedarf an Sprache und Konventionen verschiedener Länder anpassen.
  • Für die Überprüfung von Benutzereingaben bieten die Java Server Faces Standardvalidatoren; alternativ kann der Programmierer eigene implementieren.
  • Das Java-Framework Spring erleichtert dem Entwickler die Implementierung von Standardtechniken im Backend und arbeitet gut in Verbindung mit dem JSF-Framework.

Teil 1: Grundlagen und generelle Funktionsweise der Java Server Faces

Teil 3: Trennung von Seitenbeschreibung und Layout sowie Einsatz fortschrittlicher Render-Techniken

Mehr Infos

Listing 1: Resource Bundle

# Editor
editor_first_name=Vorname
editor_date_pattern=dd.MM.yyyy
editor_store=Speichern

# List
list_footer={0,choice,0#Keine Adresse|1#1 \Adresse|1<{0,number,integer} Adressen}

# Footer
footer_flag_icon=icon/flag-de.png
Mehr Infos

Listing 2: Internationalisierung

... 
<application>
<locale-config>
<default-locale>en_US</default-locale>
<supported-locale>de</supported-locale>
<supported-locale>en_GB</supported-locale>
<supported-locale>en_US</supported-locale>
</locale-config>
<message-bundle>addressbook.web.resource</message-bundle>
</application>
...
Mehr Infos

Listing 3: JSF-Validierung

...
<h:inputText id="firstName" value="#{controller.currentAddress.firstName}"
required="true">
<f:validateLength minimum="2" maximum="20"/>
</h:inputText>
...
<h:inputText id="phone" value="#{controller.currentAddress.phone}"
validator="#{controller.validatePhoneNumber}"/>
...
<h:inputText id="icq" value="#{controller.currentAddress.icq}">
<f:validateLongRange minimum="0"/>
</h:inputText>
...
Mehr Infos

Listing 4: E-Mail-Validator

...
public class EmailAddressValidator implements Validator {

...

private static final Pattern LOCAL_PART_PATTERN
= Pattern .compile(LOCAL_PART_SPEC);
private static final Pattern DOMAIN_PATTERN
= Pattern.compile(DOMAIN_SPEC);

public void validate(
FacesContext facesContext, UIComponent uiComponent, Object value)
throws ValidatorException {
EmailAddress emailAddress = (EmailAddress) value;

Matcher matcher = LOCAL_PART_PATTERN.matcher(emailAddress.getLocalPart());
if (!matcher.matches()) {
throw new ValidatorException(MessageUtils.createErrorMessage(
"validator_email_local_part", facesContext));
}
matcher = DOMAIN_PATTERN.matcher(emailAddress.getDomain());
if (!matcher.matches()) {
throw new ValidatorException(MessageUtils.createErrorMessage(
"validator_email_domain", facesContext));
}
}
}
Mehr Infos

Listing 5: Context Listener

... 
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml</param-value>
</context-param>
...
Mehr Infos

Listing 6: Service-Referenzierung

... 
<managed-bean>
<managed-bean-name>controller</managed-bean-name>
<managed-bean-class>
addressbook.web.Controller
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>addressDao</property-name>
<value>#{addressDao}</value>
</managed-property>
</managed-bean>
...

(ka)