5. JavaServer Faces (JSF) 5.1 Grundlagen 5.2 Einführendes nulltes Beispiel 5.3 Validierung 5.4 JSF mit JPA und JNDI 5.5 Kompakt: EJB-SessionBeansund CDI 5.6 Funktionale Erweiterung 5.7 Sicherheit 5.8 Weitere JSF-Möglichkeiten 5.9 JSF-Lebenszyklus 5.10 Templates und Komponenten 5.11 Nutzung von Ajax 5.12 Testen von Web-Applikationen - Selenium 5.13 JSF-Erweiterungen 246
Literatur E.Burns, C. Schalk, JavaServer Faces 2.0: The Complete Reference, Mc Graw Hill, New York, 2010 M. Marinschek, M. Kurz, G. Müllan, JavaServerFaces2.0, dpunkt, Heidelberg, 2010 (im Wesentlichen auch: http://tutorials.irian.at/jsf/semistatic/introduction.html) D. Geary, C. Horstmann, Core JavaServerFaces, 3. Auflage, Prentice Hall, USA, 2010 K. Ka IokTong, Beginning JSF 2 APIs and JBossSeam, Apress, Berkeley, USA, 2009 Standard: Sun, JSR 314: JavaServerFaces 2.1, http://www.jcp.org/en/jsr/detail?id=314 Sun, JEE6 Tutorial, http://download.oracle.com/javaee/6/tutorial/doc/ Bücher fixieren teilweise auf Eclipse und JBoss; nicht notwendig, funktioniert fast alles mit Netbeans und Glassfish / Apache 247
5.1 Grundlagen verschiedene Ziele von JSF-Applikationen 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! 248
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 249
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 250
Typische splattformen (Ausschnitt).Net / Microsoft ASP.Net(ActiveServer 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 sehr weit verbreitet verschiedene neue Frameworks (z. B. Apache Wicket) GWT (Google WidgetToolset), SW einmal in Java schreiben, dann individuell für Browser in Javascript übersetzen JavaFX, eigene Sprache nutzt im Browser JRE Meinung: Silverlight und JavaFXgegenüber HTML5 und aktuell noch Flash immer im Nachteil 251
Konzept eines Seitenaufrufs Client HTTP-Request HTTP-Response mit HTML-Datei im Body HTML (Hypertext Markup Language) Web- Container Application Server Auszeichnungssprache mit festgelegten tags zum Aufbau der Ausgabe Ebene 3/4 typisch TCP/IP, Session Ebene 5: HHTP, Darstellungsebene 6: HTML, Programmebene 7: JVM EJB- Container 252
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 253
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 254
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) 255
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) 256
Konzeptübersicht Web-Seite in XHTML Input-Komponente beschrieben in XHTML... Web-Seite in XHTML Output-Komponente beschrieben in XHTML... event leitet auf Folgeseite liest Modell Java-Programm im Container im Server 257
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 korrekte XML-Syntax: <br br/> />nicht <br br> generell saubere Terminierung <input... /> boarder="7" XHTML2 wegen HTML5 zurückgestellt (verschwimmt damit) 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 258
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:inputtext id="imname" value="#{modul.name required="true"/> <h:outputtext id="omname" value="#{modul.name"/> Kontakt zum Java-Programm über Methodenaufrufe (lesend und aufrufend, z. B. modul.setname(...), modul.getname() große Komponenten können aus kleineren komponiert werden 259
5.2 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 260
Nulltes JSF-Beispiel (2/11) - Start index.xhtml <?xml version='1.0' encoding='utf ='UTF-8'?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/ ="http://java.sun.com/jsf jsf/html html"> <h:head h:head> <title>moduleingabetitle> h:head h:head> <h:body h:body> <h:form h:form> <h:outputtext value="modulname "/> <h:inputtext id=" ="mname mname" value="#{modul.name" required=" ="true true"/>< "/><br br/> <h:outputtext value="modulnummer "/> <h:inputtext id=" ="mnr mnr" value="#{modul.nr" required=" ="true true"/>< "/><br br/> <h:commandbutton value="abschicken" action="#{ ="#{modul.uebernehmen modul.uebernehmen"/> h:form h:form> h:body h:body> html html> 261
Nulltes JSF-Beispiel (3/11) - Analyse der Startseite Einbinden der JSF-Bibliotheken <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/ ="http://java.sun.com/jsf jsf/html html" xmlns:f ="http://java.sun.com/jsf jsf/core core" > Nutzung von Standard XHTML (vereinfacht, da so als Standardnamensraum gesetzt) enge Verwandtschaft HTML zu XHTML (<h:form>) für value="#{modul.name" offene Fragen: was ist modul? (-> ManagedBean) warum #?(Trennung von ausführbaren Elementen) was passiert bei modul.name? (set/getabhängig von in/out) Ausblick: action="#{ Handling (Methodenaufruf) ="#{modul.uebernehmen modul.uebernehmen" ", echtes Event- 262
Nulltes JSF-Beispiel (4/11) - Ausgabe ausgabe.xhtml <?xml version='1.0' encoding='utf ='UTF-8'?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/ ="http://java.sun.com/jsf jsf/html html"> <h:head h:head> <title>modulausgabetitle> h:head h:head> <h:body h:body> <h:form h:form> <h:outputtext value="modulname: "/> <h:outputtext id=" ="mname mname" value="#{modul.name"/> <br br/> <h:outputtext value="modulnummer: "/> <h:outputtext id=" ="mnr mnr" value="#{modul.nr"/>< ="#{modul.nr"/><br br/> <h:commandbutton value="zur Eingabe" action="#{ ="#{modul.eingeben modul.eingeben"/> h:form h:form> h:body h:body> html html> 263
Nulltes JSF-Beispiel (5/11) - Managed Bean [1/3] package entities; import java.io.serializable; import javax.faces.bean.managedbean; import javax.faces.bean.requestscoped; @ManagedBean ManagedBean(name name=" ="modul modul") @RequestScoped public class Modul implements Serializable { private static final long serialversionuid = 1L; private int nr; private String name; public Modul(){ public Modul(int nr, String name) { this.nr = nr; this.name = name; 264
Nulltes JSF-Beispiel (6/11) - Managed Bean [2/3] public String uebernehmen(){ return "./ausgabe.xhtml ausgabe.xhtml"; public String eingeben(){ return "./index.xhtml index.xhtml"; public String getname() { return name; public void setname(string name) { this.name = name; public int getnr() { return nr; public void setnr(int nr) { this.nr = nr; //Manövrieren 265
Nulltes JSF-Beispiel (7/11) - Managed Bean [3/3] @Override public boolean equals(object object) { if (object object==null!(object instanceof Modul)) return false; Modul other = (Modul) object; if (this.nr!= other.nr!this.name.equals this.name.equals(other.name)) return false; return true; @Override // generieren lassen public int hashcode() { int hash = 5; hash = 47 * hash + this.nr; hash = 47 * hash + (this.name!= null? this.name.hashcode() : 0); return hash; @Override public String tostring() {return name+"("+ +"("+nr nr+")"; 266
267 Nulltes JSF-Beispiel (8/11) - web.xml [1/2] Konfigurationsdatei für Servlets (hier benötigt) sun-web.xml ist Glassfish-spezifische Konfiguratonsdatei <? <? <? <?xml xml xml xml version version version version="1.0" ="1.0" ="1.0" ="1.0" encoding encoding encoding encoding="utf ="UTF ="UTF ="UTF-8"?> 8"?> 8"?> 8"?> <web <web <web <web-app app app app version version version version="3.0" ="3.0" ="3.0" ="3.0" xmlns xmlns xmlns xmlns="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/xml xml xml xml/ns ns ns ns/javaee javaee javaee javaee" xmlns:xsi xmlns:xsi xmlns:xsi xmlns:xsi="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema-instance" instance" instance" instance" xsi:schemalocation xsi:schemalocation xsi:schemalocation xsi:schemalocation="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/xml xml xml xml/ns ns ns ns/javaee javaee javaee javaee http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> app_3_0.xsd"> app_3_0.xsd"> app_3_0.xsd"> <context context context context-param param param param> <param param param param-name> name> name> name>javax.faces.project_stage javax.faces.project_stage javax.faces.project_stage javax.faces.project_stage param param param param-name> name> name> name> <param param param param-value value value value>development >Development >Development >Developmentparam param param param-value value value value> context context context context-param param param param> <servlet servlet servlet servlet> <servlet servlet servlet servlet-name> name> name> name>faces Faces Faces Faces Servlet Servlet Servlet Servletservlet servlet servlet servlet-name> name> name> name> <servlet servlet servlet servlet-class class class class>javax.faces.webapp.facesservlet javax.faces.webapp.facesservlet javax.faces.webapp.facesservlet javax.faces.webapp.facesservlet servlet servlet servlet servlet-class class class class> <load load load load-on on on on-startup>1 startup>1 startup>1 startup>1load load load load-on on on on-startup> startup> startup> startup> servlet servlet servlet servlet>
268 Nulltes JSF-Beispiel (9/11) - web.xml [2/2] <servlet servlet servlet servlet-mapping mapping mapping mapping> <servlet servlet servlet servlet-name> name> name> name>faces Faces Faces Faces Servlet Servlet Servlet Servletservlet servlet servlet servlet-name> name> name> name> <url url url url-pattern>/ pattern>/ pattern>/ pattern>/faces faces faces faces/* /* /* /*url url url url-pattern> pattern> pattern> pattern> servlet servlet servlet servlet-mapping mapping mapping mapping> <session session session session-config config config config> <session session session session-timeout> timeout> timeout> timeout> 30 30 30 30 session session session session-timeout> timeout> timeout> timeout> session session session session-config config config config> <welcome welcome welcome welcome-file file file file-list> list> list> list> <welcome welcome welcome welcome-file> file> file> file>faces faces faces faces/index.xhtml index.xhtml index.xhtml index.xhtml welcome welcome welcome welcome-file> file> file> file> welcome welcome welcome welcome-file file file file-list> list> list> list> web web web web-app app app app> in sun-web.xml steht u. a. <context context context context-root root root root>/jsfspielerei2 >/JSFSpielerei2 >/JSFSpielerei2 >/JSFSpielerei2context context context context-root root root root>
Nulltes JSF-Beispiel (10/11) - Projektstruktur 269
Nulltes JSF-Beispiel (11/11) - Ergebnis 270
Einschub: IE 9 -Problem Programm läuft problemlos in Firefox und Chrome in IE 8 gab es auch keine Probleme in IE 9, erfolgt nach Drücken des Knopfes folgende Ausgabe 271
Einschub: IE 9 -Lösung Session-Informationen können statt im Server auch im Client gehalten werden entlastet Server, ist aber für Nutzer langsamer Ergänzung in web.xml: <context context-param param> <param param-name> name>javax.faces.state_saving_method javax.faces.state_saving_method param param-name> <param param-value value>client client param param-value value> context context-param param> Anmerkung: fehlt systematische Fehleranalyse: NetBeans 7.2, Glassfish3.1.2, MS IE 9, MS IE 9 Nutzereinstellungen, Win7 x64, 272
Einschub: korrekte Pfadangabe Browser zeugt immer vergangene Seite wenn nicht gewünscht, dann Manövrierungsstring ändern ist etwas langsamer (später genauer) Scope auf @SessionScoped setzen public String uebernehmen(){ return "./ausgabe.xhtml?faces ausgabe.xhtml?faces-redirect redirect=true true"; public String eingeben(){ return "./index.xhtml?faces index.xhtml?faces-redirect redirect=true true"; 273
Basisprinzip der Applikationssteuerung Im Controller: Aufruf einer Methode ohne Parameter vom Rückgabetyp String <h:commandbutton value="abschicken" Im Modell: public String uebernehmen(){ return "./ausgabe.xhtml"; action="#{modul.uebernehmen"/> 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 274
Lebensdauer von Informationen (scope) Request View Session Application nur für einen solange für eine solange Zeit Aufruf Nutzer auf Nutzer- aktuelles (auch für Applikationsseiten bleibt läuft Sitzung Deployment Weiterleitung) Scope None passt sich Aufrufer-Scope an (default kein Leben) Anmerkung: Obwohl es verlockend ist, viele Informationen in Session oder Applicationzu legen, ist dies wgperformance verboten (wird gespeichert, evtl. passiviert, hat wilde Referenzen, Zugriff muss ggfls. synchronisiert werden) 275
Scope-Beispiel (1/5) - Bean-Klasse //@ManagedBean ManagedBean(name name = "modul modul") //@RequestScoped Modul als einfache Klasse (wichtig!) public class Modul implements Serializable {...// wie vorher @ManagedBean ManagedBean(name = "moduln moduln") @NoneScoped public class ModulNone extends Modul{ @ManagedBean ManagedBean(name = "modulr modulr") @RequestScoped public class ModulRequest extends Modul{ @ManagedBean ManagedBean(name = "moduls moduls") @SessionScoped public class ModulSession extends Modul{ @ManagedBean ManagedBean(name name = "modula modula") @ApplicationScoped public class ModulApplication extends Modul{ 276
Scope-Beispiel (2/5) - Ausschnitt index.xhtml <h:form h:form> <h:panelgrid columns="3" > <h:outputlabel for=" ="mnamen mnamen" value="modulname "/> <h:inputtext id=" ="mnamen mnamen" value="#{moduln.name"/> <h:message for=" ="mnamen mnamen" /> <h:outputlabel for=" ="mnrn mnrn" value="modulnummer "/> <h:inputtext id=" ="mnrn mnrn" value="#{moduln.nr"/> <h:message for=" ="mnrn mnrn" /> <h:outputlabel for=" ="mnamer mnamer" value="modulname "/> <h:inputtext id=" ="mnamer mnamer" value="#{modulr.name"/> <h:message for=" ="mnamer mnamer" /> <h:outputlabel for=" ="mnrr mnrr" value="modulnummer "/> <h:inputtext id=" ="mnrr mnrr" value="#{modulr.nr"/> <h:message for=" ="mnrr mnrr" /> <!-- auch moduls und modula --> <h:commandbutton value="abschicken" action="#{ ="#{modulr.uebernehmen modulr.uebernehmen"/> h:panelgrid h:panelgrid> 277
Scope-Beispiel (3/5) - Ausschnitt ausgabe.xhtml <h:form h:form> <h:messages globalonly=" ="true true"/> <h:outputtext value="modulname n: "/> <h:outputtext id=" ="mnamen mnamen" value="#{moduln.name"/> <br br/> <h:outputtext value="modulnummer n: "/> <h:outputtext id=" ="mnrn mnrn" value="#{moduln.nr"/>< ="#{moduln.nr"/><br br/> <h:outputtext value="modulname r: "/> <h:outputtext id=" ="mnamer mnamer" value="#{modulr.name"/> <br br/> <h:outputtext value="modulnummer r: "/> <h:outputtext id=" ="mnrr mnrr" value="#{modulr.nr"/>< ="#{modulr.nr"/><br br/> <h:commandbutton value="zur Eingabe" action="#{ ="#{modulr.eingeben modulr.eingeben"/>< "/><br br/> <!-- auch moduls und modula --> <h:commandbutton value="ausgabe wiederholen" action="#{ ="#{modulr.uebernehmen modulr.uebernehmen"/> h:form h:form> 278
Scope-Beispiel (4/5) - Ein Nutzer, zwei Klicks 279
Scope-Beispiel (5/5) - Zwei Nutzer Nutzer 2 Nutzer 1 Zeit 280
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="eingeben") index.xhtml ausgabe.xhtml 281
282 Manövrieren vor JSF 2.0 - faces-config.xml 1/2 <? <? <? <?xml xml xml xml version version version version='1.0' ='1.0' ='1.0' ='1.0' encoding encoding encoding encoding='utf ='UTF ='UTF ='UTF-8'?> 8'?> 8'?> 8'?> <faces faces faces faces-config config config config version version version version="1.2" ="1.2" ="1.2" ="1.2" xmlns xmlns xmlns xmlns="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/xml xml xml xml/ns ns ns ns/javaee javaee javaee javaee" xmlns:xsi xmlns:xsi xmlns:xsi xmlns:xsi="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema ="http://www.w3.org/2001/xmlschema-instance" instance" instance" instance" xsi:schemalocation xsi:schemalocation xsi:schemalocation xsi:schemalocation="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/ ="http://java.sun.com/xml xml xml xml/ns ns ns ns/javaee javaee javaee javaee http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"> facesconfig_1_2.xsd"> facesconfig_1_2.xsd"> facesconfig_1_2.xsd"> <navigation navigation navigation navigation-rule rule rule rule> <from from from from-view view view view-id id id id>/ >/ >/ >/index.xhtml index.xhtml index.xhtml index.xhtml from from from from-view view view view-id id id id> <navigation navigation navigation navigation-case case case case> <from from from from-outcome outcome outcome outcome>anzeigen >ANZEIGEN >ANZEIGEN >ANZEIGENfrom from from from-outcome outcome outcome outcome> <to to to to-view view view view-id id id id>/ >/ >/ >/ausgabe.xhtml ausgabe.xhtml ausgabe.xhtml ausgabe.xhtml to to to to-view view view view-id id id id> navigation navigation navigation navigation-case case case case> navigation navigation navigation navigation-rule rule rule rule> <navigation navigation navigation navigation-rule rule rule rule> <from from from from-view view view view-id id id id>/ >/ >/ >/ausgabe.xhtml ausgabe.xhtml ausgabe.xhtml ausgabe.xhtml from from from from-view view view view-id id id id> <navigation navigation navigation navigation-case case case case> <from from from from-outcome outcome outcome outcome>eingeben >EINGEBEN >EINGEBEN >EINGEBENfrom from from from-outcome outcome outcome outcome> <to to to to-view view view view-id id id id>/ >/ >/ >/ index.xhtml index.xhtml index.xhtml index.xhtml to to to to-view view view view-id id id id> navigation navigation navigation navigation-case case case case> navigation navigation navigation navigation-rule rule rule rule>
Manövrieren vor JSF 2.0 - Managed Bean // statt durch Annotationen können Beans auch in faces- // config.xml angelegt werden public class Modul implements Serializable { private static final long serialversionuid = 1L; private int nr; private String name; // fehlt: get- und set-methoden für Exemplarvariablen public Modul(){ public String uebernehmen(){ //Action-Methode // Zugriff auf Exemplarvariablen möglich return "ANZEIGEN"; public String eingeben(){ // Zugriff auf Exemplarvariablen möglich return "EINGEBEN";... 283
Manövrieren vor JSF 2.0 - faces-config.xml 2/2 <managed-bean> <managed-bean bean-name>modulmanaged name>modulmanaged-bean bean-name> name> <managed-bean bean-class>entities.modulmanaged class>entities.modulmanaged-bean bean-class> <managed-bean bean-scope>requestmanaged scope>requestmanaged-bean bean-scope> managed-bean> faces-config> config> 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 faces faces-config.xml config.xml config.xml bleibt trotzdem wichtig 284
Erinnerung: Konstanten in Programmen schlecht return "ANZEIGEN"; besser: Konstanten getrennt deklarieren public class Modul implements Serializable{ private final static string ANZEIGEN = "ANZEIGEN";... return ANZEIGEN; Alternativ: Klasse mit Konstanten package konstanten; public class Navigation{ public final static string ANZEIGEN = "ANZEIGEN";... return konstanten.navigation.anzeigen; sumgebungen erlauben dann einfache Suche und Änderung (Refactoring) 285
Standardattribut rendered (1/3) JSF-Elemente werden typischerweise ineinander geschachtelt (typische GUI-Idee der Schächtelchen in Schächtelchen) viele (Schachtel-)Elemente haben Attribut rendered; Boolescher Wert, ob Element dargestellt werden soll @ManagedBean(name="mo") @SessionScoped public class Mojo { private boolean jo=true; public Mojo(){ public boolean getjo() {return jo; public void setjo(boolean jo) {this.jo = jo; public String change(){ jo=!jo; return "./index.xhtml"; 286
Standardattribut rendered (2/3) - JSF-Seite <?xml version='1.0' encoding='utf ='UTF-8'?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/ ="http://java.sun.com/jsf jsf/html html"> <h:head h:head> <title>klickklacktitle> h:head h:head> <h:body h:body> <h:form id="f1"> <h:panelgrid id="p1" rendered="#{mo.jo"> <h:outputlabel value= HS rocks"/> h:panelgrid h:panelgrid> <h:panelgrid id="p2" rendered="#{!mo.jo"> <h:outputlabel value="os rocks"/> h:panelgrid h:panelgrid> <h:commandbutton action="#{ ="#{mo.change mo.change" value="press"/> h:form h:form> h:body h:body> html html> 287
288 Standardattribut rendered (3/3) <? <? <? <?xml xml xml xml version version version version='1.0' ='1.0' ='1.0' ='1.0' encoding encoding encoding encoding='utf ='UTF ='UTF ='UTF-8'?> 8'?> 8'?> 8'?> <faces faces faces faces-config config config config version version version version="1.2"...> ="1.2"...> ="1.2"...> ="1.2"...> <managed managed managed managed-bean bean bean bean> <managed managed managed managed-bean bean bean bean-name> name> name> name>mo mo mo mo managed managed managed managed-bean bean bean bean-name> name> name> name> <managed managed managed managed-bean bean bean bean-class class class class>entities.mojo entities.mojo entities.mojo entities.mojo managed managed managed managed-bean bean bean bean-class class class class> <managed managed managed managed-bean bean bean bean-scope scope scope scope>session session session session managed managed managed managed-bean bean bean bean-scope scope scope scope> managed managed managed managed-bean bean bean bean> faces faces faces faces-config config config config> oder in faces-config.xhtml
Strukturierung mit panelgrid / Kommentare mit h:panelgridkönnen einzelne Komponenten zu einem Block zusammengefasst und einheitlich behandelt werden (ähnlich zu JPanel in Swing) weiterhin kann durch columns="3" eine Spaltenanzahl angegeben werden Ausgabe erfolgt in Tabellenform Elemente werden zeilenweise ergänzt echte JSF-Kommentare sehen wie folgt aus <%-- Dies liest eh keiner --%> 289
5.3 Validierung/ Fehleingaben im nullten Beispiel (1/2) Eingabe: Fehler wird automatisch unter der bleibender Seite ausgegeben j_idt7 ist interner Name, mnameist unsere iddes Eingabefeldes 290
Fehleingaben im nullten Beispiel (2/2) Anpassung des Projektstatus (oder Parameter löschen) in web.xml <context-param> <param-name>javax.faces.project_stageparam name>javax.faces.project_stageparam-name> <!-- <param-value>developmentparam value>developmentparam-value> --> <param-value>productionparam value>productionparam-value> context-param> Applikation bleibt auf der Seite, keine sichtbare Fehlermeldung im Server-Log: INFO: WARNUNG: FacesMessage(s) wurde(n) in die Warteschlange gestellt, aber möglicherweise nicht angezeigt. sourceid=j_idt7:mname[severity=(error 2), summary=(j_idt7:mname: Validierungs-Fehler: Wert wird benötigt.), detail=(j_idt7:mname: Validierungs-Fehler: Wert wird benötigt.)] 291
Direkte Validierungen - einige Möglichkeiten <h:form h:form> <h:panelgrid columns="3" > <h:outputlabel for=" ="mname mname" value="modulname "/> <h:inputtext id=" ="mname mname" value="#{modul.name" required=" ="true true" size="8" requiredmessage=" ="nich leer" validatormessage="4 Zeichen"> <f:validatelength minimum="4" maximum="4"/> h:inputtext h:inputtext> <h:message for=" ="mname mname" /> <h:outputlabel for=" ="mnr mnr" value="modulnummer "/> <h:inputtext id=" ="mnr mnr" value="#{modul.nr" required=" ="true true" requiredmessage="mach Zahl eh" size="4" convertermessage=" ="nomahle Zahl"/> <h:message for=" ="mnr mnr" /> <h:commandbutton value="abschicken" action="#{ ="#{modul.uebernehmen modul.uebernehmen"/> h:panelgrid h:panelgrid> h:form h:form> 292
Ausgaben beim Drücken von Abschicken 293
Globale Fehlermeldungen erzeugen und anzeigen public String uebernehmen() { if (name.equals name.equals("ooad")) { FacesContext ctxt = FacesContext.getCurrentInstance(); FacesMessage ms = new FacesMessage(); ms.setseverity(facesmessage.severity_error FacesMessage.SEVERITY_ERROR); ms.setsummary("ooad ist schon da"); ms.setdetail("ooad im Standard"); ctxt.addmessage(null, ms); return "ANZEIGEN"; //in ausgabe.xhtml <h:form h:form> <h:messages globalonly="true"/> <h:outputtext value="modulname Modulname: "/> 294
Validierer selbst gestrickt (1/2) public class Modul implements Serializable {... // Validierungsmethoden können beliebigen Namen haben, // müssen aber die folgende Signatur haben public void pruefe(facescontext context, UIComponent component, Object value) throws ValidatorException { if (((String) value). ).equals equals("ooad")) { throw new ValidatorException(new new FacesMessage( FacesMessage.SEVERITY_ERROR, "oweh oweh", "ole ole"));... 295
Validierer selbst gestrickt (2/2) in index.xhtml <h:panelgrid columns="3" > <h:outputlabel for=" ="mname mname" value="modulname "/> <h:inputtext id=" ="mname mname" value="#{modul.name" validator="#{ ="#{modul.pruefe modul.pruefe"/> <h:message for=" ="mname mname" /> 296
Erinnerung: Bean Validation nicht: Nutzer Oberfläche Java fachliche Ebene Datenzugriffsschicht DB besser: individuelle Datenvalidierung individuelle Datenvalidierung Java individuelle Datenvalidierung individuelle Datenvalidierung Nutzer Oberfläche fachliche Ebene Datenzugriffsschicht DB Datenmodell mit Validierungsregeln 297
Beispiel Bean-Validation (1/6) @ManagedBean ManagedBean(name name=" ="modul modul") @RequestScoped public class Modul implements Serializable { private static final long serialversionuid = 1L; @Min(value value=100, message="dreistellig") @Max(value value=999, message="dreistellig") private int nr; @NotNull @Modulnamenregel(verboten={"VHDL","PNP", groups={ ={validators.modulgroup.class validators.modulgroup.class) private String name; //... übliche Konstruktoren, get und set Hinweis: Implementierung des Validierersin Libraries benötigt (Klasseneigenschaften werden nicht unterstützt!?) 298
Beispiel Bean-Validation (2/6) @Target({ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {ModulnamenregelValidator.class) @Documented public @interface Modulnamenregel { String message() default "Modul unerwuenscht"; Class<?>[] groups() default {; Class<? extends Payload>[] payload() default {; String[] verboten() default {; package validators; public interface ModulGroup { 299
Beispiel Bean-Validation (3/6) public class ModulnamenregelValidator implements ConstraintValidator<Modulnamenregel,String>{ private String[] niveau; public void initialize(modulnamenregel ca) { niveau=ca.verboten(); public boolean isvalid(string t, ConstraintValidatorContext cvc) { System.out.println("isValid"); for(string s:niveau) if(s.equals(t)){ cvc.buildconstraintviolationwithtemplate( "Modul in unerwuenschter Liste: " +Arrays.toString(niveau)).addConstraintViolation(); return false; return true; 300
Beispiel Bean-Validation (4/6) - index.xhtml <h:body h:body> <h:form h:form> <h:panelgrid columns="3" > <h:outputlabel for=" ="mname mname" value="modulname "/> <h:inputtext id=" ="mname mname" value="#{modul.name"> <f:validatebean disabled=" ="false false" validationgroups=" ="validators.modulgroup validators.modulgroup"/> h:inputtext h:inputtext> <h:message for=" ="mname mname" /> <h:outputlabel for=" ="mnr mnr" value="modulnummer "/> <h:inputtext id=" ="mnr mnr" value="#{modul.nr" /> <h:message for=" ="mnr mnr" /> <h:commandbutton value="abschicken" action="#{ ="#{modul.uebernehmen modul.uebernehmen"/> h:panelgrid h:panelgrid> h:form h:form> h:body h:body> 301
Beispiel Bean-Validation (5/6) 302
Beispiel Bean-Validation (6/6) 303
Ordentliche Softwarearchitektur JSF-Seite Seite <<managed-bean>> Controller Bean (Entität) #{controller.bearbeiten #{controller.bean.attribut #{controller.speichern Controller (und Bean) auch backing bean genannt bei DB-Nutzung greift Controller auf DB-Verwaltungsschicht zu; die verwaltet Bean-Objekte JPA einfach im Controller (besser eigener Schicht) nutzen (später schöner mit JEE als SessionBean@Stateless) 304
5.4 JSF mit JPA und JNDI Einschub: Nutzung von JPA bei DB im Server Datenbank einrichten Datenbank wird unter JNDI-Namen im Server registriert JSF-Applikation kann über JNDI auf DB zugreifen JSF-Container regelt DB-Zugriff (nicht Nutzer!), typische container-managed Persistance[geht auch individuell] 305
Verwaltung einer Modulliste (1/9) - Entität (Wdh) @Entity public class Modul implements Serializable { private static final long serialversionuid = 1L; @Id @GeneratedValue GeneratedValue(strategy = GenerationType.AUTO) private int id; private int nr; // so sind gleiche Nummern erlaubt private String name; @Version private int version; public Modul() { public Modul(int nr, String name) { this.nr = nr; this.name = name; // fehlen get- und set-methoden, equals über id 306
Verwaltung einer Modulliste (2/9) - Seitenstruktur 307
Verwaltung einer Modulliste (3/9) - Datenbank <?xml version="1.0" encoding="utf-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" instance" xsi:schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="jsfmodulliste1mitjpapu" transaction-type="jta"> type="jta"> <provider>org.eclipse.persistence.jpa.persistenceprovider provider> <jta-data data-source>jsfmodul1jta source>jsfmodul1jta-data data-source> <exclude-unlisted unlisted-classes>falseexclude classes>falseexclude-unlisted unlisted-classes> <properties> <property name="eclipselink.ddl-generation" value="drop-and and-create create-tables"/> tables"/> properties> persistence-unit> persistence> 308
Verwaltung einer Modulliste (4/9) - Startseite <h:form id="f1"> <h:messages globalonly="true"/> <h:panelgrid columns="3" > <h:outputlabel for="mname" value="modulname "/> <h:inputtext id="mname" value="#{module.modul.name"/> <h:message for="mname" /> <h:outputlabel for="mnr" value="modulnummer "/> <h:inputtext id="mnr" value="#{module.modul.nr"/> <h:message for="mnr"/> <h:commandbutton value="abschicken" action="#{module.uebernehmen"/> h:panelgrid> <h:commandlink action="#{module.anzeigen" > <h:outputtext value="zur Modulübersicht"/> h:commandlink> h:form> 309
Verwaltung einer Modulliste (5/9) - Controller 1/3 @ManagedBean ManagedBean(name name=" ="module module") @SessionScoped public class ModuleController { @PersistenceUnit //wichtig, nicht selber erzeugen!!! private EntityManagerFactory emf; @Resource private UserTransaction utx; private List<Modul> module = new ArrayList<Modul>(); private Modul modul=new Modul(); private EntityManager em; private final String HINZUFUEGEN = "./index.xhtml index.xhtml"; private final String ANZEIGEN = "./uebersicht.xhtml uebersicht.xhtml"; private final String EINGEBEN = "./index.xhtml index.xhtml"; public ModuleController() { 310
Verwaltung einer Modulliste (6/9) - Controller 2/3 public Modul getmodul() {return modul; public void setmodul(modul modul) {this.modul = modul; public List<Modul> getmodule() {return module; public void setmodule(list<modul> module) {this.module = module; public String anzeigen() { em = emf.createentitymanager(); module= em.createquery("select m FROM Modul m",modul.class Modul.class).getResultList getresultlist(); em.close(); return ANZEIGEN; public String eingeben() { modul = new Modul(); return EINGEBEN; 311
Verwaltung einer Modulliste (7/9) - Controller 3/3 public String uebernehmen() { FacesContext ctxt = FacesContext.getCurrentInstance(); FacesMessage ms = new FacesMessage("Erfolgreich eingetragen"); try { em = emf.createentitymanager(); utx.begin(); em.persist(modul modul); module= em.createquery("select m FROM Modul m",modul.class Modul.class).getResultList getresultlist(); utx.commit(); finally { catch (Exception e) { if (em!= null) { try { em.close(); ms = new FacesMessage( e.getmessage()); utx.rollback(); ctxt.addmessage(null, ms); catch (Exception e2) { modul=new Modul(); ms = new FacesMessage( return HINZUFUEGEN; e2.getmessage()); 312
Verwaltung einer Modulliste (8/9) - Ergebnisseite 1/2 <h:form id="f2"> <h:messages globalonly="true"/> <h:panelgrid rendered="#{! ="#{!empty module.module"> <h:datatable value="#{ ="#{module.module module.module" var="m" border="8" frame="box" > <h:column > <f:facet name=" ="header header"> <h:outputtext value="nummer" /> f:facet f:facet> <h:outputlabel value="#{m.nr"/> h:column h:column> 313
Verwaltung einer Modulliste (9/9) - Ergebnisseite 2/2 <h:column h:column> <f:facet name=" ="header header"> <h:outputtext value="modulname" /> f:facet f:facet> <h:outputlabel value="#{m.name"/> h:column h:column> h:datatable h:datatable> h:panelgrid h:panelgrid> <h:commandlink action="#{ ="#{module.eingeben module.eingeben" > <h:outputtext value="zur Moduleingabe"/> h:commandlink h:commandlink> h:form h:form> 314
Projektaufbau 315
Einschub: Ausgabe von Sammlungen <h:datatable value="#{ ="#{module.module module.module" var="m"> datatableerlaubt die Datenaufbereitung einer Collectionin Tabellenform (Iteratorüber Daten mit getmodule(); Elemente in Variable m); grundlegende Darstellungsmöglichkeiten einstellbar Zur Ausgabe wird minimal <h:column h:column> benötigt Attribut firstfür erste Zeile und rows für Zeilenzahl 316
5.5 Kompakt: EJB-SessionBeans und CDI Architekturvariante bisher einfache direkte Software-Architektur (nutzbar für kleinere und mittlere Projekte) Problem: Skalierung nicht unbedingt sichergestellt, da Server nicht im Detail eingreifen kann (Ansatz: Mehrschichtarchitektur basierend auf EJB) Problem: direkte Nutzung von JPA sehr bastelig JEE-Problematik: JSF-Lösungen stark auf JSF-fokussiert, wie auf verwandte JEE-Techniken übertragen (Ansatz: Context and Dependency Injection, CDI) 317
EJB - Konzept Standardisierte Komponenten eines JEE-Servers Klassen zur Steuerung von Prozessen und Verwaltung von Daten, die leicht in anderen EJB-Applikationen nutzbar sind Unterstützt mit wenig Aufwand Transaktionssteuerung Sicherheitseinstellungen Identifikation von Objekten zur Zusammenarbeit Drei Arten (local und remote Varianten) Entity Bean (POJO,@Entity wie bereits bekannt) Session Bean: Kommunikation mit (End-)Anwendungen @Stateless: bei jeder Nutzung neu erstellt @Stateful: in einer Session nutzbar Message Driven Bean: asynchroner Nachrichtenablauf 318
EJB-Umsetzung (1/4) package ejb; import entities.modul; import java.util.list; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; @Stateless public class Modulverwaltung { @PersistenceContext PersistenceContext(unitName = "vljsfmodullistemitejbpu vljsfmodullistemitejbpu") private EntityManager em; public void persist(object object) { em.persist(object object); //Exception weiterreichen public List<Modul> getmodule() { return em.createquery("select m FROM Modul m", Modul.class).getResultList getresultlist(); 319
EJB-Umsetzung (2/4) Teil 1/2 package view; import ejb.modulverwaltung; import entities.modul; import java.io.serializable; import java.util.list; import javax.ejb.ejb; import javax.faces.bean.managedbean; import javax.faces.bean.requestscoped; @ManagedBean ManagedBean(name name = "module module") @RequestScoped public class ModulBean implements Serializable { private static final long serialversionuid = 1L; private Modul modul = new Modul(); @EJB private Modulverwaltung mv; public ModulBean() { 320
EJB-Umsetzung (3/4) Teil 2/2 public List<Modul> getmodule() { return mv.getmodule(); public String uebernehmen() { try { mv.persist(modul modul); // modul = new Modul() nicht notwendig catch (Exception e) { // wie vorher mit FacesContext return "./uebersicht.xhtml uebersicht.xhtml"; public String eingeben() { return "./index.xhtml index.xhtml"; public String anzeigen() { return "./uebersicht.xhtml uebersicht.xhtml"; // get und set für this.modul 321
EJB-Umsetzung (4/4) Klasse Modul bleibt unverändert XHTML-Seiten bleiben unverändert gleiches Verhalten, wie vorher wenn durchhangeln über this.modul nicht gewünscht: public class ModulBean implements Serializable { private static final long serialversionuid = 1L; private int nr; private String name; @EJB private Modulverwaltung mv; // Methoden anpassen, in index.html direkt module.nr 322
Projektstruktur 323
CDI JSF-Lösungen stark auf JSF-fokussiert, wie auf verwandte JEE-Techniken übertragen? JSR 299: Contexts and Dependency Injection for the Java TM EE platform (http://www.jcp.org/en/jsr/detail?id=299) Zugriff von JSF-Seiten auf Objekte über @Named-Annotation (statt @ManagedBean); auch außerhalb JSF nutzbar Wunsch flexible Nutzung von Objekten innerhalb des Servers -> Server kennt Klassen und stellt Objekte zur Verfügung Exemplarvariable/ als Parameter @Inject Modul m Benötigt beans.xml-datei (in META-INF), ist im einfachsten Fall leer Dokumentation: http://docs.jboss.org/weld/reference/1.1.0.final/en- US/pdf/weld-reference.pdf 324
Beispiel: Modulverwaltung aus mehreren Schichten Web-Design (XHTML-Seiten) [unverändert] ManagedBean (jetzt @Named) zur Verwaltung der Ein- und Ausgaben Session-Bean zur Verwaltung der Objekte; Kapselung der JPA-Schicht (Details für Entwickler verstecken) Datenobjekte (@Entity) [unverändert] 325
Umsetzung @Named Named(" ("moduldelegate moduldelegate") // flexibler als ManagedBean //(braucht beans.xml) @SessionScoped public class ModulDelegate implements Serializable { Generell weitere Annotation möglich, die z. B. Observer- Observable allein über Annotationen regeln ausnahmsweise gutes Video http://www.youtube.com/watch?v=zkpuoatsktc&list=uuk QX1tChV7Z7l1LFF4L9j_g&index=50&feature=plpp 326
5.6 Funktionale Erweiterung Interessante JSF-Elemente <f:facet name=" ="header header"> <h:outputtext value="nummer" /> f:facet f:facet> facet dient zur Ergänzung verschiedener anderer JSF- Elemente; Art der Ergänzung durch Attribut name festgelegt 327
Architekturvariante ab JSF 2.0 Grundidee: (fast) alle Objekte werden als ManagedBeans (mit unterschiedlichem Scope) aufgefasst ManagedBeanskönnen andere als Parameter in Methodenaufrufen (action-methoden) enthalten @ManagedBean ManagedBean(name = "a") @SessionScoped public class A {... private String mach(b b){ // kann b bearbeiten/nutzen nutzen return "String mit Pfad zur nächsten Seite";... @ManagedBean ManagedBean(name = "b") @RequestScoped public class B {... <h:commandlink value="bearbeitung Bearbeitung" action="#{a.mach a.mach(b)"/> 328
Kurze Diskussion der Architekturvarianten Klassischer Ansatz #{controller.bean.attribut controller.bean.attribut saubere Steuerungsklasse(n) Mehrfachpunktnotation sehr unüblich für Attribute neuer Ansatz ab JSF 2.0 <h:commandlink value="bearbeitung Bearbeitung" action="#{a.mach a.mach(b)"/> für Programmierer (!) intuitive Methodennutzung Objekt b nicht änderbar (sei anderes Objekt, geht nicht) CDI-Variante über Annotationen generelle Frage: wie steht es mit Objektorientierung 329
Funktionalität ergänzen (1/6) - Aufgabe Moduleinträge sollen editierbar werden Problem: Editieren-Link muss Modul erkennen Ansatz: Link erhält Parameter, der als Request- Parameter ausgelesen werden kann Hinweis: JSFfigerer Ansatz unter Nutzung des DataModels und von Data- Model-Events lösbar 330
Funktionalität ergänzen (2/6) - uebersicht.xhtml <h:datatable value="#{ ="#{module.module module.module" var="m" border="8" frame="box" >... <h:column h:column> <f:facet name=" ="header header"> <h:outputtext value="bearbeitung"/> f:facet f:facet> <h:commandlink action="#{ ="#{module.editieren module.editieren"> <h:outputtext value="editieren"/> <f:param name=" ="edit edit" value="#{m.id"/> h:commandlink h:commandlink> h:column h:column>... 331
Funktionalität ergänzen (3/6) - Persistierung @Stateless public class Modulverwaltung { @PersistenceContext PersistenceContext(unitName = "JSFModullisteAenderungPU JSFModullisteAenderungPU") private EntityManager em; public void persist(object object) { em.persist(object object); //Erinnerung Exceptions weitergegeben public void update(object object) { em.merge(object object); public Modul find(string id){ return em.find(modul.class Modul.class, Integer.parseInt(id id)); public List<Modul> getmodule() { return em.createquery("select m FROM Modul m", Modul.class).getResultList getresultlist(); 332
Funktionalität ergänzen (4/6) -Seite einbauen // in ModuleBean.java @SessionScoped // neu public class ModulBean implements Serializable { private String getrequestparameter(string par) { return FacesContext.getCurrentInstance().getExternalContext getexternalcontext().getrequestparametermap getrequestparametermap(). ().get get(par); //evtl. in Hilfsklasse auslagern public String editieren() { String mid = getrequestparameter(" ("edit edit"); modul = mv.find(mid mid); // Erinnerung @EJB Modulverwaltung return "./edit.xhtml edit.xhtml"; 333
Funktionalität ergänzen (5/6) - edit.xhtml <h:form h:form> <h:panelgrid columns="3"> <h:outputlabel value="interne ID "/> <h:outputlabel value="#{module.modul.id"/> <h:outputlabel value=" "/> <h:outputlabel for=" ="mname mname" value="modulname "/> <h:inputtext id=" ="mname mname" value="#{module.modul.name"/> <h:message for=" ="mname mname" /> <h:outputlabel for=" ="mnr mnr" value="modulnummer "/> <h:inputtext id=" ="mnr mnr" value="#{module.modul.nr"/> <h:message for=" ="mnr mnr"/> <h:commandbutton value="ändern" action="#{ ="#{module.aendern module.aendern"/> h:panelgrid h:panelgrid> <h:commandlink action="#{ ="#{module.anzeigen module.anzeigen" > <h:outputtext value="zur Modulübersicht"/> h:commandlink h:commandlink> h:form h:form> 334
Funktionalität ergänzen (6/6) - Ändern // in ModuleBean.java public String aendern() { try{ mv.update(modul modul); modul = new Modul(); catch (Exception e) { // TODO sinnvolle Fehlermeldung für JSF return "./uebersicht.xhtml uebersicht.xhtml"; // in uebernehmen() und eingeben() vor return ergänzen modul = new Modul(); 335
Beispielnutzung 1 2 3 4 5 6 336
Variante: JSF 2.0 ohne f:param <h:datatable value="#{module.module module.module" var="m" border="8" frame="box" >... <h:commandlink value="editieren Editieren" action="#{module.editieren module.editieren(m)"/> // in ModulBean.java public String editieren(modul m) { modul=m =m; return EDITIEREN; 337
5.7 Sicherheit Vier Aufgaben Authentifizierung: Nutzer erkennen; klassisch über Name und Passwort Autorisierung: Nutzer darf nur bestimmte Aktionen durchführen, klassisch über Rechte-Rollen-System Vertraulichkeit: kein weiterer Nutzer (außer BKA, CIA,...) darf Informationen mitlesen Unverfälschtheit: Inhalte werden zwischen Senden und Empfangen nicht verändert letzten beiden Punkte typischerweise durch Verschlüsselung realisiert 338
Nutzer Rollen Gruppen typischerweise wird ein Nutzer einer oder mehreren Gruppen (mit unterschiedlichen) Rechten zugeordnet zur Vereinfachung (Abstraktion) bekommt jeder Nutzer genau eine Rolle, die dann verschiedenen Gruppen zugeordnet werden kann jede benötigte Gruppenkombination benötigt eine Rolle Nutzer NC M Gruppe NC M 1 Rolle NC 339
Varianten zur Realisierung direkt von Hand codieren (mit DB-Anbindung für uns technisch kein Problem; Übertragung aber unsicher mit HTTP) jeder Methodenaufruf beginnt mit Berechtigungsprüfung deklarativ Möglichkeit zur abgetrennten Authentifizierung Seiten (Servlets, JSP, JSF) können als schützenswert markiert werden (im Deployment Descriptor) Zugang zu Seiten wird nur Nutzer in bestimmten Rollen gewährleistet deklarativ (Variante) Programmcode direkt mit erlaubten Rollen annotieren 340
Umsetzungsmöglichkeit in JSF Deployment Descriptor(web.xml) Man kann Rollen definieren Man kann Seiten/Ordner Rollen zuordnen Man kann Art der Übertragung festlegen und Applikationsserver-spezifisch: Auswahl eines Informationssystems zur Authentifizierung (Nutzer, Passwort, zugehörige Rollen), z. B. im Server selbst, Datenbank, Anbindung LDAP Zuordnung der Server-Gruppen zu den Rollen der JSF- Applikation (oder Zuordnung von Nutzern zu Rollen der JSF- Applikation) 341
Applikationsbeispiel -Überblick 1. Nutzer wählt Funktionalität 2. Nutzer muss sich authentifizieren 3. Prüfung ob Nutzer erlaubt und ob er benötigte Rechte hat 4a. falls ja, Zugang zur Funktionalität 4b. falls Nutzer unbekannt, ihn über Scheitern informieren 4c. falls Nutzer bekannt und zu wenig Rechte, ihn über fehlende Rechte informieren [oder wie 4b behandeln] Hinweis: statt geschützten Zugriff auf Startseite kann diese noch offen sein (ergonomisch, weitere Einstellungen regelbar) technische Probleme: Nutzer kann mehrere Seiten für gleiche Applikation nutzen Nutzer spielt mit Back -Button 342
Sicheres JSF (1/17) Aufgabenstellung / Nutzer Nur registrierte Basisnutzer können Modul hinzufügen Nur Editierer(Admins) dürfen Modul bearbeiten Server unterstützen verschiedene Sicherheitsmechanismen direkter Eintrag von Nutzern im Server Anbindung an LDAP Nutzung eigener Tabellen (wird hier genutzt, eigener Realm, eigene Tabellen zur Verwaltung, mit verschlüsselten Passwort, genauer: http://home.edvsz.hs-osnabrueck.de/skleuker/querschnittlich/netbeansnutzung.pdf) Nutzer username password Gruppen groupid usernme edna edna admin edna uwe uwe basic edna otto otto basic uwe 343
Sicheres JSF (2/17) Ergebnis 1/3 344
Sicheres JSF (3/17) Ergebnis 2/3 345
Sicheres JSF (4/17) Ergebnis 3/3 - Konzept Web-Seiten in Ordner pro Nutzergruppe einordnen In web.xml regeln, welche Gruppe worauf zugreifen darf Standard login-servlet einschalten und nutzen Ausnahmefälle regeln Ausloggen sicherstellen (Session deaktivieren) generell: inkrementelle 346
Sicheres JSF (5/17) - Projektstruktur serverspezifische Einstellungen Angabe von Rollen und Rechten zu schützende Informationen pro Gruppe auch Startseite geschützt Eingabe der Nutzererkennung bekannter Nutzer ohne Rechte nicht existenter Nutzer 347
Sicheres JSF (6/17) - serverindividuelle Vorbereitung Rechte-Rollen werden mit konkreten Nutzern in Datei glassfish-web.xml (vorher sun-web.xml) umgesetzt <security security-role role-mapping> <role-name> name>basisnutzer basisnutzerrole role-name> <group-name>basicgroup name>basicgroup-name> security-role role-mapping> <security-role role-mapping> <role-name> name>editierer editiererrole role-name> <group-name>admingroup name>admingroup-name> security-role role-mapping> Gruppenname aus Datenbank (Spalte) Auch Nutzer (username) direkt eintragbar 348
349 <welcome welcome welcome welcome-file file file file-list> list> list> list> <welcome welcome welcome welcome-file> file> file> file>faces faces faces faces/hinzufuegen hinzufuegen hinzufuegen hinzufuegen/index.xhtml index.xhtml index.xhtml index.xhtml welcome welcome welcome welcome-file> file> file> file> welcome welcome welcome welcome-file file file file-list> list> list> list> <security security security security-constraint constraint constraint constraint> <display <display <display <display-name>c1display name>c1display name>c1display name>c1display-name> name> name> name> <web <web <web <web-resource resource resource resource-collection collection collection collection> <web <web <web <web-resource resource resource resource-name>basisschutzweb name>basisschutzweb name>basisschutzweb name>basisschutzweb-resource resource resource resource-name> name> name> name> <description description description description/> /> /> /> <url url url url-pattern>/ pattern>/ pattern>/ pattern>/faces faces faces faces/hinzufuegen hinzufuegen hinzufuegen hinzufuegen/* /* /* /*url url url url-pattern> pattern> pattern> pattern> <http <http <http <http-method method method method>gethttp >GEThttp >GEThttp >GEThttp-method method method method> <http <http <http <http-method method method method>posthttp >POSThttp >POSThttp >POSThttp-method method method method> web web web web-resource resource resource resource-collection collection collection collection> <auth auth auth auth-constraint constraint constraint constraint> <description description description description/> /> /> /> <role role role role-name> name> name> name>basisnutzer basisnutzer basisnutzer basisnutzer role role role role-name> name> name> name> auth auth auth auth-constraint constraint constraint constraint> <user <user <user <user-data data data data-constraint constraint constraint constraint> <transport <transport <transport <transport-guarantee guarantee guarantee guarantee>confidentialtransport >CONFIDENTIALtransport >CONFIDENTIALtransport >CONFIDENTIALtransport-guarantee guarantee guarantee guarantee> user user user user-data data data data-constraint constraint constraint constraint> security security security security-constraint constraint constraint constraint> Sicheres JSF (7/17) - JSF-Konfiguration web.xml [1/3] Startseite im Unterordner Regel für alle Seiten des Ordners wer darf HTTPS einschalten