Übungsaufgaben zu Thymeleaf im Backend: eine Seite für die Mitfahrgesuche

https://bildung.social/@oerinformatik/

https://oer-informatik.de/flurmonitor-thymeleaf-einbinden-uebungsaufgaben

Thymeleaf, Spring MVC, Model-View-Controller, Controller, Template, statische Ressourcen, Spring Security, Smoke-Test, Fehlersuche, Mitfahrgesuche, Übungsaufgaben, Prüfungsvorbereitung

tl/dr; (ca. 58 min Lese- und Bearbeitungszeit): Auf dem Flurmonitor sollen neben den Fahrtangeboten auch die Mitfahrgesuche erscheinen. In diesen Übungen bringst Du den Weg einer Anfrage durch Spring MVC in die richtige Reihenfolge, sagst voraus, unter welcher URL Dateien landen und was ein Controller antwortet, legst Controller, Template und Smoke-Test für eine Gesuche-Seite an und findest Fehler anhand ihrer Symptome [AI-Assisted]. (Zuletzt geändert am 11.11.2026)

Dieser Artikel ist Teil einer Artikelreihe über den Flurmonitor mit Thymeleaf: Projektübersicht / Scrum-Projektstart / Thymeleaf einbinden / Übungsaufgaben zu Thymeleaf einbinden / Templates / Ansichtsmodell / Integrationstest der Web-Schicht / Konfiguration und Formatierung / Aktualisierung / Hinweise mit Formularen / Robustheit und Betrieb / GUI-Test mit Selenium / Akzeptanztest / Change Request Keycloak

Diese Übungsaufgaben gehören zum Artikel Thymeleaf ins Backend einbinden: Controller, Model und das erste Template für den Flurmonitor. Alle Aufgaben spielen im Projektteam der Mitfahr-App Mitfahrlabor und setzen den Übungsstrang zu den Mitfahrgesuchen fort: Im Product Backlog steht dafür die Story MON-13a „Gesuche anzeigen“. Ausgangspunkt ist das Projekt im Ordner src/a02-thymeleaf-einbinden des Backend-Repositorys.

Sequenzdiagramm einer Anfrage GET /flurmonitor: SecurityFilterChain, DispatcherServlet, FlurmonitorController mit MonitorService, ThymeleafViewResolver und TemplateEngine erzeugen gemeinsam das HTML für den Browser (mit KI erstellt)

Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1 und Aufgabe 1.2. Als FIA, FIDP oder FIDV musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das sind Aufgabe 2.1 und Aufgabe 2.2. Von FIA wird zusätzlich erwartet, dass ihnen Aufgaben auf Profilkompetenz-Ebene (Aufgabe 3.1) keine Probleme bereiten. Notiere Deine Antworten zuerst vollständig, bevor Du die Beispiellösung aufklappst. Code-Aufgaben prüfst Du am besten im Projekt: Lass die Tests laufen und ruf die Seite im Browser auf. Bei Begründungen und Bezeichnern sind andere fachlich richtige Lösungen ebenso richtig.

Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?

Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.

Erstelle neue Übungsaufgaben zum Thema „Thymeleaf im Backend: eine Seite
für die Mitfahrgesuche“.

Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.

Fachliche Grundlage:
- https://oer-informatik.de/flurmonitor-thymeleaf-einbinden
- https://oer-informatik.de/szenario-mitfahrlabor
- Stilbeispiel: https://oer-informatik.de/flurmonitor-thymeleaf-einbinden-uebungsaufgaben

Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Thymeleaf
- Spring MVC
- Model-View-Controller
- Controller
- Template
- statische Ressourcen
- Spring Security
- Smoke-Test
- Fehlersuche
- Mitfahrgesuche

Kompetenzstufe: Basiskompetenz (alternativ: Kernkompetenz, Profilkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan

Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
   abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
   zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
   Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
   Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
   Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
   danach frage.

Aufgabe 1.1: Den Weg einer Anfrage ordnen (Basiskompetenz)

Der Flurmonitor im Foyer soll künftig auch eine Seite mit den offenen Mitfahrgesuchen unter /flurmonitor/gesuche zeigen. Zuständig ist ein @Controller namens MitfahrgesucheController, der die Zahl der offenen Gesuche beim GesuchService abfragt. Oksana Melnyk hat die Schritte einer Anfrage auf Karten geschrieben, aber die Karten sind durcheinandergeraten:

Karten mit den Schritten einer Anfrage, ungeordnet
Karte Schritt
A Thymeleaf ersetzt im Template die th:text-Ausdrücke durch die Werte aus dem Model.
B Das DispatcherServlet ruft die Methode anzeigen(model) des MitfahrgesucheController auf.
C Der Browser im Foyer sendet GET /flurmonitor/gesuche.
D Der Controller legt die Zahl mit model.addAttribute("anzahlGesuche", …) ab.
E Der ViewResolver setzt aus dem View-Namen den Pfad classpath:/templates/flurmonitor-gesuche.html zusammen.
F Spring Security prüft seine Regeln und lässt die Anfrage ohne Anmeldung durch.
G Der Controller gibt den String "flurmonitor-gesuche" zurück.
H Der Browser erhält 200 OK mit text/html und fordert danach /css/flurmonitor-bootstrap.css an.
I Der Controller fragt beim GesuchService die Zahl der offenen Gesuche ab.

a) Bring die Karten in die Reihenfolge, in der die Schritte ablaufen. (5 Punkte)

C → F → B → I → D → G → E → A → H

Bewertung: 5 Punkte bei vollständig richtiger Reihenfolge, je falsch platzierter Karte 1 Punkt Abzug. D und I dürfen vertauscht sein, wenn der Wert vorher in einer Variablen steht; im üblichen Code fragt der Controller zuerst den Service und legt dann das Ergebnis ab.

b) Ordne die Karten B, D, E und A je einem Bestandteil von Model-View-Controller zu, der in diesem Schritt im Mittelpunkt steht, und begründe kurz. (3 Punkte)

  • B: Controller, denn er nimmt die Anfrage an.
  • D: Model, denn hier entstehen die Daten, die zur View wandern.
  • E und A: View, denn erst wird das Template gesucht, dann wird es mit den Daten gerendert.

Je zwei richtig zugeordnete und begründete Karten 1 Punkt, für alle vier 3 Punkte. D als „Controller“ ist mit der Begründung „der Controller füllt das Model“ ebenfalls richtig.

c) Jonas Wolff fragt, warum der Browser in Karte H eine zweite Anfrage stellt. Erläutere das und nenne den Ordner im Projekt, in dem die angeforderte Datei liegt. (2 Punkte)

Das HTML enthält nur einen Verweis (<link rel="stylesheet" href="/css/flurmonitor-bootstrap.css">); der Browser lädt jede verknüpfte Datei mit einer eigenen GET-Anfrage nach (1 Punkt). Die Datei liegt als statische Ressource unter src/main/resources/static/css/flurmonitor-bootstrap.css (1 Punkt).

Aufgabe 1.2: Pfade und Antworten vorhersagen (Basiskompetenz)

Für die Gesuche-Seite legt das Team neue Dateien an. Die Anwendung läuft lokal unter http://localhost:8080.

a) Gib für jede Datei die URL an, unter der Spring Boot sie ausliefert, oder „keine eigene URL“. (4 Punkte)

Dateien für die Gesuche-Seite
Nr. Datei im Projekt URL
1 src/main/resources/static/css/gesuche.css
2 src/main/resources/static/bilder/symbol-sucht.svg
3 src/main/resources/templates/flurmonitor-gesuche.html
4 src/main/resources/public/robots.txt
Dateien und ihre URLs
Nr. Datei im Projekt URL
1 src/main/resources/static/css/gesuche.css http://localhost:8080/css/gesuche.css
2 src/main/resources/static/bilder/symbol-sucht.svg http://localhost:8080/bilder/symbol-sucht.svg
3 src/main/resources/templates/flurmonitor-gesuche.html keine eigene URL, nur über einen Controller mit dem View-Namen flurmonitor-gesuche
4 src/main/resources/public/robots.txt http://localhost:8080/robots.txt

Je Zeile 1 Punkt. Zu Zeile 4: public ist neben static einer der Ordner für statische Ressourcen. Im Projekt antwortet die URL ohne Anmeldung allerdings mit 401, weil die SecurityFilterChain nur /flurmonitor/**, /css/** und /bilder/** freigibt; wer das bemerkt, zeigt besonders gutes Verständnis.

b) Gib an, welche Template-Datei Spring Boot mit den Standardeinstellungen zu diesen View-Namen sucht: "flurmonitor-gesuche", "monitor/gesuche" und "gesuche.html". (3 Punkte)

  • "flurmonitor-gesuche" → src/main/resources/templates/flurmonitor-gesuche.html (1 Punkt)
  • "monitor/gesuche" → src/main/resources/templates/monitor/gesuche.html, also im Unterordner monitor (1 Punkt)
  • "gesuche.html" → src/main/resources/templates/gesuche.html.html; die Endung wird immer angehängt, die Datei gibt es also meist nicht (1 Punkt)

c) Jonas hat zwei Varianten eines Controllers geschrieben. Sie unterscheiden sich nur in der Annotation über der Klasse:

@RestController                       // Variante 1
// @Controller                        // Variante 2
public class MitfahrgesucheController {

    @GetMapping("/flurmonitor/gesuche")
    public String anzeigen(Model model) {
        model.addAttribute("anzahlGesuche", 3);
        return "flurmonitor-gesuche";
    }
}

Im Template flurmonitor-gesuche.html steht unter anderem <p>Offene Gesuche: <strong th:text="${anzahlGesuche}">0</strong></p>. Sag für beide Varianten voraus, was im Rumpf der Antwort steht und welchen Content-Type sie hat. (4 Punkte)

  • Variante 1 (@RestController): Der Rumpf besteht nur aus dem Text flurmonitor-gesuche, Content-Type text/plain (2 Punkte). Wegen @ResponseBody ist der String der Inhalt der Antwort; das Model wird nicht benutzt.
  • Variante 2 (@Controller): Der Rumpf ist das gerenderte HTML des Templates, darin <p>Offene Gesuche: <strong>3</strong></p> ohne th:-Attribut, Content-Type text/html (2 Punkte).

Im Projekt ausprobiert: Variante 1 liefert text/plain;charset=UTF-8, Variante 2 text/html;charset=UTF-8.

Aufgabe 2.1: Eine Seite für die Mitfahrgesuche anlegen (Kernkompetenz)

Für die Story MON-13a soll im ersten Schritt eine eigene Seite entstehen, die den Standort des Monitors und die Zahl der offenen Gesuche zeigt. Die Liste der einzelnen Gesuche folgt später. Hast Du aus den Übungen der Backend-Reihe einen GesuchService, ergänzt Du dort eine Methode long anzahlOffen(). Sonst legst Du diesen Startcode an:

package de.dbh.mitfahrlabor.service;

import org.springframework.stereotype.Service;

/** Platzhalter, bis die Gesuche im Monitor-Service ankommen (Eintrag D im Product Backlog). */
@Service
public class GesuchService {

    public long anzahlOffen() {
        return 3;
    }
}

a) Schreib im Paket de.dbh.mitfahrlabor.web die Klasse MitfahrgesucheController. Sie beantwortet GET /flurmonitor/gesuche, legt den Standort „Foyer Gebäude A“ unter standort und die Zahl der offenen Gesuche unter anzahlGesuche ins Model und gibt den View-Namen flurmonitor-gesuche zurück. (6 Punkte)

package de.dbh.mitfahrlabor.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import de.dbh.mitfahrlabor.service.GesuchService;

/** Seite für die Mitfahrgesuche am Flurmonitor (Story MON-13a, erster Schritt). */
@Controller
public class MitfahrgesucheController {

    private final GesuchService gesuchService;

    public MitfahrgesucheController(GesuchService gesuchService) {
        this.gesuchService = gesuchService;
    }

    @GetMapping("/flurmonitor/gesuche")
    public String anzeigen(Model model) {
        model.addAttribute("standort", "Foyer Gebäude A");
        model.addAttribute("anzahlGesuche", gesuchService.anzahlOffen());
        return "flurmonitor-gesuche";
    }
}

Bewertung: @Controller (nicht @RestController) 1 Punkt, Service per Konstruktor 1 Punkt, @GetMapping mit richtigem Pfad 1 Punkt, Parameter Model 1 Punkt, beide Attribute mit den geforderten Namen 1 Punkt, View-Name ohne Endung 1 Punkt. Den Standort als Konstante wie im FlurmonitorController abzulegen, ist ebenso richtig.

b) Leg das Template flurmonitor-gesuche.html an. Das gerenderte HTML soll gültig sein; das Template soll das Stylesheet /css/flurmonitor-bootstrap.css über einen Link-Ausdruck einbinden, die Überschrift „Mitfahrgesuche“ tragen und Standort und Anzahl aus dem Model ausgeben. Ohne Server geöffnet soll es sinnvolle Beispielwerte zeigen. (5 Punkte)

Datei src/main/resources/templates/flurmonitor-gesuche.html:

<!DOCTYPE html>
<html lang="de" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Mitfahrlabor – Mitfahrgesuche am Flurmonitor</title>
  <link rel="stylesheet" href="../static/css/flurmonitor-bootstrap.css" th:href="@{/css/flurmonitor-bootstrap.css}">
</head>
<body>
  <main class="container-fluid px-4 py-4">
    <h1 class="display-5 fw-bold text-primary">Mitfahrgesuche</h1>
    <p class="lead">Flurmonitor im <span th:text="${standort}">Eingang A</span></p>
    <p>Offene Gesuche: <strong th:text="${anzahlGesuche}">0</strong></p>
  </main>
</body>
</html>

Bewertung: richtiger Ort unter templates 1 Punkt, vollständiges Grundgerüst mit lang und charset 1 Punkt, Stylesheet mit th:href="@{…}" 1 Punkt, beide Werte mit th:text und den Attributnamen aus a) 1 Punkt, Beispielwerte im Element für die Ansicht ohne Server 1 Punkt. Bootstrap vom CDN wie in flurmonitor.html darf zusätzlich eingebunden sein. Das gerenderte HTML dieser Lösung meldet der Nu Html Checker ohne Fehler.

c) Für die neue Seite musst Du die SecurityFilterChain nicht ändern. Begründe das und nenne ein Beispiel für eine neue Seite, bei der Du sie ändern müsstest. (2 Punkte)

Die Regel requestMatchers(HttpMethod.GET, "/flurmonitor/**", …).permitAll() passt auf alle Pfade unter /flurmonitor, also auch auf /flurmonitor/gesuche (1 Punkt). Ändern müsstest Du sie etwa für eine öffentliche Seite außerhalb von /flurmonitor, z. B. /gesuche, oder für Stylesheets in einem Ordner wie static/gesuche/, der nicht unter /css/** oder /bilder/** fällt (1 Punkt).

Aufgabe 2.2: Einen Smoke-Test für die Gesuche-Seite schreiben (Kernkompetenz)

Die Definition of Done verlangt grüne Tests für jede neue Klasse. Für die Gesuche-Seite aus Aufgabe 2.1 schreibst Du deshalb einen Smoke-Test nach dem Muster von FlurmonitorSmokeTest.

a) Schreib die Testklasse MitfahrgesucheSmokeTest. Sie startet den ganzen Anwendungskontext und prüft, dass GET /flurmonitor/gesuche ohne Anmeldung mit Status 200, HTML, dem View-Namen flurmonitor-gesuche und den Werten „Mitfahrgesuche“, „Foyer Gebäude A“ und der Anzahl 3 antwortet. Damit der Test nicht von den Daten abhängt, ersetzt Du den GesuchService durch einen Mock, der 3 liefert. (6 Punkte)

package de.dbh.mitfahrlabor.web;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.assertj.MockMvcTester;

import de.dbh.mitfahrlabor.service.GesuchService;

@SpringBootTest
@AutoConfigureMockMvc
class MitfahrgesucheSmokeTest {

    @Autowired
    private MockMvcTester mvc;

    @MockitoBean
    private GesuchService gesuchService;

    @Test
    void gesucheSeiteIstOhneAnmeldungErreichbar() {
        when(gesuchService.anzahlOffen()).thenReturn(3L);

        assertThat(mvc.get().uri("/flurmonitor/gesuche"))
                .hasStatusOk()
                .hasContentTypeCompatibleWith(MediaType.TEXT_HTML)
                .hasViewName("flurmonitor-gesuche")
                .bodyText()
                .contains("Mitfahrgesuche", "Foyer Gebäude A", "<strong>3</strong>")
                .doesNotContain("th:text");
    }
}

Bewertung: @SpringBootTest mit @AutoConfigureMockMvc und MockMvcTester 1 Punkt, @MockitoBean für den Service 1 Punkt, Verhalten des Mocks mit when(…).thenReturn(3L) 1 Punkt, Status und Content-Type 1 Punkt, View-Name 1 Punkt, Inhalte 1 Punkt. Im Projekt ausgeführt ist der Test grün.

b) Ergänze einen Test, der sicherstellt, dass POST /flurmonitor/gesuche ohne Anmeldung nicht angenommen wird. Gib an, welchen Status Du erwartest, und begründe ihn mit der Sicherheitskonfiguration. (3 Punkte)

    @Test
    void gesucheSeiteNimmtOhneAnmeldungKeinePostAnfrageAn() {
        assertThat(mvc.post().uri("/flurmonitor/gesuche")).hasStatus(HttpStatus.UNAUTHORIZED);
    }

Erwartet wird 401 (1 Punkt für den Test, 1 Punkt für den Status): Die Freigabe für /flurmonitor/** gilt nur für HttpMethod.GET; für POST greift anyRequest().authenticated(), und ohne Zugangsdaten antwortet Spring Security vor jedem Controller mit 401 (1 Punkt). Im Projekt ausgeführt ist der Test grün.

c) Benenne das Template probeweise in flurmonitor-gesuch.html um und lass den Test aus a) laufen. Beschreib, woran der Test scheitert und welche Meldung auf die Ursache hinweist. Benenne es danach zurück. (2 Punkte)

Die Anfrage scheitert beim Rendern: Thymeleaf findet zum View-Namen flurmonitor-gesuche keine Datei. Mit MockMvcTester gibt es dafür keinen Status 500; der Test bricht mit einer IllegalStateException ab: Request failed with unresolved exception jakarta.servlet.ServletException: Request processing failed: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [flurmonitor-gesuche], template might not exist or might not be accessible by any of the configured Template Resolvers (1 Punkt). Den Hinweis auf die Ursache gibt die TemplateInputException mit dem gesuchten View-Namen (1 Punkt). Im laufenden Server erhielte der Browser stattdessen den Status 500.

Aufgabe 3.1: Fehler anhand von Symptomen finden (Profilkompetenz)

Im Daily Scrum berichten mehrere Developers von Problemen mit ihren Varianten der Gesuche-Seite. Jede Variante enthält genau einen Fehler; der Rest entspricht dem Code-Stand des Artikels und der Lösung von Aufgabe 2.1. Der folgende Code ist absichtlich fehlerhaft.

Symptome und Code-Ausschnitte aus dem Daily Scrum
Nr. Symptom Ausschnitt aus der Variante
1 Der Browser zeigt für /flurmonitor/gesuche eine JSON-Antwort mit "status":404 und "detail":"No static resource flurmonitor/gesuche.". Beim Start erscheinen keine Fehler. Die Klasse beginnt mit package de.dbh.flurmonitor.web;, darunter @Controller public class MitfahrgesucheController { … } mit @GetMapping("/flurmonitor/gesuche").
2 Status 500 mit Problem Details, im Log: TemplateInputException: Error resolving template [flurmonitor/gesuche], template might not exist …. Die Datei templates/flurmonitor-gesuche.html gibt es. return "flurmonitor/gesuche";
3 Die Seite erscheint, aber ohne Farben und Schriftgrößen. In den Entwicklerwerkzeugen des Browsers steht die Anfrage GET /gesuche/gesuche.css mit Status 401. Im Template: th:href="@{/gesuche/gesuche.css}", die Datei liegt unter static/gesuche/gesuche.css.
4 Der Browser zeigt eine weiße Seite mit dem Text flurmonitor-gesuche, sonst nichts. @RestController public class MitfahrgesucheController { … }
5 Die Seite erscheint mit Farben und der Anzahl, aber hinter „Flurmonitor im“ steht nichts, nicht einmal der Beispielwert. model.addAttribute("ort", "Foyer Gebäude A");

a) Erkläre für jede Variante die Ursache des Symptoms und gib eine Korrektur an. (15 Punkte)

Ursachen und Korrekturen der fünf Varianten
Nr. Ursache Korrektur
1 Das Paket de.dbh.flurmonitor.web liegt nicht unterhalb von de.dbh.mitfahrlabor, dem Paket der Klasse mit @SpringBootApplication. Die Komponentensuche findet den Controller nicht, Spring legt keine Bean an, und für den Pfad gibt es keinen Handler. Die Anfrage landet bei der Auslieferung statischer Ressourcen, die keine Datei findet (404, „No static resource“). Klasse ins Paket de.dbh.mitfahrlabor.web verschieben.
2 Ein View-Name mit Schrägstrich wird als Unterordner gelesen: Spring sucht templates/flurmonitor/gesuche.html. Der Controller wurde gefunden, deshalb 500 und nicht 404. return "flurmonitor-gesuche"; oder die Datei nach templates/flurmonitor/gesuche.html verschieben.
3 Das HTML kommt an, weil /flurmonitor/** freigegeben ist. /gesuche/gesuche.css fällt aber unter keine Freigabe; anyRequest().authenticated() greift, Spring Security antwortet ohne Anmeldung mit 401, und der Browser verwirft das Stylesheet. Datei nach static/css/gesuche.css verschieben und th:href="@{/css/gesuche.css}" setzen, oder /gesuche/** in die permitAll-Regel für GET aufnehmen.
4 @RestController enthält @ResponseBody: Der zurückgegebene String wird als Text in die Antwort geschrieben statt als View-Name gedeutet. Model und Template werden nicht benutzt. @Controller statt @RestController.
5 Der Controller legt den Wert unter ort ab, das Template fragt ${standort} ab. Ein fehlendes Attribut ergibt in Thymeleaf null, und th:text mit null gibt einen leeren Text aus; der Beispielwert wird trotzdem ersetzt. Ergebnis im HTML: <span></span>. Gleichen Namen verwenden: model.addAttribute("standort", …).

Bewertung je Variante: Ursache 2 Punkte, Korrektur 1 Punkt. Alle fünf Varianten sind im Projekt nachgestellt; die beschriebenen Symptome treten genau so auf.

b) Welche der fünf Fehler hätte der Smoke-Test aus Aufgabe 2.2 a) aufgedeckt, und welche nicht? Begründe und schlage für einen nicht entdeckten Fehler eine zusätzliche Prüfung vor. (4 Punkte)

Aufgedeckt hätte der Smoke-Test aus 2.2 a) die Varianten 1 (Status 404 statt 200), 2 (Abbruch mit TemplateInputException), 4 (Content-Type text/plain, kein View-Name) und 5 (der Text „Foyer Gebäude A“ fehlt im HTML) (2 Punkte, je zwei richtige Varianten mit Begründung 1 Punkt).

Nicht aufgedeckt hätte er Variante 3: Er fragt nur die Seite selbst ab, und die kommt mit 200 an. Das Stylesheet lädt erst der Browser nach (1 Punkt). Eine zusätzliche Prüfung fragt jede eingebundene Ressource ohne Anmeldung ab, z. B. assertThat(mvc.get().uri("/gesuche/gesuche.css")).hasStatusOk();, wie es FlurmonitorSmokeTest für Stylesheet und Logo tut (1 Punkt). Ein Systemtest im echten Browser, wie er mit Selenium später in der Reihe folgt, würde den Fehler ebenfalls zeigen.


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zu Thymeleaf im Backend: eine Seite für die Mitfahrgesuche” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/flurmonitor-thymeleaf-einbinden-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/java-springboot/Backend. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 11.11.2026.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: