Mvc public

44
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 [email protected] Slides und DemoDB für diesen Vortrag: www.leonso.de/dnug14

Transcript of Mvc public

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

[email protected]

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

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

ZooAnimal

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

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

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