Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
207
5. JavaServer Faces (JSF)
• Grundlagen
• Nutzung von JSF-Annotationen
• Validierung von Eingaben
• Ausgabe von Fehlermeldungen
• Auswahl darzustellender Elemente
• typische elementare Software-Architektur
• JSF + JPA
• Visualisierungskomponenten
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
208
Literatur
• M. Marinschek, M. Kurz, G. Müllan, JavaServer Faces 2.0, dpunkt, Heidelberg, 2010 (im Wesentlich auch: http://tutorials.irian.at/jsf/semistatic/introduction.html)
• K. Ka Iok Tong, Beginning JSF 2 APIs and JBoss Seam, Apress, Berkeley, USA, 2009
• Standard: Sun, JSR 314: JavaServer Faces 2.0, http://www.jcp.org/en/jsr/detail?id=314
• Sun, JEE6 Tutorial, http://java.sun.com/javaee/6/docs/tutorial/doc
• Bücher fixieren teilweise auf Eclipse und JBoss; nicht notwendig, funktioniert fast alles mit Netbeans und Glassfish / Apache
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
209
Generelle Ziele
verschiedene Ziele
• Software, die Web als zusätzlichen Nutzen hat (z. B. Web-Präsenz, Kataloge, Bestellmöglichkeiten)
• verteilte Softwaresysteme, die Netz als Komponentenverbindung nutzen (z. B. B2B)
• Arbeitsplatzsoftware, die auch das Web nutzt (nahtlose Integration, Web ist „unsichtbar“)
• letztes Ziel gewinnt immer mehr Bedeutung für andere Ziele
• Aber: Nicht immer ist Web-fähige Software gewünscht!
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
210
Technische Herausforderungen (1/2)
auf welchem Rechner läuft welche Software
• zentraler Server oder peer-to-peer
• Client-Server, wer ist thin, wer ist fat
Browser-fähig oder standalone
• welcher Browser, welche Sicherheitseinstellungen, welche Plugins, welches HTML
• Wie bekommt Kunde Software zum Laufen, wie funktionieren Updates
• darf man, muss man offline arbeiten können
• Usability
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
211
Technische Herausforderungen (2/2)
Sicherheit
• wie Daten sicher verschicken, wem gehört Internet, wer muss zuhören dürfen
Performance und Stabilität
• schnelle Antworten auch bei Last
• saubere, reproduzierbare Transaktionen
• was passiert bei Netzausfall
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
212
Typische Entwicklungsplattformen (Ausschnitt)
.Net / Microsoft• ASP.Net (Active Server Pages, gute Abstraktion, zunächst zu
wenig Web-Server (IIS))• Silverlight (Browser-PlugIn) für RIA, mittlerweile auch lokal• Oberflächen basierend auf WPF (Windows Presentation
Forum, vektorbasiert, anfänglich zu langsam)Java• Servlets, JSP, JSF [später genauer], angegeben mit
steigenden Abstraktionsgrad ser weit verbreitet• verschiedene neue Frameworks (z. B. Apache Wicket)• GWT (Google Widget Toolset), SW einmal in Java schreiben,
dann individuell für Browser in Javascript übersetzen• JavaFX , eigene Sprache nutzt im Browser JRE• Meinung: Silverlight und JavaFX gegenüber Flash(-
Nachfolger) immer im Nachteil
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
213
Konzept eines Seitenaufrufs
• HTML (Hypertext Markup Language)
– Auszeichnungssprache mit festgelegten tags zum Aufbau der Ausgabe
• Ebene 3/4 typisch TCP/IP, Session Ebene 5: HHTP, Darstellungsebene 6: HTML, Programmebene 7: JVM
ClientClientClientClient
WebWebWebWeb----ServerServerServerServer
ServerServerServerServer
HTTPHTTPHTTPHTTP----RequestRequestRequestRequest
HTTPHTTPHTTPHTTP----ResponseResponseResponseResponsemitmitmitmitHTMLHTMLHTMLHTML----Datei im Body Datei im Body Datei im Body Datei im Body
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
214
HTTP-Ablauf
• Client: Request
– get, post, head, put, ... URL HTTP1.x
– Header Info: Accept, Cookie, ...
– Body: Post-Parameter
• Server: Response
– Statusmeldung: HTTP1.x 200 OK, oder 404 Error
– Header Info: Content-type, set-cookie, ...
– Body: Dokument
• Verbindungsabbau
• Protokoll ist zustandslos/gedächtnislos; Client wird bei erneutem Request ohne Trick nicht als Bekannter erkannt
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
215
Web-Server mit Container nutzen
• Servlet: Wortkreation aus den Begriffen „Server“und „Applet“, (serverseitiges Applet)
• Web-Server leitet HTTP-Request an Servlet weiter
• Servlet kann Antwort (HTML-Code) berechnen
• Servlet kann Anfrage-Informationen und Serverumgebung nutzen
• Servlet kann mit anderen Servlets kommunizieren
Container
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
216
Motivation für JSF
• Die Widerverwendbarkeit von Servlets ist gering
• Innerhalb jeder JSP bzw. jedes Servlets müssen ähnliche Schritte ausgeführt werden
• Nur ein Teil der Applikationslogik kann in Tag-Bibliotheken gekapselt werden
• Workflow ist in der Applikationslogik versteckt, dadurch schwer nachvollzierbar
• ab JSF 2.0 sehr flexible Gestaltungsmöglichkeiten, u. a. AJAX-Einbettung
• Hinweis: wir betrachten nur Grundkonzepte (-> mehr evtl. Semesteraufgabe)
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
217
Web-Server mit JSF- (und EJB-) Unterstützung
• Beispiele:
– Apache + Tomcat
– BEA WebLogic Server
– IBM WebSphere (Apache Geronimo)
– JBoss
– Oracle WebLogic
– Sun Glassfish Enterprise Server (Glassfish)
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
218
Konzeptübersicht
Input-Komponente beschrieben in
XHTML...
Web-Seite in XHTML
Output-Komponente beschrieben in
XHTML...
Web-Seite in XHTML
Modell
Java-Programmim Container
im Server
eventeventeventevent
leitet aufleitet aufleitet aufleitet aufFolgeseiteFolgeseiteFolgeseiteFolgeseite
liestliestliestliest
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
219
XHTML
• Idee: HTML nicht XML-konform und zu viele Freiheiten
• XHTML in fast allen Elementen wie HTML
• XHTML basierend auf XML-Schema leichter zu verarbeiten
• Unterschiede zu HTML (Ausschnitt)
– Tags und Attribute müssen klein geschrieben werden
– Attributwerte immer in Anführungsstrichen boarder="7"boarder="7"boarder="7"boarder="7"
– korrekte XML-Syntax: <<<<brbrbrbr/>/>/>/> nicht <<<<brbrbrbr>>>>
– generell saubere Terminierung <<<<inputinputinputinput ... />... />... />... />
• XHTML2 wegen HTML5 zurückgestellt http://www.w3.org/2009/06/xhtml-faq.html
• Standard: http://www.w3.org/TR/xhtml1/
• Literatur: U. Ogbuji, XHTML step-by-step, http://www.ibm.com/developerworks/edu/x-dw-x-xhtml-i.html
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
220
Web-GUI-Komponenten
• JSF bietet alle klassischen GUI-Komponenten zur Darstellung und Bearbeitung an
• Grundidee: Komponenten schicken bei Veränderungen Events
• Nutzung von MVC2
• Komponenten als XHTML eingebettet
<<<<h:inputTexth:inputTexth:inputTexth:inputText id="id="id="id="imnameimnameimnameimname" value="#{" value="#{" value="#{" value="#{modul.namemodul.namemodul.namemodul.name}}}}““““required="true"/>required="true"/>required="true"/>required="true"/>
<<<<h:outputTexth:outputTexth:outputTexth:outputText idididid====""""omnameomnameomnameomname" " " " value="#{modul.namevalue="#{modul.namevalue="#{modul.namevalue="#{modul.name}"/>}"/>}"/>}"/>
• Kontakt zum Java-Programm über Methodenaufrufe (lesend und aufrufend, z. B. modul.setNamemodul.setNamemodul.setNamemodul.setName(...), (...), (...), (...), modul.getNamemodul.getNamemodul.getNamemodul.getName()()()()
• große Komponenten können aus kleineren komponiert werden
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
221
Nulltes JSF-Beispiel (1/11)
• Aufgabe: Modul (Name + Nummer) eingeben und auf zweiter Seite wieder ausgeben
• Beispiel zeigt:
– Konzept der XHTML-Nutzung
– erste JSF-Befehle
– Seitenmanövrierung durch JSF
• 0. Beispiel zeigt nicht:
– ordentliche Softwarearchitektur (Controller und Model trennen)
– Validierungsmöglichkeiten für Eingaben
– Layoutgestaltung
– viele coole Dinge
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
222
<?<?<?<?xmlxmlxmlxml version='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTF----8' ?>8' ?>8' ?>8' ?><!DOCTYPE <!DOCTYPE <!DOCTYPE <!DOCTYPE htmlhtmlhtmlhtml PUBLIC "PUBLIC "PUBLIC "PUBLIC "----//W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 Transitional//ENTransitional//ENTransitional//ENTransitional//EN" " " "
"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1----transitional.dtd">transitional.dtd">transitional.dtd">transitional.dtd"><<<<htmlhtmlhtmlhtml xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/html">">">"><<<<h:headh:headh:headh:head>>>><<<<title>Moduleingabe</titletitle>Moduleingabe</titletitle>Moduleingabe</titletitle>Moduleingabe</title>>>>
</</</</h:headh:headh:headh:head>>>><<<<h:bodyh:bodyh:bodyh:body>>>><<<<h:formh:formh:formh:form>>>><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnameid="mnameid="mnameid="mname" " " " value="#{modul.namevalue="#{modul.namevalue="#{modul.namevalue="#{modul.name}" }" }" }"
required="true"/><brrequired="true"/><brrequired="true"/><brrequired="true"/><br/>/>/>/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnrid="mnrid="mnrid="mnr" " " " value="#{modul.nrvalue="#{modul.nrvalue="#{modul.nrvalue="#{modul.nr}" }" }" }"
required="true"/><brrequired="true"/><brrequired="true"/><brrequired="true"/><br/>/>/>/><<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Abschickenvalue="Abschickenvalue="Abschickenvalue="Abschicken" " " "
action="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmen}"/>}"/>}"/>}"/></</</</h:formh:formh:formh:form>>>>
</</</</h:bodyh:bodyh:bodyh:body>>>></</</</htmlhtmlhtmlhtml>>>>
Nulltes JSF-Beispiel (2/11) - Start index.xhtml
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
223
Nulltes JSF-Beispiel (3/11) - Analyse der Startseite
• Einbinden der JSF-Bibliotheken<<<<htmlhtmlhtmlhtml xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/html""""xmlns:fxmlns:fxmlns:fxmlns:f ="="="="http://java.sun.com/jsf/corehttp://java.sun.com/jsf/corehttp://java.sun.com/jsf/corehttp://java.sun.com/jsf/core" >" >" >" >
• Nutzung von Standard XHTML (vereinfacht, da so als Standardnamensraum gesetzt)
• enge Verwandtschaft HTML zu XHTML (<h:form>)
• für value="#{modul.namevalue="#{modul.namevalue="#{modul.namevalue="#{modul.name}" }" }" }" offene Fragen:
– was ist modul? ( -> Managed Bean)
– warum #? (Trennung von ausführbaren Elementen)
– was passiert bei modul.name? (set/get abhängig von in/out)
• Ausblick: action="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmen}"}"}"}", echtes Event-Handling (Methodenaufruf)
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
224
Nulltes JSF-Beispiel (4/11) - Ausgabe ausgabe.xhtml
<?<?<?<?xmlxmlxmlxml version='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTF----8' ?>8' ?>8' ?>8' ?><!DOCTYPE <!DOCTYPE <!DOCTYPE <!DOCTYPE htmlhtmlhtmlhtml PUBLIC "PUBLIC "PUBLIC "PUBLIC "----//W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 //W3C//DTD XHTML 1.0 Transitional//ENTransitional//ENTransitional//ENTransitional//EN" " " "
"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1"http://www.w3.org/TR/xhtml1/DTD/xhtml1----transitional.dtd">transitional.dtd">transitional.dtd">transitional.dtd"><<<<htmlhtmlhtmlhtml xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/htmlxmlns:h="http://java.sun.com/jsf/html">">">"><<<<h:headh:headh:headh:head>>>><<<<title>Modulausgabe</titletitle>Modulausgabe</titletitle>Modulausgabe</titletitle>Modulausgabe</title>>>>
</</</</h:headh:headh:headh:head>>>><<<<h:bodyh:bodyh:bodyh:body>>>><<<<h:formh:formh:formh:form>>>><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname: "/>: "/>: "/>: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnameid="mnameid="mnameid="mname" " " " value="#{modul.namevalue="#{modul.namevalue="#{modul.namevalue="#{modul.name}"/> <}"/> <}"/> <}"/> <brbrbrbr/>/>/>/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer: "/>: "/>: "/>: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnrid="mnrid="mnrid="mnr" " " " value="#{modul.nr}"/><brvalue="#{modul.nr}"/><brvalue="#{modul.nr}"/><brvalue="#{modul.nr}"/><br/>/>/>/><<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Zurvalue="Zurvalue="Zurvalue="Zur Eingabe" Eingabe" Eingabe" Eingabe"
action="#{modul.eingebenaction="#{modul.eingebenaction="#{modul.eingebenaction="#{modul.eingeben}"/>}"/>}"/>}"/></</</</h:formh:formh:formh:form>>>>
</</</</h:bodyh:bodyh:bodyh:body>>>></</</</htmlhtmlhtmlhtml>>>>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
225
Nulltes JSF-Beispiel (5/11) - Managed Bean [1/3]
packagepackagepackagepackage entitiesentitiesentitiesentities;;;;
importimportimportimport java.io.Serializablejava.io.Serializablejava.io.Serializablejava.io.Serializable;;;;importimportimportimport javax.faces.bean.ManagedBeanjavax.faces.bean.ManagedBeanjavax.faces.bean.ManagedBeanjavax.faces.bean.ManagedBean;;;;importimportimportimport javax.faces.bean.RequestScopedjavax.faces.bean.RequestScopedjavax.faces.bean.RequestScopedjavax.faces.bean.RequestScoped;;;;
@@@@ManagedBean(name="modulManagedBean(name="modulManagedBean(name="modulManagedBean(name="modul")")")")@@@@RequestScopedRequestScopedRequestScopedRequestScopedpublicpublicpublicpublic classclassclassclass Modul Modul Modul Modul implementsimplementsimplementsimplements SerializableSerializableSerializableSerializable {{{{private private private private staticstaticstaticstatic final final final final longlonglonglong serialVersionUIDserialVersionUIDserialVersionUIDserialVersionUID = 1L;= 1L;= 1L;= 1L;private private private private intintintint nrnrnrnr;;;;private String private String private String private String namenamenamename;;;;
publicpublicpublicpublic Modul(){}Modul(){}Modul(){}Modul(){}
publicpublicpublicpublic Modul(intModul(intModul(intModul(int nrnrnrnr, String , String , String , String namenamenamename) {) {) {) {this.nrthis.nrthis.nrthis.nr = = = = nrnrnrnr;;;;this.namethis.namethis.namethis.name = = = = namenamenamename;;;;
}}}}
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
226
Nulltes JSF-Beispiel (6/11) - Managed Bean [2/3]
publicpublicpublicpublic String String String String uebernehmenuebernehmenuebernehmenuebernehmen(){(){(){(){returnreturnreturnreturn "./"./"./"./ausgabe.xhtmlausgabe.xhtmlausgabe.xhtmlausgabe.xhtml";";";";
}}}}
publicpublicpublicpublic String eingeben(){String eingeben(){String eingeben(){String eingeben(){returnreturnreturnreturn "./"./"./"./index.xhtmlindex.xhtmlindex.xhtmlindex.xhtml";";";";
}}}}
publicpublicpublicpublic String String String String getNamegetNamegetNamegetName() {() {() {() {returnreturnreturnreturn namenamenamename;;;;
}}}}
publicpublicpublicpublic voidvoidvoidvoid setName(StringsetName(StringsetName(StringsetName(String namenamenamename) {) {) {) {this.namethis.namethis.namethis.name = = = = namenamenamename;;;;
}}}}
publicpublicpublicpublic intintintint getNrgetNrgetNrgetNr() {() {() {() {returnreturnreturnreturn nrnrnrnr;;;;
}}}}
publicpublicpublicpublic voidvoidvoidvoid setNr(intsetNr(intsetNr(intsetNr(int nrnrnrnr) {) {) {) {this.nrthis.nrthis.nrthis.nr = = = = nrnrnrnr;;;;
}}}}
//Man//Man//Man//Manöööövrierenvrierenvrierenvrieren
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
227
Nulltes JSF-Beispiel (7/11) - Managed Bean [3/3]
@@@@OverrideOverrideOverrideOverridepublicpublicpublicpublic booleanbooleanbooleanboolean equals(Objectequals(Objectequals(Objectequals(Object objectobjectobjectobject) {) {) {) {ifififif ((((object==nullobject==nullobject==nullobject==null || !(|| !(|| !(|| !(objectobjectobjectobject instanceofinstanceofinstanceofinstanceof Modul)) Modul)) Modul)) Modul)) returnreturnreturnreturn falsefalsefalsefalse;;;;
Modul Modul Modul Modul otherotherotherother = (Modul) = (Modul) = (Modul) = (Modul) objectobjectobjectobject;;;;ifififif ((((this.nrthis.nrthis.nrthis.nr != != != != other.nrother.nrother.nrother.nr || !|| !|| !|| !this.name.equals(other.namethis.name.equals(other.namethis.name.equals(other.namethis.name.equals(other.name)) )) )) )) returnreturnreturnreturn falsefalsefalsefalse;;;;
returnreturnreturnreturn truetruetruetrue;;;;}}}}
@@@@OverrideOverrideOverrideOverride // generieren lassen// generieren lassen// generieren lassen// generieren lassenpublicpublicpublicpublic intintintint hashCodehashCodehashCodehashCode() {() {() {() {intintintint hashhashhashhash = 5;= 5;= 5;= 5;hashhashhashhash = 47 * = 47 * = 47 * = 47 * hashhashhashhash + + + + this.nrthis.nrthis.nrthis.nr;;;;hashhashhashhash = 47 * = 47 * = 47 * = 47 * hashhashhashhash
+ (+ (+ (+ (this.namethis.namethis.namethis.name != null ? != null ? != null ? != null ? this.name.hashCodethis.name.hashCodethis.name.hashCodethis.name.hashCode() : 0);() : 0);() : 0);() : 0);returnreturnreturnreturn hashhashhashhash;;;;
}}}}
@@@@OverrideOverrideOverrideOverridepublicpublicpublicpublic String String String String toStringtoStringtoStringtoString() {() {() {() {returnreturnreturnreturn name+"("+nrname+"("+nrname+"("+nrname+"("+nr+")";}+")";}+")";}+")";}
}}}}
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
228
Nulltes JSF-Beispiel (8/11) - web.xml [1/2]• Konfigurationsdatei für Servlets (hier benötigt)• sun-web.xml ist Glassfish-spezifische Konfiguratonsdatei<?<?<?<?xmlxmlxmlxml version="1.0" encoding="UTFversion="1.0" encoding="UTFversion="1.0" encoding="UTFversion="1.0" encoding="UTF----8"?>8"?>8"?>8"?><<<<webwebwebweb----appappappapp version="3.0" version="3.0" version="3.0" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaee" " " " xmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchema----instance" instance" instance" instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/web----app_3_0.xsd">app_3_0.xsd">app_3_0.xsd">app_3_0.xsd">
<<<<contextcontextcontextcontext----paramparamparamparam>>>><<<<paramparamparamparam----name>javax.faces.PROJECT_STAGE</paramname>javax.faces.PROJECT_STAGE</paramname>javax.faces.PROJECT_STAGE</paramname>javax.faces.PROJECT_STAGE</param----namenamenamename>>>><<<<paramparamparamparam----value>Development</paramvalue>Development</paramvalue>Development</paramvalue>Development</param----valuevaluevaluevalue>>>>
</</</</contextcontextcontextcontext----paramparamparamparam>>>><<<<servletservletservletservlet>>>><<<<servletservletservletservlet----name>Facesname>Facesname>Facesname>Faces Servlet</servletServlet</servletServlet</servletServlet</servlet----namenamenamename>>>><<<<servletservletservletservlet----class>javax.faces.webapp.FacesServletclass>javax.faces.webapp.FacesServletclass>javax.faces.webapp.FacesServletclass>javax.faces.webapp.FacesServlet</</</</servletservletservletservlet----classclassclassclass>>>><load<load<load<load----onononon----startup>1</loadstartup>1</loadstartup>1</loadstartup>1</load----onononon----startup>startup>startup>startup>
</</</</servletservletservletservlet>>>>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
229
Nulltes JSF-Beispiel (9/11) - web.xml [2/2]
<<<<servletservletservletservlet----mappingmappingmappingmapping>>>><<<<servletservletservletservlet----name>Facesname>Facesname>Facesname>Faces Servlet</servletServlet</servletServlet</servletServlet</servlet----namenamenamename>>>><<<<urlurlurlurl----pattern>/faces/*</urlpattern>/faces/*</urlpattern>/faces/*</urlpattern>/faces/*</url----patternpatternpatternpattern>>>>
</</</</servletservletservletservlet----mappingmappingmappingmapping>>>><<<<sessionsessionsessionsession----configconfigconfigconfig>>>><<<<sessionsessionsessionsession----timeouttimeouttimeouttimeout>>>>30303030
</</</</sessionsessionsessionsession----timeouttimeouttimeouttimeout>>>></</</</sessionsessionsessionsession----configconfigconfigconfig>>>><<<<welcomewelcomewelcomewelcome----filefilefilefile----listlistlistlist>>>><<<<welcomewelcomewelcomewelcome----file>faces/index.xhtml</welcomefile>faces/index.xhtml</welcomefile>faces/index.xhtml</welcomefile>faces/index.xhtml</welcome----filefilefilefile>>>>
</</</</welcomewelcomewelcomewelcome----filefilefilefile----listlistlistlist>>>></</</</webwebwebweb----appappappapp>>>>
in sun-web.xml steht u. a.<context<context<context<context----root>/JSFSpielerei2</contextroot>/JSFSpielerei2</contextroot>/JSFSpielerei2</contextroot>/JSFSpielerei2</context----root>root>root>root>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
230
Nulltes JSF-Beispiel (10/11) - Projektstruktur
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
231
Nulltes JSF-Beispiel (11/11) - Ergebnis
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
232
Basisprinzip der Applikationssteuerung
• Im Controller: Auftruf einer Methode ohne Parameter vom Rückgabetyp String<<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Abschickenvalue="Abschickenvalue="Abschickenvalue="Abschicken" " " "
action="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmenaction="#{modul.uebernehmen}"/>}"/>}"/>}"/>
• Im Modell:publicpublicpublicpublic String String String String uebernehmenuebernehmenuebernehmenuebernehmen(){(){(){(){
returnreturnreturnreturn "./"./"./"./ausgabe.xhtmlausgabe.xhtmlausgabe.xhtmlausgabe.xhtml";";";";}}}}
• Methode kann natürlich abhängig von Variablen unterschiedliche Seiten liefern
• Beachten: Navigation kann in den Tiefen des Codes verschwinden ( -> Konstanten nutzen, Architektur)
• Hinweis: wir werden noch Varianten kennenlernen
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
233
Lebensdauer von Informationen (scope)
• Anmerkung: Obwohl es verlockend ist, viele Informationen in Session oder Application zu legen, ist dies wg Performance verboten (wird gespeichert, evtl. passiviert, hat wilde Referenzen, Zugriff muss ggfls. synchronisiert werden)
RequestRequestRequestRequest
SessionSessionSessionSession
ApplicationApplicationApplicationApplication
nur für einenAufruf (auch fürWeiterleitung)
für eineNutzer-Sitzung
solangeaktuellesDeploymentläuft
NoneNoneNoneNone
nur aktuelleSeite
Zeit
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
234
Scope-Beispiel (1/5) - Bean-Klasse
//@//@//@//@ManagedBean(nameManagedBean(nameManagedBean(nameManagedBean(name = "= "= "= "modulmodulmodulmodul")")")")//@//@//@//@RequestScopedRequestScopedRequestScopedRequestScoped Modul als einfache KlasseModul als einfache KlasseModul als einfache KlasseModul als einfache Klassepublicpublicpublicpublic classclassclassclass Modul Modul Modul Modul implementsimplementsimplementsimplements SerializableSerializableSerializableSerializable { ...// wie vorher{ ...// wie vorher{ ...// wie vorher{ ...// wie vorher
@@@@ManagedBean(nameManagedBean(nameManagedBean(nameManagedBean(name = "= "= "= "modulnmodulnmodulnmoduln")")")")
@@@@NoneScopedNoneScopedNoneScopedNoneScopedpublic class public class public class public class ModulNoneModulNoneModulNoneModulNone extends extends extends extends ModulModulModulModul{}{}{}{}
@@@@ManagedBean(nameManagedBean(nameManagedBean(nameManagedBean(name = "= "= "= "modulrmodulrmodulrmodulr")")")")
@@@@RequestScopedRequestScopedRequestScopedRequestScopedpublic class public class public class public class ModulRequestModulRequestModulRequestModulRequest extends extends extends extends ModulModulModulModul{}{}{}{}
@@@@ManagedBean(nameManagedBean(nameManagedBean(nameManagedBean(name = "= "= "= "modulsmodulsmodulsmoduls")")")")
@@@@SessionScopedSessionScopedSessionScopedSessionScopedpublic class public class public class public class ModulSessionModulSessionModulSessionModulSession extends extends extends extends ModulModulModulModul{}{}{}{}
@@@@ManagedBean(nameManagedBean(nameManagedBean(nameManagedBean(name = "= "= "= "modulamodulamodulamodula")")")")
@@@@ApplicationScopedApplicationScopedApplicationScopedApplicationScopedpublicpublicpublicpublic classclassclassclass ModulApplicationModulApplicationModulApplicationModulApplication extendsextendsextendsextends Modul{}Modul{}Modul{}Modul{}
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
235
Scope-Beispiel (2/5) - Ausschnitt index.xhtml<<<<h:formh:formh:formh:form>>>><<<<h:panelGridh:panelGridh:panelGridh:panelGrid columns="3" >columns="3" >columns="3" >columns="3" ><<<<h:outputLabelh:outputLabelh:outputLabelh:outputLabel for="mnamenfor="mnamenfor="mnamenfor="mnamen" " " " value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnamenid="mnamenid="mnamenid="mnamen" " " " value="#{moduln.namevalue="#{moduln.namevalue="#{moduln.namevalue="#{moduln.name}"/>}"/>}"/>}"/><<<<h:messageh:messageh:messageh:message for="mnamenfor="mnamenfor="mnamenfor="mnamen" />" />" />" /><<<<h:outputLabelh:outputLabelh:outputLabelh:outputLabel for="mnrnfor="mnrnfor="mnrnfor="mnrn" " " " value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnrnid="mnrnid="mnrnid="mnrn" " " " value="#{moduln.nrvalue="#{moduln.nrvalue="#{moduln.nrvalue="#{moduln.nr}"/> }"/> }"/> }"/> <<<<h:messageh:messageh:messageh:message for="mnrnfor="mnrnfor="mnrnfor="mnrn" />" />" />" /><<<<h:outputLabelh:outputLabelh:outputLabelh:outputLabel for="mnamerfor="mnamerfor="mnamerfor="mnamer" " " " value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnamerid="mnamerid="mnamerid="mnamer" " " " value="#{modulr.namevalue="#{modulr.namevalue="#{modulr.namevalue="#{modulr.name}"/>}"/>}"/>}"/><<<<h:messageh:messageh:messageh:message for="mnamerfor="mnamerfor="mnamerfor="mnamer" />" />" />" /><<<<h:outputLabelh:outputLabelh:outputLabelh:outputLabel for="mnrrfor="mnrrfor="mnrrfor="mnrr" " " " value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer "/>"/>"/>"/><<<<h:inputTexth:inputTexth:inputTexth:inputText id="mnrrid="mnrrid="mnrrid="mnrr" " " " value="#{modulr.nrvalue="#{modulr.nrvalue="#{modulr.nrvalue="#{modulr.nr}"/> }"/> }"/> }"/> <<<<h:messageh:messageh:messageh:message for="mnrrfor="mnrrfor="mnrrfor="mnrr" />" />" />" /><!<!<!<!-------- auch auch auch auch modulsmodulsmodulsmoduls und und und und modulamodulamodulamodula -------->>>><<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Abschickenvalue="Abschickenvalue="Abschickenvalue="Abschicken""""
action="#{modulr.uebernehmenaction="#{modulr.uebernehmenaction="#{modulr.uebernehmenaction="#{modulr.uebernehmen}"/>}"/>}"/>}"/></</</</h:panelGridh:panelGridh:panelGridh:panelGrid>>>>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
236
Scope-Beispiel (3/5) - Ausschnitt ausgabe.xhtml
<<<<h:formh:formh:formh:form>>>><<<<h:messagesh:messagesh:messagesh:messages globalOnly="trueglobalOnly="trueglobalOnly="trueglobalOnly="true"/>"/>"/>"/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname n: "/>n: "/>n: "/>n: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnamenid="mnamenid="mnamenid="mnamen" " " " value="#{moduln.namevalue="#{moduln.namevalue="#{moduln.namevalue="#{moduln.name}"/> <}"/> <}"/> <}"/> <brbrbrbr/>/>/>/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer n: "/>n: "/>n: "/>n: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnrnid="mnrnid="mnrnid="mnrn" " " " value="#{moduln.nr}"/><brvalue="#{moduln.nr}"/><brvalue="#{moduln.nr}"/><brvalue="#{moduln.nr}"/><br/>/>/>/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnamevalue="Modulnamevalue="Modulnamevalue="Modulname r: "/>r: "/>r: "/>r: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnamerid="mnamerid="mnamerid="mnamer" " " " value="#{modulr.namevalue="#{modulr.namevalue="#{modulr.namevalue="#{modulr.name}"/> <}"/> <}"/> <}"/> <brbrbrbr/>/>/>/><<<<h:outputTexth:outputTexth:outputTexth:outputText value="Modulnummervalue="Modulnummervalue="Modulnummervalue="Modulnummer r: "/>r: "/>r: "/>r: "/><<<<h:outputTexth:outputTexth:outputTexth:outputText id="mnrrid="mnrrid="mnrrid="mnrr" " " " value="#{modulr.nr}"/><brvalue="#{modulr.nr}"/><brvalue="#{modulr.nr}"/><brvalue="#{modulr.nr}"/><br/>/>/>/><<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Zurvalue="Zurvalue="Zurvalue="Zur Eingabe" Eingabe" Eingabe" Eingabe"
action="#{modulr.eingeben}"/><braction="#{modulr.eingeben}"/><braction="#{modulr.eingeben}"/><braction="#{modulr.eingeben}"/><br/>/>/>/><!<!<!<!-------- auch auch auch auch modulsmodulsmodulsmoduls und und und und modulamodulamodulamodula -------->>>><<<<h:commandButtonh:commandButtonh:commandButtonh:commandButton value="Ausgabevalue="Ausgabevalue="Ausgabevalue="Ausgabe wiederholen" wiederholen" wiederholen" wiederholen"
action="#{modulr.uebernehmenaction="#{modulr.uebernehmenaction="#{modulr.uebernehmenaction="#{modulr.uebernehmen}"/>}"/>}"/>}"/></</</</h:formh:formh:formh:form>>>>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
237
Scope-Beispiel (4/5) - Ein Nutzer, zwei Klicks
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
238
Scope-Beispiel (5/5) - Zwei NutzerN
utz
er
1N
utz
er
2
Zeit
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
239
Manövrieren vor JSF 2.0
• Grundidee: Automat mit Seiten als Knoten (Zustände), Übergang findet durch String-Konstanten statt
• String-Konstanten sind Ergebnisse von (Action-) Methoden (oder stehen direkt in action="EINGEBENaction="EINGEBENaction="EINGEBENaction="EINGEBEN"""")
index.xhtml
ausgabe.xhtml
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
240
Manövrieren vor JSF 2.0 - faces-config.xml 1/2<?<?<?<?xmlxmlxmlxml version='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTFversion='1.0' encoding='UTF----8'?>8'?>8'?>8'?><<<<facesfacesfacesfaces----configconfigconfigconfig version="1.2" version="1.2" version="1.2" version="1.2"
xmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaeexmlns="http://java.sun.com/xml/ns/javaee" " " " xmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchemaxmlns:xsi="http://www.w3.org/2001/XMLSchema----instance" instance" instance" instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeexsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/webhttp://java.sun.com/xml/ns/javaee/web----facesconfig_1_2.xsd">facesconfig_1_2.xsd">facesconfig_1_2.xsd">facesconfig_1_2.xsd">
<<<<navigationnavigationnavigationnavigation----rulerulerulerule>>>><<<<fromfromfromfrom----viewviewviewview----id>/index.xhtml</fromid>/index.xhtml</fromid>/index.xhtml</fromid>/index.xhtml</from----viewviewviewview----idididid>>>><<<<navigationnavigationnavigationnavigation----casecasecasecase>>>><<<<fromfromfromfrom----outcome>ANZEIGEN</fromoutcome>ANZEIGEN</fromoutcome>ANZEIGEN</fromoutcome>ANZEIGEN</from----outcomeoutcomeoutcomeoutcome>>>><<<<totototo----viewviewviewview----id>/ausgabe.xhtml</toid>/ausgabe.xhtml</toid>/ausgabe.xhtml</toid>/ausgabe.xhtml</to----viewviewviewview----idididid>>>>
</</</</navigationnavigationnavigationnavigation----casecasecasecase>>>></</</</navigationnavigationnavigationnavigation----rulerulerulerule>>>><<<<navigationnavigationnavigationnavigation----rulerulerulerule>>>><<<<fromfromfromfrom----viewviewviewview----id>/ausgabe.xhtml</fromid>/ausgabe.xhtml</fromid>/ausgabe.xhtml</fromid>/ausgabe.xhtml</from----viewviewviewview----idididid>>>><<<<navigationnavigationnavigationnavigation----casecasecasecase>>>><<<<fromfromfromfrom----outcome>EINGEBEN</fromoutcome>EINGEBEN</fromoutcome>EINGEBEN</fromoutcome>EINGEBEN</from----outcomeoutcomeoutcomeoutcome>>>><<<<totototo----viewviewviewview----idididid>/ >/ >/ >/ index.xhtmlindex.xhtmlindex.xhtmlindex.xhtml </</</</totototo----viewviewviewview----idididid>>>>
</</</</navigationnavigationnavigationnavigation----casecasecasecase>>>></</</</navigationnavigationnavigationnavigation----rulerulerulerule>>>>
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
241
Manövrieren vor JSF 2.0 - Managed Bean
// statt durch Annotationen k// statt durch Annotationen k// statt durch Annotationen k// statt durch Annotationen köööönnen nnen nnen nnen BeansBeansBeansBeans auch in auch in auch in auch in facesfacesfacesfaces----// // // // config.xmlconfig.xmlconfig.xmlconfig.xml angelegt werdenangelegt werdenangelegt werdenangelegt werdenpublicpublicpublicpublic classclassclassclass Modul Modul Modul Modul implementsimplementsimplementsimplements SerializableSerializableSerializableSerializable {{{{private private private private staticstaticstaticstatic final final final final longlonglonglong serialVersionUIDserialVersionUIDserialVersionUIDserialVersionUID = 1L;= 1L;= 1L;= 1L;private private private private intintintint nrnrnrnr;;;;private String private String private String private String namenamenamename;;;;// fehlt: // fehlt: // fehlt: // fehlt: getgetgetget---- und und und und setsetsetset----MethodenMethodenMethodenMethoden ffffüüüür Exemplarvariablenr Exemplarvariablenr Exemplarvariablenr Exemplarvariablenpublicpublicpublicpublic Modul(){}Modul(){}Modul(){}Modul(){}
publicpublicpublicpublic String String String String uebernehmenuebernehmenuebernehmenuebernehmen(){ //Action(){ //Action(){ //Action(){ //Action----MethodeMethodeMethodeMethode// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen mööööglichglichglichglichreturnreturnreturnreturn "ANZEIGEN";"ANZEIGEN";"ANZEIGEN";"ANZEIGEN";
}}}}
publicpublicpublicpublic String eingeben(){String eingeben(){String eingeben(){String eingeben(){// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen m// Zugriff auf Exemplarvariablen mööööglichglichglichglichreturnreturnreturnreturn "EINGEBEN";"EINGEBEN";"EINGEBEN";"EINGEBEN";
}}}}............
}}}}
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
242
Manövrieren vor JSF 2.0 - faces-config.xml 2/2
<<<<managedmanagedmanagedmanaged----beanbeanbeanbean>>>><<<<managedmanagedmanagedmanaged----beanbeanbeanbean----name>modul</managedname>modul</managedname>modul</managedname>modul</managed----beanbeanbeanbean----namenamenamename>>>><<<<managedmanagedmanagedmanaged----beanbeanbeanbean----class>entities.Modul</managedclass>entities.Modul</managedclass>entities.Modul</managedclass>entities.Modul</managed----beanbeanbeanbean----classclassclassclass>>>><<<<managedmanagedmanagedmanaged----beanbeanbeanbean----scope>request</managedscope>request</managedscope>request</managedscope>request</managed----beanbeanbeanbean----scopescopescopescope>>>>
</</</</managedmanagedmanagedmanaged----beanbeanbeanbean>>>></</</</facesfacesfacesfaces----configconfigconfigconfig>>>>
Vorteil der klassischen Navigation:
• Es gibt zentrale Stelle, an der es einen Überblick über mögliche Abläufe gibt
Nachteile:
• JSF 2.0 bietet flexiblere Ablaufsteuerung
• XML ist schwer nachvollziehbar
• Konfigurationsdatei facesfacesfacesfaces----config.xmlconfig.xmlconfig.xmlconfig.xml bleibt trotzdem wichtig
Komponentenbasierte Software-Entwicklung
Prof. Dr. Stephan Kleuker
243
Erinnerung: Konstanten in Programmen
• schlecht returnreturnreturnreturn "ANZEIGEN";"ANZEIGEN";"ANZEIGEN";"ANZEIGEN";
• besser: Konstanten getrennt deklarierenpublicpublicpublicpublic classclassclassclass Modul Modul Modul Modul implementsimplementsimplementsimplements SerializableSerializableSerializableSerializable{{{{private final private final private final private final staticstaticstaticstatic stringstringstringstring ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";............returnreturnreturnreturn ANZEIGEN;ANZEIGEN;ANZEIGEN;ANZEIGEN;
• Alternativ: Klasse mit Konstantenpackagepackagepackagepackage konstanten;konstanten;konstanten;konstanten;publicpublicpublicpublic classclassclassclass Navigation{Navigation{Navigation{Navigation{publicpublicpublicpublic final final final final staticstaticstaticstatic stringstringstringstring ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";ANZEIGEN = "ANZEIGEN";............returnreturnreturnreturn konstanten.Navigation.ANZEIGENkonstanten.Navigation.ANZEIGENkonstanten.Navigation.ANZEIGENkonstanten.Navigation.ANZEIGEN;;;;
– Entwicklungsumgebungen erlauben dann einfache Suche und Änderung (Refactoring)