Erstellen Sie eine MVC-Webanwendung mit Grails

Erstellen Sie eine MVC-Webanwendung mit Grails

 

1. Überblick

In diesem Tutorial erfahren Sie, wie Sie mitGrails eine einfache Webanwendung erstellen.

Grails (genauer gesagt die neueste Hauptversion) ist ein Framework, das auf dem Spring Boot-Projekt aufbaut und die Apache Groovy-Sprache zum Entwickeln von Web-Apps verwendet.

Es ist vom Rails Framework für Ruby undis built around the convention-over-configuration philosophy which allows reducing boilerplate code inspiriert.

2. Konfiguration

Gehen wir zunächst zur offiziellen Seite, um die Umgebung vorzubereiten. Zum Zeitpunkt dieses Tutorials ist die neueste Version 3.3.3.

Einfach ausgedrückt gibt es zwei Möglichkeiten, Grails zu installieren: über SDKMAN oder durch Herunterladen der Distribution und Hinzufügen von Binärdateien zur Umgebungsvariablen PATH.

Wir werden das Setup nicht Schritt für Schritt behandeln, da es inGrails Docs gut dokumentiert ist.

3. Anatomie eines Grals App

In diesem Abschnitt erhalten Sie ein besseres Verständnis der Grails-Anwendungsstruktur. Wie bereits erwähnt, zieht Grails die Konvention der Konfiguration vor, daher definiert der Speicherort der Dateien deren Zweck. Mal sehen, was wir im Verzeichnisgrails-apphaben:

  • assets - ein Ort, an dem statische Assets-Dateien wie Stile, Javascript-Dateien oder Bilder gespeichert werden

  • conf - enthält Projektkonfigurationsdateien:

    • application.yml enthält Standardeinstellungen für Web-Apps wie Datenquelle, MIME-Typen und andere Einstellungen für Grails oder Spring

    • resources.groovy enthält Spring Bean-Definitionen

    • logback.groovy enthält die Protokollierungskonfiguration

  • controllers - verantwortlich für die Bearbeitung von Anfragen und das Generieren von Antworten oder das Delegieren dieser an die Ansichten. Wenn ein Dateiname mit*Controller endet, erstellt das Framework standardmäßig eine Standard-URL-Zuordnung für jede in der Controller-Klasse definierte Aktion

  • domain - enthält das Geschäftsmodell der Grails-Anwendung. Jede hier lebende Klasse wird von GORM auf Datenbanktabellen abgebildet

  • i18n - wird zur Unterstützung der Internationalisierung verwendet

  • init - ein Einstiegspunkt der Anwendung

  • services - Hier wird die Geschäftslogik der Anwendung gespeichert. Standardmäßig erstellt Grails für jeden Service eine Spring-Singleton-Bean

  • taglib - der Ort für benutzerdefinierte Tag-Bibliotheken

  • views - enthält Ansichten und Vorlagen

4. Eine einfache Webanwendung

In diesem Kapitel erstellen wir eine einfache Web-App zum Verwalten von Schülern. Beginnen wir mit dem Aufruf des CLI-Befehls zum Erstellen eines Anwendungsskeletts:

grails create-app

Wenn die Grundstruktur des Projekts erstellt wurde, können Sie mit der Implementierung der tatsächlichen Web-App-Komponenten fortfahren.

4.1. Domänenschicht

Beginnen wir beim Generieren einer Webanwendung für den Umgang mit Schülern mit der Generierung einer Domänenklasse mit dem NamenStudent:

grails create-domain-class com.example.grails.Student

Zum Schluss fügen wir die EigenschaftenfirstName undlastNamehinzu:

class Student {
    String firstName
    String lastName
}

Grails wendet seine Konventionen an und richtet eine objektrelationale Zuordnung für alle Klassen im Verzeichnisgrails-app/domainein.

Dank des MerkmalsGormEntity,all domain classes will have access to all CRUD operations, das wir im nächsten Abschnitt für die Implementierung von Diensten verwenden werden.

4.2. Service-Schicht

Unsere Anwendung wird die folgenden Anwendungsfälle behandeln:

  • Liste der Schüler anzeigen

  • Neue Schüler anlegen

  • Bestehende Schüler entfernen

Lassen Sie uns diese Anwendungsfälle implementieren. Wir beginnen mit der Generierung einer Serviceklasse:

grails create-service com.example.grails.Student

Gehen wir zum Verzeichnisgrails-app/services, suchen unseren neu erstellten Service im entsprechenden Paket und fügen alle erforderlichen Methoden hinzu:

@Transactional
class StudentService {

    def get(id){
        Student.get(id)
    }

    def list() {
        Student.list()
    }

    def save(student){
        student.save()
    }

    def delete(id){
        Student.get(id).delete()
    }
}

Note that services don’t support transactions by default. Wir können diese Funktion aktivieren, indem wir der Klasse die Annotation@Transactionalhinzufügen.

4.3. Controller-Schicht

Um die Geschäftslogik für die Benutzeroberfläche verfügbar zu machen, erstellen wir einStudentController, indem Sie den folgenden Befehl aufrufen:

grails create-controller com.example.grails.Student

Standardmäßig istGrails injects beans by names. Dies bedeutet, dass wir die Singleton-InstanzStudentService einfach in unseren Controller einfügen können, indem wir eine Instanzvariable namensstudentsService deklarieren.

Wir können jetzt Aktionen zum Lesen, Erstellen und Löschen von Schülern definieren.

class StudentController {

    def studentService

    def index() {
        respond studentService.list()
    }

    def show(Long id) {
        respond studentService.get(id)
    }

    def create() {
        respond new Student(params)
    }

    def save(Student student) {
        studentService.save(student)
        redirect action:"index", method:"GET"
    }

    def delete(Long id) {
        studentService.delete(id)
        redirect action:"index", method:"GET"
    }
}

Konventionell istthe index() action from this controller will be mapped to the URI*/student/index*, dieshow() Aktion auf/student/show und so weiter.

4.4. Ebene anzeigen

Nachdem wir unsere Controller-Aktionen eingerichtet haben, können wir nun mit der Erstellung der UI-Ansichten fortfahren. Wir erstellen drei Groovy-Serverseiten zum Auflisten, Erstellen und Entfernen von Schülern.

Gemäß der Konvention rendert Grails eine Ansicht basierend auf dem Namen und der Aktion des Controllers. Zum Beispielthe index()action from StudentController will resolve to /grails-app/views/student/index.gsp

Beginnen wir mit der Implementierung der Ansicht/grails-app/views/student/index.gsp, in der eine Liste der Schüler angezeigt wird. Wir verwenden das Tag<f:table/>, um eine HTML-Tabelle zu erstellen, in der alle Schüler angezeigt werden, die von der Aktionindex()in unserem Controller zurückgegeben wurden.

Wenn wir mit einer Liste von Objekten antworten,Grails will add the “List” suffix to the model name, damit wir auf die Liste der Schülerobjekte mit der VariablenstudentList zugreifen können:



    
        
    
    
        
        

Wir fahren nun mit der Ansicht/grails-app/views/student/create.gsp, fort, mit der der Benutzer neue Schüler erstellen kann. Wir verwenden das integrierte<f:all/>-Tag, das ein Formular für alle Eigenschaften einer bestimmten Bean anzeigt:



    
        
    
    
        

Zuletzt erstellen wir die Ansicht/grails-app/views/student/show.gsp zum Anzeigen und eventuellen Löschen von Schülern.

Unter anderem nutzen wir<f:display/>, das eine Bean als Argument verwendet und alle ihre Felder anzeigt:



    
        
    
    
        
        

4.5. Unit-Tests

Grails nutzt hauptsächlichSpock zu Testzwecken. Wenn Sie mit Spock nicht vertraut sind, empfehlen wir dringend, zuerstthis tutorial zu lesen.

Beginnen wir mit dem Unit-Test derindex()-Aktion unsererStudentController.

Wir werden dielist()-Methode vonStudentService verspotten und testen, obindex() das erwartete Modell zurückgibt:

void "Test the index action returns the correct model"() {
    given:
    controller.studentService = Mock(StudentService) {
        list() >> [new Student(firstName: 'John',lastName: 'Doe')]
    }

    when:"The index action is executed"
    controller.index()

    then:"The model is correct"
    model.studentList.size() == 1
    model.studentList[0].firstName == 'John'
    model.studentList[0].lastName == 'Doe'
}

Testen wir nun die Aktion vondelete(). Wir überprüfen, obdelete() vonStudentService aufgerufen wurde, und überprüfen die Umleitung zur Indexseite:

void "Test the delete action with an instance"() {
    given:
    controller.studentService = Mock(StudentService) {
      1 * delete(2)
    }

    when:"The domain instance is passed to the delete action"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'DELETE'
    controller.delete(2)

    then:"The user is redirected to index"
    response.redirectedUrl == '/student/index'
}

4.6. Integrationstests

Schauen wir uns als Nächstes an, wie Integrationstests für die Serviceschicht erstellt werden. Hauptsächlich testen wir die Integration mit einer ingrails-app/conf/application.yml. konfigurierten Datenbank

By default, Grails uses the in-memory H2 database für diesen Zweck.

Beginnen wir zunächst mit der Definition einer Hilfsmethode zum Erstellen von Daten zum Auffüllen der Datenbank:

private Long setupData() {
    new Student(firstName: 'John',lastName: 'Doe')
      .save(flush: true, failOnError: true)
    new Student(firstName: 'Max',lastName: 'Foo')
      .save(flush: true, failOnError: true)
    Student student = new Student(firstName: 'Alex',lastName: 'Bar')
      .save(flush: true, failOnError: true)
    student.id
}

Dank der Annotation@Rollback in unserer Integrationstestklasseeach method will run in a separate transaction, which will be rolled back at the end of the test.

Sehen Sie sich an, wie wir den Integrationstest für unserelist()-Methode implementiert haben:

void "test list"() {
    setupData()

    when:
    List studentList = studentService.list()

    then:
    studentList.size() == 3
    studentList[0].lastName == 'Doe'
    studentList[1].lastName == 'Foo'
    studentList[2].lastName == 'Bar'
}

Testen wir auch diedelete()-Methode und überprüfen Sie, ob die Gesamtzahl der Schüler um eins verringert wird:

void "test delete"() {
    Long id = setupData()

    expect:
    studentService.list().size() == 3

    when:
    studentService.delete(id)
    sessionFactory.currentSession.flush()

    then:
    studentService.list().size() == 2
}

5. Ausführen und Bereitstellen

Das Ausführen und Bereitstellen von Apps kann durch Aufrufen eines einzelnen Befehls über die Grails-CLI erfolgen.

Zum Ausführen der App verwenden Sie:

grails run-app

Standardmäßig richtet Grails Tomcat auf Port 8080 ein.

Navigieren wir zuhttp://localhost:8080/student/index, um zu sehen, wie unsere Webanwendung aussieht:

image

Wenn Sie Ihre Anwendung in einem Servlet-Container bereitstellen möchten, verwenden Sie:

grails war

um ein einsatzbereites Kriegsartefakt zu erstellen.

6. Fazit

In diesem Artikel haben wir uns darauf konzentriert, wie eine Grails-Webanwendung mit der Philosophie "Convention over Configuration" erstellt wird. Wir haben auch gesehen, wie Unit- und Integrationstests mit dem Spock-Framework durchgeführt werden.

Wie immer befindet sich der gesamte hier verwendete Code inover on GitHub.