Play Framework, MySQL, JPA, HQL, HTML, jQuery, …

Werbung
Play Framework, MySQL, JPA, HQL, HTML, jQuery, …
Wer
Mit wem
Resultat
1. Kunde
Schalter: Bibliothekarin
Bestimmt, welcher Archivar
die Zeitschrift holen geht
2. Schalter: Bibliothekarin
Archivar
Kontrollübergabe
2.1 Archivar
Zeitschriften Archiv
Gewünschte Zeitschrift
2.2 Archivar
Kopiergerät
Kopien der gewünschten
Seiten an Bibliothekarin
übergeben
3 Schalter: Bibliothekarin
Kunde
Übergabe der kopierten
Seiten an Kunde
Wer
Mit wem
Resultat
1. Kunde
Schalter: Bibliothekarin
Bestimmt, welcher Archivar
die Zeitschrift holen geht
2. Schalter: Bibliothekarin
Archivar
Kontrollübergabe
2.1 Archivar
Zeitschriften Archiv
Gewünschte Zeitschrift
2.2 Archivar
Kopiergerät
Kopien der gewünschten
Seiten an Bibliothekarin
übergeben
3 Schalter: Bibliothekarin
Kunde
Übergabe der kopierten
Seiten an Kunde
Wir müssen für unsere Webapplikation programmieren:
1 – «Archivar», der die Kontrolle inne hat
2 – «Archiv», die Anbindung an die Datenbank
3 – «Kopiergerät», das sich um Darstellung kümmert
«Controller»
Archivar
1
3
2
4
«Model»
Zeitschriften Archiv
«View»
Kopiergerät
Client
Der Browser
Firefox
Chrome
Safari
Internet
Explorer…
URL
http://localhost:9000/?f=Redford
Internet
Die darzustellende Webseite
HTML
Server
Apache
Tomcat
Play
Microsoft IIS
…
Browser:
http://localhost:9000/
?f=Redford
Datei conf/routes
#
GET
GET
GET
URL
/
/actors
/actor
Methode, die ausgeführt werden soll
controllers.Application.actors(f ?= "")
controllers.Application.actors(f ?= "")
controllers.Application.actor(id:Long)
GET
GET
/movies controllers.Application.movies(f ?= "")
/movie controllers.Application.movie(id:Long)
Mit dieser Datei teilen wir dem Play Controller mit, wer
die Anfrage einer URL beantworten soll.
Play Server:
Aufruf von
Application.
actors("Redford")
Klasse controllers.Application
@Transactional(readOnly = true)
public static Result actors(String name) {
List<Actor> actors = Actor.findActorsByName(name); // 1
return ok(views.html.actors.render(actors)); // 2
}
Mit dieser Methode definieren wir, wie die Anfrage
beantwortet werden soll. Eine Controller-Methode geht
typischerweise zweistufig vor.
1.
2.
Wir suchen die angeforderten Daten («Archiv»).
Wir stellen die gefundenen Daten dar («Kopiergerät»).
Application.actors:
Aufruf von
Actor.findActors
ByName("Redford")
Klasse models.Actor
Diese Klasse hat zwei Aufgaben.
1. Sie beschreibt die Tabelle «actors» in der MySQLDatenbank.
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
@Id public Long actorid; // d.h. actorid ist Primärschlüssel
public String name;
public String sex;
// …
}
Meta-Informationen im Java-Code
Die sog. Annotationen wie @Entity beinhalten
Informationen, die den Code beschreiben.
Das Java Persistence API (JPA) ordnet Java-Klassen
Tabellen in relationalen Datenbanken zu:
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
@Id public Long actorid; // d.h. actorid ist Primärschlüssel
public String name; // d.h. es gibt eine Spalte name in DB
public String sex; // d.h. es gibt eine Spalte sex in DB
// …
}
Siehe auch de.wikipedia.org/wiki/Java_Persistence_API
Aufruf von
Actor.findActors
ByName("Redford")
Klasse models.Actor
Diese Klasse hat zwei Aufgaben.
2. Sie hat Methoden, um Daten zu suchen:
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
findActorsByName: Schritt für Schritt
findActorsByName
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Wir definieren Methode, die einen String als Input erhält und eine Liste
von Actor-Objekten zurückliefert.
findActorsByName: Schritt für Schritt
findActorsByName
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Falls der Input “name” vorhanden und nicht-leer ist:
findActorsByName Schritt für Schritt
findActorsByName:
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Wir definieren Abfrage. Da wir die JPA-Umsetzung Hibernate
verwenden, müssen wir die Hibernate Queery Language (HQL)
verwenden.
verwenden Siehe de.wikipedia.org/wiki/Hibernate_(Framework).
findActorsByName Schritt für Schritt
findActorsByName:
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Wir bereiten die Hibernate-Anfrage vor. Wir geben mit Actor.class an,
dass wir als Resultat der Anfrage eine Liste von Actor-Objekten
erwarten.
findActorsByName Schritt für Schritt
findActorsByName:
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Wir legen fest, dass Hibernate den Platzhalten «:name» durch den Wert
ersetzen soll, der durch den Ausdruck "%" + name + "%" entsteht (in
unserem Beispiel “%Redford%”.
findActorsByName: Schritt für Schritt
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Wir lassen Hibernate die Query ausführen. Unsere Methode liefert die
Resultat-Liste von Actor-Objekten zurück, die uns Hibernate gibt.
findActorsByName: Schritt für Schritt
@Entity(name = "actors") // der Name der Tabelle
public class Actor implements Serializable {
public static List<Actor> findActorsByName(String name) {
if (name != null && !name.equals("")) {
// Achtung, Abfrage ist HQL, nicht SQL!
String hql = "SELECT a FROM actors a WHERE name LIKE :name";
TypedQuery<Actor> query = JPA.em().createQuery(hql, Actor.class);
query = query.setParameter("name", "%" + name + "%");
return query.getResultList();
}
return new ArrayList<Actor>();
}
}
Falls der Input “name” nicht vorhanden oder leer ist:
Liefere leere Liste von Actor-Objekten zurück.
Application.actors:
Aufruf von
views.html.actor.
render(actors)
Template views/movie.scala.html
Das Template gibt an, wie die Daten dargestellt werden.
Teil 1: Definition der View; Formular
@(actors: List[Actor])
@main(title = "IMDB-Webapplikation: Suche nach Schauspielern") {
<h2>Schauspieler suchen</h2>
<form>
<input type="text" name="f"
value="@request.queryString.getOrElse("f", Array()).mkString">
</form>
movie.scala.html Schritt für Schritt
@(actors: List[Actor])
@main(title = "IMDB-Webapplikation: Suche nach Schauspielern") {
<h2>Schauspieler suchen</h2>
<form>
<input type="text" name="f"
value="@request.queryString.getOrElse("f", Array()).mkString">
</form>
Hinter dem @-Zeichen kommt jeweils ein Scala-Ausdruck.
In dieser Zeile definieren wir, dass diese View als Input die Variable
«actors» erhält, die eine Liste von Actor-Objekten ist.
Scala
movie.scala.html Schritt für Schritt
@(actors: List[Actor])
@main(title = "IMDB-Webapplikation: Suche nach Schauspielern") {
<h2>Schauspieler suchen</h2>
<form>
<input type="text" name="f"
value="@request.queryString.getOrElse("f", Array()).mkString">
</form>
Hier rufen wir das Template main.scala.html auf. Das Template stellt das
Gerüst einer Seite dar (Header, Menü, Footer). Wir übergeben diesem
Template als Inhalt der Seite alles, was zwischen den geschweiften
Klammern steht.
movie.scala.html Schritt für Schritt
@(actors: List[Actor])
@main(title = "IMDB-Webapplikation: Suche nach Schauspielern") {
<h2>Schauspieler suchen</h2>
<form>
<input type="text" name="f"
value="@request.queryString.getOrElse("f", Array()).mkString">
</form>
Hier definieren wir das Eingabe-Formular. «input» ist ein Eingabefeld
vom Typ «text» und hat den Namen «f». Dieser Name ist wichtig: Der
muss gleich sein wie in der Konfigurations-Datei routes.
Template views/movie.scala.html
Teil 2: Darstellung der Daten
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
}
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Falls die Liste von Actor-Objekten nicht leer ist (der Benutzer also eine
erfolgreiche Suche durchgeführt hat):
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Dann zeige eine Tabelle an. Erste Zeile enthält die Spaltentitel.
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Fülle die Tabelle mit weiteren Zeilen: Erstelle eine Tabellenzeile für jedes
Actor-Objekt in der Liste der “actors”.
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Zeige einen Link auf die Detailansicht von Schauspielern an. Wir können
den Link von Play abfragen über routes.Application.actor – genauso, wie
es in der Konfigurationsdatei routes definiert ist.
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Beschrifte den Link mit dem Namen des Schauspielers. Hier können wir
einfach alle Felder der Klasse “Actor” für die Anzeige verwenden.
movie.scala.html Schritt für Schritt
@if(!actors.isEmpty()) {
<table>
<tr><th>Name</th><th>Geschlecht</th></tr>
@for(actor <- actors) {
<tr>
<td><a href="@routes.Application.actor(actor.actorid)">
@actor.name</a></td>
<td>@actor.sex</td>
</tr>
}
</table>
}
Zeige in der nächsten Spalte das Geschlecht des Schauspielers / der
Schauspielerin an. Hier können wir einfach alle Felder der Klasse “Actor”
für die Anzeige verwenden.
Wer
Mit wem
Resultat
1. Browser: localhost:9000
Play Server: Controller
Action bestimmen, die für
Anfrage zuständig ist
2. Play Server: Controller mit
Konfiguration in routes
Unsere Controller-Action:
Application.actors
Kontrollübergabe
2.1 Unsere Controller-Action:
Application.actors
Unsere Model-Klasse:
Actor.findActorsByName
Liste von Actor-Objekten,
zwischengespeichert in
Variable actors
2.2 Controller: Unsere Action:
Application.actors
Unser View-Template: views.
html.actors.render(actors)
Aufbereitete HTML-Seite mit
Eingabeformular für Suche,
mit Liste von Schauspielern,
übergeben an Play Controller
3 Play Server: Controller
Browser
Übermittlung und Anzeige der
aufbereiteten HTML-Seite
«Controller»
Application.actors
«Model»
Klasse Actor
1
3
2
4
«View»
views/movie.scala.html
Das Play Framework basiert (wie
viele andere Frameworks für WebApplikationen) auf dem Design
Pattern «Model, View,
Controller» bzw. auf dem
verwandten Design Pattern «Front
Controller».
Siehe auch de.wikipedia.org/
wiki/Model_View_Controller
Herunterladen