Byg en MVC-webapplikation med Grails

1. Oversigt

I denne vejledning lærer vi, hvordan du opretter en simpel webapplikation ved hjælp af Grails.

Grails (mere præcist er den nyeste større version) er en ramme bygget oven på Spring Boot-projektet og bruger Apache Groovy-sproget til at udvikle webapps.

Det er inspireret af Rails Framework for Ruby og er bygget op omkring konvention-over-konfigurationsfilosofien, som tillader reduktion af kedelpladekoden.

2. Opsætning

Lad os først gå over til den officielle side for at forberede miljøet. På tidspunktet for denne tutorial er den seneste version 3.3.3.

Kort sagt, der er to måder at installere Grails på: via SDKMAN eller ved at downloade distributionen og tilføje binære filer til PATH-miljøvariablen.

Vi dækker ikke opsætningen trin for trin, fordi den er veldokumenteret i Grails Docs.

3. Anatomi af en Grails-app

I dette afsnit vil vi få en bedre forståelse af Grails applikationsstruktur. Som vi nævnte tidligere foretrækker Grails konvention frem for konfiguration, hvorfor filernes placering definerer deres formål. Lad os se, hvad vi har i grails-app vejviser:

  • aktiver - et sted, hvor vi gemmer statiske aktiver-filer som stilarter, javascript-filer eller billeder
  • konf - indeholder projektkonfigurationsfiler:
    • ansøgning.yml indeholder standardindstillinger for webapp som datakilde, mime-typer og andre Grails eller Spring-relaterede indstillinger
    • resources.groovy indeholder definitioner på forårsbønner
    • logback.groovy indeholder logningskonfiguration
  • controllere - ansvarlig for håndtering af anmodninger og generering af svar eller delegering af dem til synspunkterne. Efter konvention, når et filnavn slutter med * Controller, rammen opretter en standard URL-kortlægning for hver handling defineret i controller-klassen
  • domæne - indeholder forretningsmodellen for Grails-applikationen. Hver klasse, der bor her, bliver kortlagt til databasetabeller af GORM
  • i18n - bruges til internationaliseringsstøtte
  • i det - et startpunkt for ansøgningen
  • tjenester - applikationens forretningslogik lever her. Efter konvention opretter Grails en Spring singleton bønne til hver tjeneste
  • taglib - stedet for brugerdefinerede tagbiblioteker
  • synspunkter - indeholder visninger og skabeloner

4. En simpel webapplikation

I dette kapitel opretter vi en simpel webapp til styring af studerende. Lad os starte med at påkalde CLI-kommandoen til oprettelse af et applikationsskelet:

grails create-app

Når projektets grundlæggende struktur er genereret, lad os gå videre til implementering af faktiske webapp-komponenter.

4.1. Domain Layer

Når vi implementerer en webapplikation til håndtering af studerende, lad os starte med at generere en domæneklasse kaldet Studerende:

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

Og endelig, lad os tilføje fornavn og efternavn egenskaber til det:

klasse Elev {Streng fornavn Streng efternavn}

Grails anvender sine konventioner og opretter en objektrelationskortlægning for alle klasser i grails-app / domæne vejviser.

Desuden takket være GormEntity-træk, alle domæneklasser har adgang til alle CRUD-operationer, som vi bruger i det næste afsnit til implementering af tjenester.

4.2. Servicelag

Vores applikation håndterer følgende brugssager:

  • Visning af en liste over studerende
  • Oprettelse af nye studerende
  • Fjernelse af eksisterende studerende

Lad os implementere disse brugssager. Vi starter med at generere en serviceklasse:

grails create-service com.baeldung.grails.Student

Lad os gå over til grails-app / tjenester katalog, find vores nyoprettede tjeneste i den relevante pakke og tilføj alle nødvendige metoder:

@Transactional class StudentService {def get (id) {Student.get (id)} def list () {Student.list ()} def save (student) {student.save ()} def delete (id) {Student.get (id). slet ()}}

Bemærk, at tjenester ikke understøtter transaktioner som standard. Vi kan aktivere denne funktion ved at tilføje @Transaktionel kommentar til klassen.

4.3. Controller Layer

For at gøre forretningslogikken tilgængelig for brugergrænsefladen, lad os oprette en StudentController ved at påkalde følgende kommando:

grails create-controller com.baeldung.grails.Student

Som standard, Grails injicerer bønner ved navne. Det betyder, at vi let kan injicere StudentService singleton-forekomst i vores controller ved at erklære en instansvariabel kaldet studentsService.

Vi kan nu definere handlinger til læsning, oprettelse og sletning af studerende.

klasse 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"}}

Efter konvention, det indeks() handling fra denne controller kortlægges til URI / studerende / indeks, det at vise() handling til / studerende / show og så videre.

4.4. Vis lag

Efter at have oprettet vores controllerhandlinger kan vi nu fortsætte med at oprette UI-visningerne. Vi opretter tre Groovy Server-sider til notering, oprettelse og fjernelse af studerende.

Efter konvention vil Grails gengive en visning baseret på controllerens navn og handling. For eksempel,indekset () handling fra StudentController vil beslutte at /grails-app/views/student/index.gsp

Lad os starte med at implementere visningen / grails-app /visninger / studerende / index.gsp, der viser en liste over studerende. Vi bruger mærket for at oprette en HTML-tabel, der viser alle studerende, der er vendt tilbage fra indeks() handling i vores controller.

Når vi reagerer med en liste over objekter efter konvention, Grails tilføjer "List" -suffikset til modelnavnet så vi kan få adgang til listen over elevobjekter med variablen studentListe:

  • skab

Vi fortsætter nu til visningen / grails-app /visninger /studerende / create.gsp, som giver brugeren mulighed for at oprette nye studerende. Vi bruger den indbyggede tag, der viser en formular for alle egenskaber for en given bønne:

Lad os endelig oprette visningen / grails-app /visninger /studerende / show.gsp til visning og til sidst sletning af studerende.

Blandt andre tags vil vi drage fordel af , der tager en bønne som et argument og viser alle dens felter:

  • Studenterliste

4.5. Enhedstest

Grails drager hovedsagelig fordel af Spock til testformål. Hvis du ikke er fortrolig med Spock, anbefaler vi stærkt, at du først læser denne vejledning.

Lad os starte med enhedstest af indeks() handling af vores StudentController.

Vi håner liste() metode fra StudentService og test om indeks() returnerer den forventede model:

ugyldigt "Test indekshandlingen returnerer den korrekte model" () {given: controller.studentService = Mock (StudentService) {list () >> [new Student (firstName: 'John', lastName: 'Doe')]} when: "Indekshandling udføres" controller.index () derefter: "Modellen er korrekt" model.studentList.size () == 1 model.studentList [0]. Første navn == 'John' model.studentList [0]. efternavn == 'Doe'}

Lad os nu teste slet () handling. Vi kontrollerer, om slet () blev påberåbt sig fra StudentService og bekræft omdirigering til indekssiden:

ugyldigt "Test slettehandlingen med en forekomst" () {givet: controller.studentService = Mock (StudentService) {1 * slet (2)} når: "Domæneinstansen sendes til sletningen" anmodning.contentType = FORM_CONTENT_TYPE anmodning .method = 'SLET' controller.delete (2) derefter: "Brugeren omdirigeres til indeks" response.redirectedUrl == '/ student / index'}

4.6. Integrationstests

Lad os derefter se på, hvordan man opretter integrationstests til servicelaget. Primært tester vi integration med en database konfigureret i grails-app / conf / application.yml.

Som standard bruger Grails H2-databasen i hukommelsen til dette formål.

Lad os først og fremmest starte med at definere en hjælpemetode til oprettelse af data til udfyldning af databasen:

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) Studentstudent = ny student (fornavn: 'Alex', efternavn: 'Bar'). save (flush: true, failOnError: true) student.id}

Tak til @Rollback kommentar til vores integrationstestklasse, hver metode kører i en separat transaktion, som rulles tilbage i slutningen af ​​testen.

Se på, hvordan vi implementerede integrationstesten til vores liste() metode:

ugyldig "testliste" () {setupData () når: List studentList = studentService.list () derefter: studentList.size () == 3 studentList [0] .lastName == 'Doe' studentList [1] .lastName == 'Foo' studentList [2] .lastName == 'Bar'}

Lad os også teste slet () metode og validere, hvis det samlede antal studerende reduceres med en:

ugyldig "test sletning" () {Lang id = setupData () forvent: studentService.list (). størrelse () == 3 når: studentService.delete (id) sessionFactory.currentSession.flush () derefter: studentService.list () .størrelse () == 2}

5. Kørsel og implementering

Kørsel og implementering af apps kan gøres ved at påberåbe sig en enkelt kommando via Grails CLI.

Brug app til at køre appen:

grails run-app

Som standard opsætter Grails Tomcat på port 8080.

Lad os navigere til // localhost: 8080 / student / indeks for at se, hvordan vores webapplikation ser ud:

Hvis du vil distribuere din applikation til en servletcontainer, skal du bruge:

gral krig

at skabe en klar-til-udrulning krig artefakt.

6. Konklusion

I denne artikel fokuserede vi på, hvordan du opretter en Grails-webapplikation ved hjælp af filosofien convention-over-configuration. Vi så også, hvordan vi udførte enheds- og integrationstest med Spock-rammen.

Som altid kan al den kode, der bruges her, findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found