© DrHitch/Shutterstock.com
Webentwicklung mit dem Play Framework

2 Fixtures, Bootstrap-Klassen, Styling


Nachdem wir uns im ersten Teil dieses shortcuts mit den Grundlagen einer Play-Applikation beschäftigt haben, geht es nun weiter mit Fixtures, Bootstrapping, Forms und deren Validierung und Security.

Eben haben wir uns mit der Struktur, Funktionsweise, Konfiguration, Routing und Templates vertraut gemacht. Darüber hinaus bietet Play aber noch eine Reihe weiterer interessanter Möglichkeiten, denen wir uns in diesem Kapitel zuwenden wollen. Unsere Webapplikation (To-do-Liste) implementieren wir weiter und werden am Ende dieses Teils eine zumindest teilweise gebrauchsfähige Anwendung haben. Vor Kurzem wurde die aktuelle Version 2.1 des Play-Frameworks veröffentlicht. Dies wollen wir zum Anlass nehmen und in diesem Teil auf einige Anpassungen für Play 2.1 hinweisen. Wir – die Autoren – versuchen möglichst aktuell zu bleiben. Wir haben aus diesem Grund auch ein wenig die Themen von Kapitel 2 und 3 variiert, was Sie uns bitte nachsehen mögen.

Fixtures

Sie erinnern sich sicher noch an die letzten Schritte. Wir haben unsere Modellklassen und entsprechende Testklassen geschrieben. Die eigentlichen Testdaten haben wir dann mittels Instanziierung unserer Modellklassen und deren Persistierung in unsere In-Memory-Datenbank eingefügt. Dies mag für einige wenige Testdaten noch annehmbar sein, für eine große Menge an Testdaten aber eher nicht. Ein weitaus eleganterer Weg ist die Verwendung von Fixtures in Play. Fixtures ermöglichen die Injektion von Daten in eine DB. In Play beschreiben wir diese Daten in YAML-Dateien. Aus diesen Daten werden dann Java-Objekte. Wichtig ist in diesem Zusammenhang der YAML-Operator „!!“. Dieser spezifiziert die Java-Klasse, die mit den Daten befüllt werden soll. Erstellen Sie im Verzeichnis conf eine YAML-Datei test-data.yml (Listing 2.1).

# Users

- &bob !!models.User
email: bob@example.com
firstName: Bob
lastName: Razowski
password: secret

- &jane !!models.User
email: jane@example.com
firstName: Jane
lastName: Krautrock
password: secret

# ToDos

- !!models.ToDo
description: Fix the documentation
done: false
assignedUser: *bob

- !!models.ToDo
description: Prepare the beta release
done: false
assignedUser: *bob

- !!models.ToDo
description: Buy some milk
done: true
dateOfDone: 2013-01-04
assignedUser: *bob

- !!models.ToDo
description: Roll to continuous deployment
done: true
dateOfDone: 2012-12-25
assignedUser: *jane

- !!models.ToDo
description: Deploy to cloud
done: false
assignedUser: *jane

Listing 2.1

Anschließend wollen wir diese Daten in unseren Tests verwenden. Bei der Gelegenheit erweitern wir unsere Modellklassen (User.java und ToDo.java) um eine Methode zum Ermitteln der Anzahl an Datensätzen (Listing 2.2). Anschließend passen wir die Testklasse UserTest.java für die Verwendung der YAML-Daten an (Listing 2.3).

package models;

import javax.persistence.Entity;
import javax.persistence.Id;

import play.db.ebean.Model;

@Entity
public class ...

public static int count() {
return find.findRowCount();
}
}

Listing 2.2

package models;

import static org.junit.Assert.*;
import static play.test.Helpers.*;

import java.util.List;

import org.junit.Before;
import org.junit.Test;

import play.libs.Yaml;

import com.avaje.ebean.Ebean;

public class UserTest {
@Before
public void setUp() {
start(fakeApplication(inMemoryDatabase()));

Ebean.save((List<Object>) Yaml.load("test-data.yml"));
}
...
@Test
public void canAuthenticateUserLoadedByYamlTest() {
assertEquals(2, User.count());

assertNotNull(User.authenticate("bob@example.com", "secret"));
assertNull(User.authenticate("invalid@exemple.de", "secret"));
assertNull(User.authenticate("bob@example.com", "wrong"));
}
}

Listing 2.3

Geladen werden die Testdaten durch den Aufruf Yaml.load(). Den Rückgabewert casten wir auf java.util.List und persistieren diese mittels Ebean.save(). Da die Testdaten im Allgemeinen von allen Testmethoden verwendet werden, laden wir diese in unserer setUp()-Methode. Der Test selbst ist analog zu den bestehenden Tests.

Bootstrapping

Der Mechanismus der Dateninjektion ist für die eigentliche Applikationsentwicklung aber ebenso hilfreich. Wenn wir unsere Applikation entwickeln wollen, sollten wir so schnell wie möglich „klicken“ können und mit sinnvollen Daten arbeiten. Wenn wir aber erst die Übersichtsseite unserer Daten umsetzen (auflisten), existiert die Seite zur Dateneingabe noch nicht. In diesem Fall ist es hilfreich, wenn es bereits Testdaten gibt. Das ist mit dem Laden von YAML-Daten zur Startzeit unserer Play-Applikation möglich. Dazu hängen wir uns in den Start-up-Prozess ein. In Play geschieht dies durch eine eigene Klasse, Global.java, im Root Package (app). Unsere Klasse muss die Klasse play.GlobalSettings.java erweitern und die Methode onStart() implementieren (Listing 2.4).

import java.util.List;

import models.User;
import play.Application;
import play.GlobalSettings;
import play.Logger;
import play.libs.Yaml;

import com.avaje.ebean.Ebean;

public class Global extends GlobalSettings {

@Override
public void onStart(Application app) {
// Check if the database is empty
// and we are running in development mode
if (app.isDev() && User.count() == 0) {
Logger.debug("Bootstrapping with default data");
Ebean.save((List) Yaml.load("initial-data.yml"));
}
}
}

Listing 2.4

Wir benötigen natürlich noch die referenzierte YAML-Datei initial-data.yml. Diese erstellen wir ebenfalls im conf-Verzeichnis. Sie können hier eine neue Datei erstellen oder die Datei test-data.yml kopieren. Wie Sie in Listing 2.4 gesehen haben, befüllen wir unsere Datenbank nur, wenn es noch keine Daten gibt. Außerdem bietet uns Play die Möglichkeit, die Umgebung zu ermitteln, in der wir unsere Applikation gestartet haben. Da wir in einer Produktionsumgebung (Kommando play start) normalerweise keine Daten auf diesem Weg in unserer Datenbank persistieren wollen, prüfen wir hier explizit auf unsere Entwicklungsumgebung (play run).

Unsere erste Seite

Nachdem wir unsere Applikation mit initialen Daten befüllt haben, wollen wir diese auf einer ersten einfachen Seite anzeigen. Wir erweitern dazu unsere Komponenten für die Anzeige unserer ToDos. In der routes haben wir unsere GET-Aufrufe an die Methode index() unseres Application-Controllers geleitet. Dieser rendert dann die Seiten für die Anzeige. Für die Anzeige unserer ToDos erweitern wir nun unsere index()-Methode. Diese übergibt als Parameter für das Rendering der index.scala.html-View (im views-Verzeichnis) die Liste der ToDos (Listing 2.5). Aktuell werden „festverdrahtet“ die ToDos des Users Bob angezeigt. Dies werden wir später anpassen, wenn wir Login und Authentifikation implementiert haben.

package controllers;

import models.ToDo;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;

public class Application extends Controller {

public static Result index() {
return ok(index.render(
ToDo.findTodosByUserEMail("bob@example.com")
));
}
}

Listing 2.5

Die index.scala.html passen wir an das Argument (L...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang