41. DNUG Konferenz · 11./12. November 2014 · Leipzig
www.dnug.de
Das Model-View-Controller - Pattern
Track Entwicklung 12.11.2014 13:30 – 14:15 Uhr
Bert Häßler
Leonso GmbH
www.leonso.de
bert.haessler@leonso.de
Slides und DemoDB für diesen Vortrag: www.leonso.de/dnug14
Über mich
 Bert Häßler, verheiratet, drei Kinder
 Diplom-Wirtschaftsinformatiker, Technische Universität Dresden
 1998 „Erstkontakt“ mit Notes
 Anwendungsentwicklung / Administration
 @Formula-Debugger (www.nappz.de/xfl)
 seit 2006 EntwicklerCamp, DNUG
 OO – Frameworks in Notes
 LotusScript (!!!) und Java/XPages
 2012 Gründung Leonso GmbH
18.11.2014 2www.leonso.de
Agenda
 Softwarequalität
 MVC – Was ist das?
 Model / DAO
 View
 Controller
 MVC in XPages
 Beispielimplementation
 Der Weg zum eigenen Framework
18.11.2014 3www.leonso.de
Softwarequalität – Worauf kommt es an?
18.11.2014 4www.leonso.de
Quelle: http://cdn-static.zdnet.com/i/story/61/03/001582/istock_000002369355xsmall.jpg
Softwarequalität – Worauf kommt es an?
18.11.2014 5www.leonso.de
Funktionalität
Effizienz Übertragbarkeit
Änderbarkeit
Zuverlässigkeit
Benutzbarkeit
Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität
Softwarequalität – Worauf kommt es an?
18.11.2014 6www.leonso.de
Funktionalität
Effizienz Übertragbarkeit
Änderbarkeit
Zuverlässigkeit
Benutzbarkeit
Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität
Softwarequalität – Worauf kommt es an?
18.11.2014 7www.leonso.de
Funktionalität
Effizienz
Änderbarkeit
Zuverlässigkeit
Benutzbarkeit
Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität
Übertragbarkeit
Softwarequalität – Worauf kommt es an?
18.11.2014 8www.leonso.de
E. Rauschenbach
Deutscher Karikaturpreis 2003
Softwarequalität – Worauf kommt es an?
 Probleme bei „gewachsenen“ Notes-Anwendungen:
 Code kann überall stehen
 z.B. Buttons, Events, Agenten, Bibliotheken
 Verschiedene Sprachen (Formel, LS, einfache Aktionen, JS)
 Redundanz
 Ansatz:
 Modularisierung
18.11.2014 9www.leonso.de
„Frontend“ „Backend“
Das MVC-Pattern
 Model
 View
 Controller
18.11.2014 10www.leonso.de
Quelle: http://www.casting-power.de/images/kindermodels.jpg
Das MVC-Pattern
 Model
 View
 Controller
18.11.2014 11www.leonso.de
Quelle: http://upload.wikimedia.org/wikipedia/en/6/6a/View_From_Rock_Cottage_to_Soldiers_Bay.jpg
Das MVC-Pattern
 Model
 View
 Controller
18.11.2014 12www.leonso.de
Quelle: http://writeups.org/img/fiche/2719a.jpg
Das MVC-Pattern
 Model
 Daten
 Geschäftslogik
 View
 Darstellung
 Benutzeraktion
 Controller
 Steuerung
18.11.2014 13www.leonso.de
ModelView
Controller
MVC-Pattern für „klassische“ XPage
18.11.2014 14www.leonso.de
ModelView
Controller
FacesServlet
NSF
XPage
<HTML>
…
</HTML>
request
response
18.11.2014 15www.leonso.de
Demo
Model-Komponente
 Class Animal
 Einstiegsklasse
 „Application“
 In diesen Klassen KEINE konkreten Datenbankzugriffe
implementieren!
18.11.2014 16www.leonso.de
Zoo
getAllAnimals()
getAnimalByID()
createAnimal()
…
Animal
Species
Name
Description
save()
Model-Komponente
 DAO (Data Access Object)
 Implementiert benötigte lesende/schreibende Datenzugriffsmethoden
 CRUD (Create, Read, Update, Delete)
18.11.2014 17www.leonso.de
Dao
saveAnimal(animal)
removeAnimal(animal)
getAllAnimals()
getAnimalByID()
…
Model-Komponente
18.11.2014 18www.leonso.de
Model
Zoo
Animal
DB
DAO
Model-Komponente
18.11.2014 19www.leonso.de
public class Zoo implements Serializable {
/* Ermitteln aller Tiere in der Datenbasis<br>
* Methode wird an aktuell verwendete DAO-Instanz delegiert<br>
* nach aussen ist Zoo eine Facade, die die DAO-Ebene verbirgt */
public List<Animal> getAllAnimals() throws Exception {
return getDao().getAllAnimals();
}
/* Suche nach einem Tier ueber dessen ID */
public Animal getAnimalById(String id) throws Exception {
return getDao().getAnimalById(id);
}
// DAO-Instanz uebernimmt das Lesen und Schreiben der Daten
private Dao dao = null;
public Dao getDao() throws Exception {
if (dao == null) dao = new Dao(this);
return dao;
}
/* erzeugt ein neues Animal-Objekt */
public Animal createAnimal() throws Exception {
Animal model = getInstanceOfAnimal();
model.generateNewId(); // Initiale Werte werden gleich hier gesetzt
return model;
}
/* Factory-Methode zum Erstellen einer Animal-Instanz<br>
* alle Stellen im gesamten Code, die eine Instanz von Animal brauchen,<br>
* sollten dies nicht ueber <code>Animal a = new Animal();</code><br>
* implementieren, Factory-Pattern erlaubt flexiblere Klassenbindung! */
public Animal getInstanceOfAnimal() {
return new Animal(this);
}
}
Model-Komponente
18.11.2014 20www.leonso.de
public class Animal implements Serializable {
private static final long serialVersionUID = 1L;
private final Zoo app; // die Application als "Mutter" aller Objekte
private String id = null;
private String species = null;
private String name = null;
private String description = null;
public Animal(Zoo app) {
this.app = app;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//weitere Getter/Setter
...
/**
* speichert das Objekt<br>
* standardmaessig delegieren wir diese Methode an DAO<br>
* Damit kann die Komplexitaet (Arbeitsteilung von Model und DAO) nach
* aussen verborgen werden.
*/
public void save() throws Exception {
app.getDao().saveAnimal(this);
}
}
Model-Komponente
18.11.2014 21www.leonso.de
public class Dao implements Serializable {
private final Zoo app;
public Dao(Zoo zoo) {
this.app = zoo;
}
/* Suche nach einem bestimmten Tier */
public Animal getAnimalById(String id) throws Exception {
View view = UtilsJsf.getCurrentDatabase().getView("Animals");
Document doc = null;
Animal model = null;
try {
doc = view.getDocumentByKey(id); // Dokument suchen
if (doc != null) {
model = app.getInstanceOfAnimal(); // leeres Objekt erzeugen
readModelValuesFromDoc(doc, model); // Daten übertragen
}
} finally {
recycleDominoObjects(doc, view); // Recycling nicht vergessen
}
return model;
}
private void readModelValuesFromDoc(Document doc, Animal model {
model.setId(doc.getItemValueString("ID"));
model.setName(doc.getItemValueString("Name"));
model.setSpecies(doc.getItemValueString("Species"));
model.setDescription(doc.getItemValueString("Description"));
}
}
View-Komponente
 XPage Animal.xsp
 Class AnimalPageBean
 Code für Buttons
 Databinding
18.11.2014 22www.leonso.de
AnimalPageBean
clickSave()
clickBack()
getAnimal()
View-Komponente
18.11.2014 23www.leonso.de
 XPage Animal.xsp
 XPage ohne natives Notes-Databinding!
 Binding über PageBean bzw. Model
<?xml version="1.0" encoding="UTF-8"?>
<xp:view>
<h2>Tier</h2>
Tierart <xp:inputText value="#{page.animal.species}" />
Name <xp:inputText value="#{page.animal.name}" />
Details <xp:inputTextarea value="#{page.animal.description}" />
<xp:button value="zurück">
<xp:eventHandler event="onclick">
<xp:this.action><![CDATA[#{javascript:page.clickBack()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button value="speichern">
<xp:eventHandler event="onclick">
<xp:this.action><![CDATA[#{javascript:page.clickSave()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
View-Komponente
18.11.2014 24www.leonso.de
public class AnimalPageBean implements Serializable {
private final Animal model; // akuell geöffnetes Objekt
public AnimalPageBean() throws Exception {
String id = UtilsJsf.getParameter("id");
// ManagedBean "app" holen
Zoo app =(Zoo) UtilsJsf.resolveVariable("app");
// Ueber die ID in der Datenbank suchen
model = app.getAnimalById(id);
}
// wird fuer Data-Binding benutzt, siehe xsp
public Animal getAnimal() {
return model;
}
// Code fuer Button "speichern"
public void clickSave() throws Exception {
// Validierung und Fehleranzeige muss noch implementiert werden
model.save();
redirectToOverview();
}
// Code fuer Button "zurueck"
public void clickBack() throws Exception {
redirectToOverview();
}
// zur Uebersichtsseite navigieren
private void redirectToOverview() throws IOException {
UtilsJsf.sendRedirect("Overview.xsp");
}
}
Diagramm Animal.xsp
18.11.2014 25www.leonso.de
Model
View
Animal.xsp
AnimalPageBean
Zoo
Animal
DB
DAO
View-Komponente
 XPage Overview.xsp
 Class OverviewPageBean
 Code für Buttons
 Anzeigefunktionen
18.11.2014 26www.leonso.de
OverviewPageBean
clickNew()
clickRemove(animal)
getUrl(animal)
getDisplayText(animal)
View-Komponente
 XPage Overview.xsp
18.11.2014 27www.leonso.de
<xp:view>
<h2>Das sind unsere Tiere</h2>
<xp:repeat
value="#{page.allAnimals}"
var="animal">
<xp:link
text="#{javascript:page.getDisplayText(animal)}"
value="#{javascript:page.getUrl(animal)}" />
<xp:button value=“löschen">
<xp:eventHandler event="onclick">
<xp:this.action><![CDATA[#{javascript:page.clickRemove(animal);}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:repeat>
<xp:button value="neu">
<xp:eventHandler event="onclick">
<xp:this.action><![CDATA[#{javascript:page.clickNew();}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
View-Komponente
18.11.2014 28www.leonso.de
public class OverviewPageBean implements Serializable {
/* liefert die Tiere in alphabetischer Reihenfolge */
public List<Animal> getAllAnimals() throws Exception {
List<Animal> all = (Zoo) UtilsJsf.resolveVariable("app").getAllAnimals();
// wir erwarten von der App nicht, dass sie uns die Daten schon sortiert hat
Collections.sort(all, new Comparator<Animal>() {
// wir sortieren hier nach Tierart + Name
public int compare(Animal a1, Animal a2) {
String sortValue1 = a1.getSpecies() + " " + a1.getName();
String sortValue2 = a2.getSpecies() + " " + a2.getName();
return sortValue1.compareTo(sortValue2);
}
});
return all;
}
/* liefert den Anzeigetext fuer ein Tier */
public String getDisplayText(Animal animal) {
return animal.getSpecies() + " " + animal.getName();
}
/* Code fuer den Button "Loeschen" auf der Seite */
public void clickRemove(Animal model) throws Exception {
// hier koennten ggfs. noch Sicherheitsabfragen kommen...
model.remove();
}
/* generiert die URL fuer ein bestimmtes Model */
public String getUrl(Animal model) {
return "Animal.xsp?id=" + model.getId();
}
}
View-Komponente
 XPage ohne natives Notes-Databinding!
 Binding über PageBean oder Model
 Code so weit wie möglich in PageBean halten
 Bessere Wiederverwendung (Vererbung)
 Performance
 Anzeige von Meldungen
 Validierungsfehler
 Laufzeitfehler
 Erfolgsmeldungen
18.11.2014 29www.leonso.de
Diagramm Overview.xsp
18.11.2014 30www.leonso.de
Model
View
Overview.xsp
OverviewPageBean
Zoo
Animal
DB
DAO
Controller-Komponente
 Realisiert JSF-Lifecycle
 PhaseListener
 Bean-Management
 faces-config.xml
 Scope-Bereitstellung
 Triggert Events
 beforePageLoad(), afterPageLoad(), …
 Class ZooPhaseListener
18.11.2014 31www.leonso.de
ZooPhaseListener
beforePhase()
Controller-Komponente
18.11.2014 32www.leonso.de
public class ZooPhaseListener implements PhaseListener {
private static final long serialVersionUID = 1L;
public PhaseId getPhaseId() {
// uns interessiert nur beforeRenderResponse
return PhaseId.RENDER_RESPONSE;
}
public void beforePhase(PhaseEvent phase) {
// zu jeder XPage gibt es eine passende PageBean,
// z.B. Animal.xsp - AnimalPageBean
String url = UtilsJsf.getXSPContext().getHistoryUrl(0);
// aus '/Animal.xsp' mach 'Animal'
String page = Utils.strLeft(Utils.strRight(url, "/"), ".");
// jetzt suchen wir die passende PageBean-Klasse...
String packageName = "de.leonso.dnug.view";
String className = page + "PageBean";
Class<?> cl = Class.forName(packageName + "." + className);
Object pageBean = cl.newInstance();
// ... und als ViewScope-Variable abgespeichert
Map<String, Object> viewScope = UtilsJsf.getViewScope();
viewScope.put("page", pageBean);
}
}
Controller-Komponente
18.11.2014 33www.leonso.de
<faces-config>
<managed-bean>
<managed-bean-name>app</managed-bean-name>
<managed-bean-class>
de.leonso.dnug.model.Zoo
</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
<lifecycle>
<phase-listener>
de.leonso.dnug.controller.ZooPhaseListener
</phase-listener>
</lifecycle>
</faces-config>
View
Diagramm Demo-Applikation
18.11.2014 34www.leonso.de
Model
Animal.xsp
AnimalPageBean
Zoo
Animal
DB
DAO
Controller
FacesServlet
faces-
config.xml
instantiiert
ZooPhaseListener
Overview.xsp
OverviewPageBean
Designelemente
18.11.2014 35www.leonso.de
Änderungsanforderung
 Nicht mehr auf NSF zugreifen, sondern auf andere Datenquelle
 z.B. XML-File:
 Was ist hier zu tun?
 Neue DAO-Klasse schreiben
18.11.2014 36www.leonso.de
Änderungsanforderung
18.11.2014 37www.leonso.de
<interface>
DaoI
saveAnimal(animal)
removeAnimal(animal)
getAllAnimals()
getAnimalByID()
DaoNotes
saveAnimal(animal)
removeAnimal(animal)
getAllAnimals()
getAnimalByID()
DaoXml
saveAnimal(animal)
removeAnimal(animal)
getAllAnimals()
getAnimalByID()
18.11.2014 38www.leonso.de
Demo
Was haben wir gesehen?
 Einfache XPage-Applikation mit MVC-Struktur
 Austauschbarkeit des Datenbasis
 Datenmigration durch Implementierung von DAO-Klassen
 Nutzung der Modelklassen in verschiedenen „Frontends“
18.11.2014 39www.leonso.de
Der Weg zum eigenen Framework
 Abstraktion
 Basisklassen für Model, DAO, PageBeans
 Validierung
 Tendenziell im Model
 Und/Oder im View
 Caching
 Steigerung der Performance !!!
 Scope-Festlegung (Application, Session, View)
 Verdrängungsstrategien
 Erkennung von „dirty“-Elementen
 Daten-Formatierung und Internationalisierung
 View, Model oder ganz anders
18.11.2014 40www.leonso.de
MVC – Was bringt uns das?
 Klare Codestrukturen
 Unabhängigkeit von zugrundeliegender Datenstruktur
 Nutzung in verschiedenen „Clients“
 Browser
 REST-Services
 Periodische Hintergrundagenten (auch das gibt es noch)
 JUnit-Tests
 Wechsel zu alternativen Web-Technologien denkbar
 JSF: Apache MyFaces
 Template Engines
 Keine Angst vor „Notes-ist-tot“ – Diskussion!
18.11.2014 41www.leonso.de
Quellen / Links
 Model View Controller
http://de.wikipedia.org/wiki/Model_View_Controller
 Frostillicus Framework
http://www.notesin9.com/2014/10/10/notesin9-158-intro-to-the-
frostillicus-framework
 MVC & XPages
http://www.slideshare.net/JohnDalsgaard/mvc-and-ibm-xpages-
from-dannotes-in-korsr-dk-28-november-2013
 JAVA in Xpages
http://www.notesin9.com/2013/12/17/notesin9-132-using-java-in-
xpages-part-1/
18.11.2014 42www.leonso.de
Quellen / Links
 Head First Design Patterns
by Eric Freeman, Elisabeth Freeman,
Bert Bates, Kathy Sierra
 ISBN: 0596007124
 Publisher: O'Reilly
 www.it-ebooks.info
18.11.2014 43www.leonso.de
Leonso GmbH
Softwareentwicklung auf Basis von Java, XPages und Notes/Domino
 Fokus auf Sparkassen und Genossenschaftsbanken
 Leonso-Framework mit Schnittstelle zum Sparkassenrechenzentrum
 Produkte
 www.observer4notes.de
Notes-Datenbanken automatisch analysieren (kostenlos)
 www.qrcode4notes.de
QR-Code Generator für Notes
 www.ereignis-manager.de
Ereignissystem der Finanz-Informatik effizient nutzen
 www.leonso-transaktionstool.de
Transaktionswerkzeug für Sparkassen
18.11.2014 44www.leonso.de

Mvc public

  • 1.
    41. DNUG Konferenz· 11./12. November 2014 · Leipzig www.dnug.de Das Model-View-Controller - Pattern Track Entwicklung 12.11.2014 13:30 – 14:15 Uhr Bert Häßler Leonso GmbH www.leonso.de bert.haessler@leonso.de Slides und DemoDB für diesen Vortrag: www.leonso.de/dnug14
  • 2.
    Über mich  BertHäßler, verheiratet, drei Kinder  Diplom-Wirtschaftsinformatiker, Technische Universität Dresden  1998 „Erstkontakt“ mit Notes  Anwendungsentwicklung / Administration  @Formula-Debugger (www.nappz.de/xfl)  seit 2006 EntwicklerCamp, DNUG  OO – Frameworks in Notes  LotusScript (!!!) und Java/XPages  2012 Gründung Leonso GmbH 18.11.2014 2www.leonso.de
  • 3.
    Agenda  Softwarequalität  MVC– Was ist das?  Model / DAO  View  Controller  MVC in XPages  Beispielimplementation  Der Weg zum eigenen Framework 18.11.2014 3www.leonso.de
  • 4.
    Softwarequalität – Woraufkommt es an? 18.11.2014 4www.leonso.de Quelle: http://cdn-static.zdnet.com/i/story/61/03/001582/istock_000002369355xsmall.jpg
  • 5.
    Softwarequalität – Woraufkommt es an? 18.11.2014 5www.leonso.de Funktionalität Effizienz Übertragbarkeit Änderbarkeit Zuverlässigkeit Benutzbarkeit Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität
  • 6.
    Softwarequalität – Woraufkommt es an? 18.11.2014 6www.leonso.de Funktionalität Effizienz Übertragbarkeit Änderbarkeit Zuverlässigkeit Benutzbarkeit Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität
  • 7.
    Softwarequalität – Woraufkommt es an? 18.11.2014 7www.leonso.de Funktionalität Effizienz Änderbarkeit Zuverlässigkeit Benutzbarkeit Siehe auch: http://de.wikipedia.org/wiki/Softwarequalität Übertragbarkeit
  • 8.
    Softwarequalität – Woraufkommt es an? 18.11.2014 8www.leonso.de E. Rauschenbach Deutscher Karikaturpreis 2003
  • 9.
    Softwarequalität – Woraufkommt es an?  Probleme bei „gewachsenen“ Notes-Anwendungen:  Code kann überall stehen  z.B. Buttons, Events, Agenten, Bibliotheken  Verschiedene Sprachen (Formel, LS, einfache Aktionen, JS)  Redundanz  Ansatz:  Modularisierung 18.11.2014 9www.leonso.de „Frontend“ „Backend“
  • 10.
    Das MVC-Pattern  Model View  Controller 18.11.2014 10www.leonso.de Quelle: http://www.casting-power.de/images/kindermodels.jpg
  • 11.
    Das MVC-Pattern  Model View  Controller 18.11.2014 11www.leonso.de Quelle: http://upload.wikimedia.org/wikipedia/en/6/6a/View_From_Rock_Cottage_to_Soldiers_Bay.jpg
  • 12.
    Das MVC-Pattern  Model View  Controller 18.11.2014 12www.leonso.de Quelle: http://writeups.org/img/fiche/2719a.jpg
  • 13.
    Das MVC-Pattern  Model Daten  Geschäftslogik  View  Darstellung  Benutzeraktion  Controller  Steuerung 18.11.2014 13www.leonso.de ModelView Controller
  • 14.
    MVC-Pattern für „klassische“XPage 18.11.2014 14www.leonso.de ModelView Controller FacesServlet NSF XPage <HTML> … </HTML> request response
  • 15.
  • 16.
    Model-Komponente  Class Animal Einstiegsklasse  „Application“  In diesen Klassen KEINE konkreten Datenbankzugriffe implementieren! 18.11.2014 16www.leonso.de Zoo getAllAnimals() getAnimalByID() createAnimal() … Animal Species Name Description save()
  • 17.
    Model-Komponente  DAO (DataAccess Object)  Implementiert benötigte lesende/schreibende Datenzugriffsmethoden  CRUD (Create, Read, Update, Delete) 18.11.2014 17www.leonso.de Dao saveAnimal(animal) removeAnimal(animal) getAllAnimals() getAnimalByID() …
  • 18.
  • 19.
    Model-Komponente 18.11.2014 19www.leonso.de public classZoo implements Serializable { /* Ermitteln aller Tiere in der Datenbasis<br> * Methode wird an aktuell verwendete DAO-Instanz delegiert<br> * nach aussen ist Zoo eine Facade, die die DAO-Ebene verbirgt */ public List<Animal> getAllAnimals() throws Exception { return getDao().getAllAnimals(); } /* Suche nach einem Tier ueber dessen ID */ public Animal getAnimalById(String id) throws Exception { return getDao().getAnimalById(id); } // DAO-Instanz uebernimmt das Lesen und Schreiben der Daten private Dao dao = null; public Dao getDao() throws Exception { if (dao == null) dao = new Dao(this); return dao; } /* erzeugt ein neues Animal-Objekt */ public Animal createAnimal() throws Exception { Animal model = getInstanceOfAnimal(); model.generateNewId(); // Initiale Werte werden gleich hier gesetzt return model; } /* Factory-Methode zum Erstellen einer Animal-Instanz<br> * alle Stellen im gesamten Code, die eine Instanz von Animal brauchen,<br> * sollten dies nicht ueber <code>Animal a = new Animal();</code><br> * implementieren, Factory-Pattern erlaubt flexiblere Klassenbindung! */ public Animal getInstanceOfAnimal() { return new Animal(this); } }
  • 20.
    Model-Komponente 18.11.2014 20www.leonso.de public classAnimal implements Serializable { private static final long serialVersionUID = 1L; private final Zoo app; // die Application als "Mutter" aller Objekte private String id = null; private String species = null; private String name = null; private String description = null; public Animal(Zoo app) { this.app = app; } public String getName() { return name; } public void setName(String name) { this.name = name; } //weitere Getter/Setter ... /** * speichert das Objekt<br> * standardmaessig delegieren wir diese Methode an DAO<br> * Damit kann die Komplexitaet (Arbeitsteilung von Model und DAO) nach * aussen verborgen werden. */ public void save() throws Exception { app.getDao().saveAnimal(this); } }
  • 21.
    Model-Komponente 18.11.2014 21www.leonso.de public classDao implements Serializable { private final Zoo app; public Dao(Zoo zoo) { this.app = zoo; } /* Suche nach einem bestimmten Tier */ public Animal getAnimalById(String id) throws Exception { View view = UtilsJsf.getCurrentDatabase().getView("Animals"); Document doc = null; Animal model = null; try { doc = view.getDocumentByKey(id); // Dokument suchen if (doc != null) { model = app.getInstanceOfAnimal(); // leeres Objekt erzeugen readModelValuesFromDoc(doc, model); // Daten übertragen } } finally { recycleDominoObjects(doc, view); // Recycling nicht vergessen } return model; } private void readModelValuesFromDoc(Document doc, Animal model { model.setId(doc.getItemValueString("ID")); model.setName(doc.getItemValueString("Name")); model.setSpecies(doc.getItemValueString("Species")); model.setDescription(doc.getItemValueString("Description")); } }
  • 22.
    View-Komponente  XPage Animal.xsp Class AnimalPageBean  Code für Buttons  Databinding 18.11.2014 22www.leonso.de AnimalPageBean clickSave() clickBack() getAnimal()
  • 23.
    View-Komponente 18.11.2014 23www.leonso.de  XPageAnimal.xsp  XPage ohne natives Notes-Databinding!  Binding über PageBean bzw. Model <?xml version="1.0" encoding="UTF-8"?> <xp:view> <h2>Tier</h2> Tierart <xp:inputText value="#{page.animal.species}" /> Name <xp:inputText value="#{page.animal.name}" /> Details <xp:inputTextarea value="#{page.animal.description}" /> <xp:button value="zurück"> <xp:eventHandler event="onclick"> <xp:this.action><![CDATA[#{javascript:page.clickBack()}]]></xp:this.action> </xp:eventHandler> </xp:button> <xp:button value="speichern"> <xp:eventHandler event="onclick"> <xp:this.action><![CDATA[#{javascript:page.clickSave()}]]></xp:this.action> </xp:eventHandler> </xp:button> </xp:view>
  • 24.
    View-Komponente 18.11.2014 24www.leonso.de public classAnimalPageBean implements Serializable { private final Animal model; // akuell geöffnetes Objekt public AnimalPageBean() throws Exception { String id = UtilsJsf.getParameter("id"); // ManagedBean "app" holen Zoo app =(Zoo) UtilsJsf.resolveVariable("app"); // Ueber die ID in der Datenbank suchen model = app.getAnimalById(id); } // wird fuer Data-Binding benutzt, siehe xsp public Animal getAnimal() { return model; } // Code fuer Button "speichern" public void clickSave() throws Exception { // Validierung und Fehleranzeige muss noch implementiert werden model.save(); redirectToOverview(); } // Code fuer Button "zurueck" public void clickBack() throws Exception { redirectToOverview(); } // zur Uebersichtsseite navigieren private void redirectToOverview() throws IOException { UtilsJsf.sendRedirect("Overview.xsp"); } }
  • 25.
  • 26.
    View-Komponente  XPage Overview.xsp Class OverviewPageBean  Code für Buttons  Anzeigefunktionen 18.11.2014 26www.leonso.de OverviewPageBean clickNew() clickRemove(animal) getUrl(animal) getDisplayText(animal)
  • 27.
    View-Komponente  XPage Overview.xsp 18.11.201427www.leonso.de <xp:view> <h2>Das sind unsere Tiere</h2> <xp:repeat value="#{page.allAnimals}" var="animal"> <xp:link text="#{javascript:page.getDisplayText(animal)}" value="#{javascript:page.getUrl(animal)}" /> <xp:button value=“löschen"> <xp:eventHandler event="onclick"> <xp:this.action><![CDATA[#{javascript:page.clickRemove(animal);}]]> </xp:this.action> </xp:eventHandler> </xp:button> </xp:repeat> <xp:button value="neu"> <xp:eventHandler event="onclick"> <xp:this.action><![CDATA[#{javascript:page.clickNew();}]]> </xp:this.action> </xp:eventHandler> </xp:button> </xp:view>
  • 28.
    View-Komponente 18.11.2014 28www.leonso.de public classOverviewPageBean implements Serializable { /* liefert die Tiere in alphabetischer Reihenfolge */ public List<Animal> getAllAnimals() throws Exception { List<Animal> all = (Zoo) UtilsJsf.resolveVariable("app").getAllAnimals(); // wir erwarten von der App nicht, dass sie uns die Daten schon sortiert hat Collections.sort(all, new Comparator<Animal>() { // wir sortieren hier nach Tierart + Name public int compare(Animal a1, Animal a2) { String sortValue1 = a1.getSpecies() + " " + a1.getName(); String sortValue2 = a2.getSpecies() + " " + a2.getName(); return sortValue1.compareTo(sortValue2); } }); return all; } /* liefert den Anzeigetext fuer ein Tier */ public String getDisplayText(Animal animal) { return animal.getSpecies() + " " + animal.getName(); } /* Code fuer den Button "Loeschen" auf der Seite */ public void clickRemove(Animal model) throws Exception { // hier koennten ggfs. noch Sicherheitsabfragen kommen... model.remove(); } /* generiert die URL fuer ein bestimmtes Model */ public String getUrl(Animal model) { return "Animal.xsp?id=" + model.getId(); } }
  • 29.
    View-Komponente  XPage ohnenatives Notes-Databinding!  Binding über PageBean oder Model  Code so weit wie möglich in PageBean halten  Bessere Wiederverwendung (Vererbung)  Performance  Anzeige von Meldungen  Validierungsfehler  Laufzeitfehler  Erfolgsmeldungen 18.11.2014 29www.leonso.de
  • 30.
  • 31.
    Controller-Komponente  Realisiert JSF-Lifecycle PhaseListener  Bean-Management  faces-config.xml  Scope-Bereitstellung  Triggert Events  beforePageLoad(), afterPageLoad(), …  Class ZooPhaseListener 18.11.2014 31www.leonso.de ZooPhaseListener beforePhase()
  • 32.
    Controller-Komponente 18.11.2014 32www.leonso.de public classZooPhaseListener implements PhaseListener { private static final long serialVersionUID = 1L; public PhaseId getPhaseId() { // uns interessiert nur beforeRenderResponse return PhaseId.RENDER_RESPONSE; } public void beforePhase(PhaseEvent phase) { // zu jeder XPage gibt es eine passende PageBean, // z.B. Animal.xsp - AnimalPageBean String url = UtilsJsf.getXSPContext().getHistoryUrl(0); // aus '/Animal.xsp' mach 'Animal' String page = Utils.strLeft(Utils.strRight(url, "/"), "."); // jetzt suchen wir die passende PageBean-Klasse... String packageName = "de.leonso.dnug.view"; String className = page + "PageBean"; Class<?> cl = Class.forName(packageName + "." + className); Object pageBean = cl.newInstance(); // ... und als ViewScope-Variable abgespeichert Map<String, Object> viewScope = UtilsJsf.getViewScope(); viewScope.put("page", pageBean); } }
  • 33.
  • 34.
  • 35.
  • 36.
    Änderungsanforderung  Nicht mehrauf NSF zugreifen, sondern auf andere Datenquelle  z.B. XML-File:  Was ist hier zu tun?  Neue DAO-Klasse schreiben 18.11.2014 36www.leonso.de
  • 37.
  • 38.
  • 39.
    Was haben wirgesehen?  Einfache XPage-Applikation mit MVC-Struktur  Austauschbarkeit des Datenbasis  Datenmigration durch Implementierung von DAO-Klassen  Nutzung der Modelklassen in verschiedenen „Frontends“ 18.11.2014 39www.leonso.de
  • 40.
    Der Weg zumeigenen Framework  Abstraktion  Basisklassen für Model, DAO, PageBeans  Validierung  Tendenziell im Model  Und/Oder im View  Caching  Steigerung der Performance !!!  Scope-Festlegung (Application, Session, View)  Verdrängungsstrategien  Erkennung von „dirty“-Elementen  Daten-Formatierung und Internationalisierung  View, Model oder ganz anders 18.11.2014 40www.leonso.de
  • 41.
    MVC – Wasbringt uns das?  Klare Codestrukturen  Unabhängigkeit von zugrundeliegender Datenstruktur  Nutzung in verschiedenen „Clients“  Browser  REST-Services  Periodische Hintergrundagenten (auch das gibt es noch)  JUnit-Tests  Wechsel zu alternativen Web-Technologien denkbar  JSF: Apache MyFaces  Template Engines  Keine Angst vor „Notes-ist-tot“ – Diskussion! 18.11.2014 41www.leonso.de
  • 42.
    Quellen / Links Model View Controller http://de.wikipedia.org/wiki/Model_View_Controller  Frostillicus Framework http://www.notesin9.com/2014/10/10/notesin9-158-intro-to-the- frostillicus-framework  MVC & XPages http://www.slideshare.net/JohnDalsgaard/mvc-and-ibm-xpages- from-dannotes-in-korsr-dk-28-november-2013  JAVA in Xpages http://www.notesin9.com/2013/12/17/notesin9-132-using-java-in- xpages-part-1/ 18.11.2014 42www.leonso.de
  • 43.
    Quellen / Links Head First Design Patterns by Eric Freeman, Elisabeth Freeman, Bert Bates, Kathy Sierra  ISBN: 0596007124  Publisher: O'Reilly  www.it-ebooks.info 18.11.2014 43www.leonso.de
  • 44.
    Leonso GmbH Softwareentwicklung aufBasis von Java, XPages und Notes/Domino  Fokus auf Sparkassen und Genossenschaftsbanken  Leonso-Framework mit Schnittstelle zum Sparkassenrechenzentrum  Produkte  www.observer4notes.de Notes-Datenbanken automatisch analysieren (kostenlos)  www.qrcode4notes.de QR-Code Generator für Notes  www.ereignis-manager.de Ereignissystem der Finanz-Informatik effizient nutzen  www.leonso-transaktionstool.de Transaktionswerkzeug für Sparkassen 18.11.2014 44www.leonso.de