© DrHitch/Shutterstock.com
Webentwicklung mit dem Play Framework

3 Security, Validierung und Tests


Wir werden nun unsere Webapplikation vervollständigen und uns mit weiteren wichtigen Themen wie JavaScript-Routen, Styling oder Selenium-Tests beschäftigen. Das Betreiben einer Play-Applikation wird ein weiterer wichtiger Bestandteil sein.

In den ersten Abschnitten haben wir uns mit dem grundlegenden Aufbau einer Play-Applikation beschäftigt. In diesem Teil unserer Entdeckungstour werden wir unsere Applikation erweitern: Hinzufügen und Löschen von To-dos (unter Einsatz von Ajax und CoffeeScript), Testen mit Selenium und FluentLenium, Styling mit CSS/LESS und Übergabe in Produktion. Abschließen wollen wir mit einem kurzen Überblick über den Einsatz von Play im realen Leben und weitere Möglichkeiten mit Play selbst. Fangen wir mit dem Hinzufügen und Löschen von To-dos an.

Aktuell zeigt unsere Applikation lediglich die in der YAML-Datei definierten To-dos an. Wir wollen aber eigene To-dos anlegen und diese bei Bedarf auch als erledigt markieren können, sodass sie aus der Anzeige entfernt werden. Für diese Funktionalitäten erzeugen wir eine eigene Controller-Klasse ToDos.java. Diese besitzt zwei Methoden, eine zum Hinzufügen und eine zum Löschen von To-dos (Listing 3.1). Die delete-Methode erwartet als Parameter die ID des zu löschenden Datensatzes. Innerhalb dieser Methode behandeln wir nur die zum angemeldeten Nutzer gehörenden To-dos, sodass nur eigene To-dos gelöscht werden können. Auf die Methode werden wir aber weiter unten noch detaillierter eingehen. Unser ToDo-Model muss für die Löschen-Funktionalität noch um eine Methode erweitert werden, die ein To-do eines Benutzers ermittelt. Dazu muss die Model-Klasse ToDo.java erweitert werden (Listing 3.2).

Hinzufügen von To-dos

Wie Sie sicher schon entdeckt haben, ist diese Controller-Klasse generell vor Aufrufen durch unautorisierte Nutzer abgesichert: @Security.Authenticated(Secured.class). Die add-Methode fügt ein neues To-do für einen Nutzer hinzu, sofern dieser auf der Webseite eine entsprechende Beschreibung eingegeben hat. Neu ist das Binden der Felder unserer Form. Für diese haben wir kein korrespondierendes Model. Aus diesem Grund greifen wir auf die Felder der Form mit der Form.form().bindFormRequest()-Methode zu, welche eine play.data.DynamicForm zurückgibt. An dieser können wir die Feldwerte der Form mit get(<FELDNAME>) ermitteln. Das ist immer dann sinnvoll, wenn wir kein Model implementieren oder wenn die Form unterschiedliche Felder haben kann. So ermitteln wir die durch den Nutzer eingegebene To-do-Beschreibung. Eine leere Eingabe führt zu einem Fehler, den wir dann auf der Seite anzeigen. Im Fall einer Eingabe erzeugen wir für den angemeldeten Nutzer ein neues To-do und machen einen Redirect auf die index()-Methode unseres Application-Controllers. Damit wird unser neues To-do in der Liste angezeigt.

package controllers;

import models.ToDo;
import models.User;

import org.apache.commons.lang3.StringUtils;

import play.data.Form;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Security;

@Security.Authenticated(Secured.class)
public class ToDos extends Controller {

public static Result add() {
String description = Form.form().bindFromRequest().get("description");
if (StringUtils.isEmpty(description)) {
flash("error", "Please enter a description");
} else {
ToDo toDo = new ToDo();
toDo.description = description;
toDo.assignedUser = User.find.byId(request().username());
toDo.save();
}
return redirect(routes.Application.index());
}

public static Result delete(Long id) {
String email = request().username();
ToDo toDo = ToDo.findTodoByIdAndUserEmail(id, email);
if (toDo != null) {
toDo.delete();
}
return ok();
}
}

Listing 3.1

...
public static ToDo findTodoByIdAndUserEmail(Long id, String email) {
return find.where()
.eq("id", id)
.eq("assignedUser.email", email)
.findUnique();
}
...

Listing 3.2

Damit die neuen Methoden aufgerufen werden können, müssen wir sie noch in unserer routes definieren. Fügen Sie in dieser Datei die zwei Routen hinzu (Listing 3.3).

...
# Tasks
POST /tasks controllers.ToDos.add
DELETE /tasks/:id/delete controllers.ToDos.delete(id: Long)
...

Listing 3.3

Jetzt wollen wir unsere neuen Funktionalitäten natürlich verwenden. Dazu erweitern Sie die index.scala.html zunächst um die Funktionalität zum Hinzufügen eines To-dos. Erweitern Sie dazu die View (Listing 3.4). Wenn Sie unsere Applikation nun starten, sollten Sie neue To-dos eingeben können.

...
</ul>

<div class="separator"></div>

@helper.form(routes.ToDos.add) {
<h2>Add TODO</h2>

@if(flash.contains("error")) {
<p class="error">
@flash.get("error")
</p>
}

<p>
<input type="text" name="description" placeholder="description">
</p>
<p>
<button type="submit">Add TODO</button>
</p>
}

Listing 3.4

Der eingebaute h2-Browser

Es ist durchaus sinnvoll die Daten in unserer Datenbank auch außerhalb unserer Anwendung anzeigen zu können. Play bringt einen h2-Browser mit, mit dem wir die aktuell in der In-Memory-Datenbank vorhandenen Daten ansehen und verändern können. Dazu führen Sie vor dem Start der Play-Applikation (mit run) in der Play-Konsole h2-browser aus. Im Webbrowser öffnet sich ein Anmeldebildschirm, in dem Sie die Konfiguration analog zu der DB-Konfiguration in der application.conf eingeben (Abb. 3.1). Wenn Sie nun unsere To-do-Applikation starten und im Browser aufrufen, können Sie anschließend im h2-Browser unsere DB-Daten anzeigen und bearbeiten (Abb. 3.2).

schildmann_abb1.png

Abbildung 3.1: Anmeldebildschirm h2-Browser

schildmann_abb2.png

Abbildung 3.2: Anzeige der Daten in der In-Memory-DB

Löschen von To-dos

Natürlich müssen wir To-dos auch als erledigt markieren können. Sie werden in unserem Fall durch das Markieren gelöscht. Die bereits implementierte (ToDo.java)- und konfigurierte (routes)-Funktionalität zum Löschen wollen wir als...

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