Date post: | 14-Aug-2015 |
Category: |
Documents |
Upload: | bert-haessler |
View: | 70 times |
Download: | 0 times |
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
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. RauschenbachDeutscher 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>
requestresponse
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 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
ModelView
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
Ä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()
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