3 Stimmen

Grails: Weiteren Code-Ablauf nach einem Redirect oder Forward in der Basisklasse eines Controllers verhindern

Ich habe folgende Controller-Struktur:

abstrakte Klasse AbstractController {
  // ...
}

abstrakte Klasse AbstractDiagramController erweitert AbstractController {
  // ...
}

Klasse PopulationController erweitert AbstractDiagramController {
  // ...
}

Die meisten Controller-Aktionen rufen verschiedene Methoden der abstrakten Basisklassen auf. Wenn nun eine dieser Basismethoden einen Redirect (oder Forward) an den Client senden muss, verhindert Grails nicht, dass die Anwendung den restlichen Aktionscode der Controller-Aktion trotzdem verarbeitet.

Von meinem Standpunkt aus ist dies ein unerwünschtes Verhalten, da die Basismethoden eine Art Validierung durchführen (wie die Validierung von Parametern, Benutzern, Sitzungen usw.) und der Controller davon ausgeht, dass die Validierung erfolgreich war (und daher nachfolgende Fehler produziert).

Wie kann ich dieses unzureichende Verhalten verhindern?

Mit freundlichen Grüßen, Christopher

PS: Ich habe bereits diese Frage gefunden, aber die Antworten haben mich nicht zufriedengestellt, da sich keine davon mit einem Basiskontroller befassen:

PPS: Ich benutze Grails in der Version 1.3.7

EDIT

Dies ist eine Reaktion auf die Kommentare von Victor Sergienko. Hier gebe ich ein detaillierteres Codebeispiel meines Problems.

// Der Basiskontroller
abstrakte Klasse AbstractController {

    // Der Interceptor wird aufgerufen, bevor eine Aktion der Ableiter verarbeitet wird
    def beforeInterceptor = [action:this.&initialize]

    // Methode validiert verschiedene Dinge
    protected initialize() {
        if( someThingIsWrong() ) {
            // Dieser Redirect sollte jeden anderen Code der Ableiter stoppen
            redirect( controller: "foo", action: "bar" )
            return false
        }
    } 
}

// Der zweite Basiskontroller
abstrakte Klasse AbstractDiagramController erweitert AbstractController {

    // Dieses Objekt muss initialisiert werden. Wenn nicht (z. B. bei Fehlern oder Ausnahmen)
    // dürfen alle Aktionen der Ableiter nichts tun
    MyObject myGreatObject = null

    // Überschrieben wegen zusätzlicher individueller Diagrammvalidierung
    @Override
    protected initialize() {
        // Zuerst Elternstuff machen
        super.auth()

        // Wenn Eltern fehlgeschlagen sind, sollte dieser Code nicht mehr ausgeführt werden.
        // Ja, hier könnte ich überprüfen, ob Eltern false zurückgegeben haben und ebenfalls false zurückgeben, bevor
        // ich die nächste Validierung fortsetze. So oder so muss ich das tun, weil Grails verständlicherweise
        // eine Ausnahme wirft, wenn zwei Redirects hintereinander ausgeführt werden.
        // (Damit möchte ich nur das Verhalten verdeutlichen, das ich erwarten würde)
        if( someThingElseIsWrong() ) { 
            redirect( controller: "hello", action: "world")
            return false
        }

        // Nach der Validierung kann ich das Objekt initialisieren
        myGreatObject = new MyObject()
    }
}

// Eine Controllerimplementierung
Klasse MyDiagramController erweitert AbstractDiagramController {

    // Überschrieben wegen individueller Validierung
    @Override 
    protected initialize() {

        // Zuerst Elternstuff machen
        boolean succeeded = super.auth()

        // Wieder ärgerliche Doppelüberprüfung
        if( !succeeded ) {
            return false
        }
    }

    def myAction = { 
        myGreatObject.SpinAroundAndBeHappy()
    } 
}

Sieht so aus, als ob es eine gute Idee war, den Anwendungsfall auf das Minimum an Codezeilen zu reduzieren. Jetzt scheint es, als könnten die Vorschläge von Victor (entweder canContinue oder hasErrors) dieses unangenehme Umstände irgendwie lösen, auch wenn es eine Art Workaround ist.

Aber irgendwie mag ich diese doppelten Überprüfungen nicht. Ich kämpfe immer noch gegen die Tatsache, dass alle Schichten über dem abstrakten Basiskontroller auf ungültige Validierungen reagieren müssen, die bereits zuvor aufgetreten sind (und auch von den Basiskontrollern selbst verwaltet werden sollten). Aus meiner Sicht sollten diese Überprüfungen nicht in den Implementierungen des Controllers liegen.

PS: Ich hoffe, es sind keine schwerwiegenden Fehler im Code aufgetreten.

4voto

Victor Sergienko Punkte 12396

Als Workaround können Sie ein boolean canContinue von einer übergeordneten Aktion zurückgeben oder eine Ausnahme auslösen oder instance.hasErrors() in Ihrem Fall überprüfen.

BEARBEITEN: Die Tatsache, dass initialize() vor einer Aktion aufgerufen wird, sieht nach Zugriffskontrolle oder einem anderen kompletten Override der Aktionssyntax aus (bevor irgendein Teil der Aktion ausgeführt wird). Bitte sagen Sie mir, wenn meine Annahme falsch ist.

Als wir einen benutzerdefinierten Sicherheitszugriff auf verschiedene Aktionen durchgeführt haben, haben wir die Aktionen mit eigenen Tags wie @SecuredDoodah (siehe @Secured) versehen und einen Filter hinzugefügt, der die Aktion vollständig überschreibt (bei uns antwortet der Filter mit 403, aber das ist nicht notwendig).

Filter könnte besser sein als beforeInterceptor. Wenn Sie einen Zustand von Filter übergeben müssen, wie das myGreatObject im Beispiel, können Sie einen Service in Filter injizieren und den Zustand im Service speichern.

Es gibt sicherlich bessere Wege als meine Idee, aber dies sollte transparent für Controller funktionieren.

2voto

Burt Beckwith Punkte 74817

Sie sind eingeschränkt durch die Tatsache, dass es sich um Java/Groovy handelt und es keinen Weg gibt, dass ein Methodenaufruf sofort einen Ausstieg aus einer Methode (oder Closure) auslöst. Ich habe gesehen, dass ein anderes Framework betrügt und wenn Sie rendern, umleiten usw. aufrufen, wird eine Ausnahme ausgelöst, die in der Framework-Basisklasse abgefangen wird. Dies wirkt wie ein Goto, das eigentlich nicht existiert.

Es ist jedoch ein teurer Ansatz - das Ausfüllen all dieser Stapelrahmen ist verschwenderisch, da es kein Ausnahmefall ist und der Stapel immer ignoriert wird.

Leider benötigen Sie einen Ansatz wie Victors, bei dem Sie boolesche Rückgabewerte verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X