Innerhalb des MVC Entwurfsmusters nimmt ein Controller die Anfragen (Requests) entgegen und generiert die Antworten (Responses) bzw. leitet die Daten (Model) an die View weiter. Folgendes sollte man über Grails Controller wissen:
- Namenskonvention
- Erstellen von Controllern
- Erstellen von Aktionen (Actions)
- Abfragen von Parametern aus dem Request und der Session
- Nutzen des Flash Scopes
- Verarbeitung der Daten (Models)
- Generieren der Antwort (Response)
- Weiterleitung und Verkettung von Aktionen (Actions)
Erstellen von Controllern / Namenskonvention
Controller liegen bei Grails im grails-appcontroller
. Sie enden im Dateinamen immer auf Controller z.B. ManagedUserController.groovy . Der erste Teil des Namens ist Bestandteil der URI (z.B. managedUser) , über die die Actions angesprochen werden.
Controller können auch über den Befehl grails create-controller
erstellt werden.
Erstellen von Aktionen (Actions)
Actions (Aktionen) werden als Eigenschaften eines Controllers definiert und auf eine URI gemapped. So wird die Action list des Controllers für die ManagedUser über die URI managedUser/list
angesprochen
class ManagedUserController {
def list = {
if(!params.max)params.max = 10
[ managedUserList: ManagedUser.list( params ) ]
}
}
Wird nur der Controller in der URI angesprochen, so wird die „Default Action“ ausgeführt. Diese kann man über die Eigenschaft index festlegen.
def index = { redirect(action:list,params:params) }
Abfragen von Parametern aus dem Request und der Session
Jeder Controller verfügt über eine Anzahl vordefinierter Eigenschaften, die zur Laufzeit dynamisch mit Werten versorgt werden. Dazu gehören:
- actionUri
- controllerUri
- actionName
- controllerName
- flash
- grailsApplication
- grailsAttributes
- log
- params
- session
- request
- response
- servletContext
Will man nun auf die Parameter aus dem Request oder der Session zugreifen, so greift man auf die Eigenschaften params
oder session
zu:
def findBy = params["findBy"]
def loggedUser = session["logged_user"]
Nutzen des Flash Scopes
Mit dem Flashscope ist es möglich ein Attribut für die nächste Anfrage (Request), bereitzustellen. Genutzt wird diese Funktionalität um den Benutzer über den Status von Aktionen zu informieren, z.B. dass der Löschvorgang erfolgreich war.
flash.message = "ManagedUser ${params.id} deleted."
Verarbeitung der Daten (Models)
Die Parameter in Webanwendungen werden als Strings übergeben, daher ist es notwendig sie auf die Daten Objekte (Models) zu mappen. In Grails geschieht das sehr einfach über die Zuweisung der Parameter an die Eigenschaft properties
eines jeden Models.
managedUser.properties = params
Models sind in Grails als Maps implementiert. Die einfachste Art ein Model Object an die View weiterzuleiten, ist die Instanz zurückzugeben.
def managedUser = new ManagedUser()
managedUser.properties = params
return ['managedUser':managedUser]
Generieren der Antwort (Response)
Um eine spezielle View oder Code Teile aus dem Controller heraus zu rendern, wird von Grails die Funktion render
zur Verfügung gestellt.
render(view:'edit',model:[managedUser:managedUser])
Um eine spezielle View oder Code Teile aus dem Controller heraus zu rendern, wird von Grails die Funktion render
zur Verfügung gestellt.
Weiterleitung und Verkettung von Aktionen (Actions)
Die Weiterleitung auf eine andere Aktion erfolgt über die Funktion redirect
. Der Weiterleiung können dabei optional Parameter hinzugefügt werden. Auf Aktionen anderer Kontroller wird über einen String verwiesen.
// einfache Weiterleitung
redirect(action:list)
// Weiterleitung, mit Parametern
redirect(action:show,id:managedUser.id)
// Weiterleitung auf einen anderen Controller
redirect(action:"/address/list")
Aktionen können natürlich auch verkettet werden, dabei stehen die Model Objekte, die während der Verkettung hinzugefügt werden, auch anderen Aktionen der Kette zur Verfügung. Sinnvoll ist dies z.B. bei der Umsetzung von Wizzards.
class WizzardsController {
def firstStep = {
chain(action:secondStep,model:["step1":new Object()])
}
def secondStep = {
chain(action:thirdStep,model:["step2":new Object()])
};
def thirdStep= {
return ["step3":new Object()])
};
}
Update: die aktuelle Version des Beitrags habe ich zur besseren Pflegbarkeit als Teil eines kleinen Tutorials zu Grails ausgelagert und direkt in der rechten Seitenleiste verlinkt.
Hallo Gero,
diese Art von Übersicht fehlt mir als an Grails interessierterm (‚Vorstufe zu Einsteiger‘ 😉 auf der Grails-Seite. Wäre es nicht sinnvoll sie mal dort zu positionieren?
Darüber hinaus ist mir immer noch nicht klar welcher innneren Architektur Grails eigentlich folgt. Es sieht mir aus wie einfache JSPs, die halt im Gewand der GSP daherkommen. Aber wäre z.B. eine Zusammenarbeit mit JSF möglich (damit meine ich natürlich nicht ein redirect o.Ä. zwischen diesen beiden Konzepten)?
Hallo,
ich habe ein Problem damit Variablen vom beforeInterceptor zum afterInterceptor innerhalb eines Controllers zu übergeben.
Wie funktioniert das?
Kann mir da jemand weiterhelfen?
Leider nicht. Ich benutze weder den beforeInterceptor noch den afterInterceptor. Zur Absicherung verwende ich stattdessen den SecurityFilter.
Was möchtest Du denn mit dieser Kombination umsetzen. Vielleicht gibt es noch eine ander Möglichkeit.
Ich möchte im beforINterceptor eine Domain-Instanz in die Datenbank schreiben und diese dann im afterinterceptor updaten.. für Statistiken zu einem Request..
Wenn Du sie erfolgreich in die Datenbank geschrieben hast, kannst Du sie im afterInterceptor wieder aus der Datenbank lesen und dann natürlich auch updaten.
Für die Performance ist das natürlich nicht so prickelnd, aber sofern der Zugriff auf den Datensatz über einen Index erfolgt, sollte es nicht so tragisch sein.