Übungsaufgaben zu Formularen mit Thymeleaf: ein Mitfahrgesuch zurückziehen
https://bildung.social/@oerinformatik/
https://oer-informatik.de/flurmonitor-hinweise-formulare-uebungsaufgaben
Thymeleaf, Formular, th:object, th:field, Bean Validation, BindingResult, Post-Redirect-Get, CSRF, Fehlersuche, Mitfahrgesuche, Übungsaufgaben, Prüfungsvorbereitung
tl/dr; (ca. 47 min Lese- und Bearbeitungszeit): Das Organisationsteam soll ein Mitfahrgesuch vom Monitor nehmen können, wenn sich die Person gemeldet hat. In diesen Übungen ordnest Du den Ablauf von Post-Redirect-Get und die Bausteine eines Formulars, schreibst Formular-Objekt, Controller, Template und Tests für „Gesuch zurückziehen“ und findest heraus, warum Hinweise der Schulverwaltung doppelt auf dem Monitor stehen [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 / Templates / Ansichtsmodell / Integrationstest der Web-Schicht / Konfiguration und Formatierung / Aktualisierung / Hinweise mit Formularen / Übungsaufgaben zu Formularen / Robustheit und Betrieb / GUI-Test mit Selenium / Akzeptanztest / Change Request Keycloak
Diese Übungsaufgaben gehören zum Artikel Formulare mit Thymeleaf: Die Schulverwaltung legt Hinweise für den Flurmonitor an. Alle Aufgaben spielen im Projektteam der Mitfahr-App Mitfahrlabor und setzen den Übungsstrang zu den Mitfahrgesuchen fort. Ausgangspunkt ist das Projekt im Ordner src/a08-hinweise-formulare des Backend-Repositorys. Den Startcode für die Gesuche findest Du dort im Unterordner uebung-mitfahrgesuche; kopiere seinen Ordner src über den Ordner src des Projekts mitfahrlabor. Er enthält die Gesuche-Seite für den Monitor und den Platzhalter GesuchService, der die Gesuche in einer Liste im Arbeitsspeicher hält. Neu ist dort diese Methode:
/**
* Zieht das Gesuch mit dieser Nummer zurück (Nummer = Position in offeneGesuche(), ab 1).
* @return false, wenn es kein Gesuch mit dieser Nummer gibt
*/
public synchronized boolean zurueckziehen(int nummer, String grund) { … }Product Owner Thomas Becker hat aus dem Epic MON-13 die nächste Story geschnitten:
MON-13g Gesuch zurückziehen (3 SP): Als Organisationsteam möchte ich ein Mitfahrgesuch vom Monitor nehmen, wenn die Person schon eine Fahrt gefunden hat, damit auf den Monitoren nur offene Gesuche stehen.
- AK-MON-13g.1: Angenommen, Gesuch 1 hat sich erledigt. Wenn Andrea Wolf es mit dem Grund „Fahrt gefunden“ zurückzieht und bestätigt, dass die Person informiert ist, dann verschwindet es von den Monitoren, und die Verwaltungsseite meldet „Gesuch zurückgezogen.“
- AK-MON-13g.2: Angenommen, Andrea Wolf lässt den Grund leer, bestätigt nicht oder gibt eine Nummer an, zu der es kein offenes Gesuch gibt. Wenn sie absendet, dann wird nichts zurückgezogen, und das Formular zeigt ihre Eingaben mit einer Meldung am betroffenen Feld.
Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1. 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, starte die Anwendung, melde Dich unter /login als Admin-AW an (Passwort aller Demo-Konten: mitfahren) und beobachte im Browser im Reiter „Netzwerk“ der Entwicklerwerkzeuge, welche Anfragen beim Absenden und beim Neuladen hinausgehen. Bei Begründungen, Bezeichnern und Testnamen 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 „Formulare mit Thymeleaf: ein
Mitfahrgesuch zurückziehen“.
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-hinweise-formulare
- https://oer-informatik.de/szenario-mitfahrlabor
- https://oer-informatik.de/flurmonitor-web-integrationstest
- https://oer-informatik.de/html-grundlagen
- Stilbeispiel: https://oer-informatik.de/flurmonitor-hinweise-formulare-uebungsaufgaben
Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Thymeleaf
- Formular
- th:object
- th:field
- Bean Validation
- BindingResult
- Post-Redirect-Get
- CSRF
- Fehlersuche
- Mitfahrgesuche
Kompetenzstufe: Kernkompetenz (alternativ: Basiskompetenz, 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: Post-Redirect-Get und die Bausteine eines Formulars (Basiskompetenz)
Oksana Melnyk zeigt der neuen Praktikantin, was passiert, wenn Heike Brinkmann im Sekretariat einen Hinweis speichert. Die Praktikantin hat die Schritte auf Karten notiert, aber durcheinandergebracht.
a) Bringe die Schritte in die richtige Reihenfolge für den Fall, dass alle Eingaben gültig sind. (3 Punkte)
| Karte | Schritt | Position |
|---|---|---|
| A | Der Browser schickt GET /verwaltung/hinweise. |
|
| B | Der Controller ruft legeAn(…) am Service auf, der Hinweis wird gespeichert. |
|
| C | Der Browser schickt POST /verwaltung/hinweise mit den Feldern und dem CSRF-Token. |
|
| D | Der Server antwortet mit 302 Found und Location: /verwaltung/hinweise. |
|
| E | Spring füllt das Formular-Objekt und prüft es mit Bean Validation; das BindingResult ist leer. |
|
| F | Der Server liefert die Liste mit der Meldung „Hinweis gespeichert.“; die Meldung kommt aus einem Flash-Attribut. |
Reihenfolge: C, E, B, D, A, F. Volle Punktzahl bei richtiger Reihenfolge, je vertauschtem Paar 1 Punkt Abzug.
b) Ordne jeder Beschreibung den passenden Begriff zu: th:object, th:field, th:errors, BindingResult, Flash-Attribut, CSRF-Token. (6 Punkte)
| Nr. | Beschreibung | Begriff |
|---|---|---|
| 1 | Sammelt im Controller alle Fehler aus Umwandlung und Validierung des Formular-Objekts. | |
| 2 | Legt am <form> fest, auf welches Objekt sich die Felder darin beziehen. |
|
| 3 | Zufälliger Wert in einem versteckten Feld, ohne den Spring Security einen POST mit 403 ablehnt. |
|
| 4 | Setzt an einem Eingabefeld id, name und den aktuellen Wert. |
|
| 5 | Überlebt genau eine Umleitung und steht dann im Model der nächsten Anfrage. | |
| 6 | Gibt die Meldungen zu einem bestimmten Feld aus. |
Je richtiger Zuordnung 1 Punkt.
| Nr. | Begriff |
|---|---|
| 1 | BindingResult |
| 2 | th:object |
| 3 | CSRF-Token |
| 4 | th:field |
| 5 | Flash-Attribut |
| 6 | th:errors |
c) Sage für beide Fälle voraus, welche Anfrage der Browser beim Neuladen (F5) schickt und ob dabei ein weiterer Hinweis gespeichert wird: (1) Heike Brinkmann sieht nach dem Speichern die Meldung „Hinweis gespeichert.“; (2) sie sieht das Formular mit der Meldung „Bitte einen Hinweistext eingeben.“ (2 Punkte)
Die letzte Anfrage war das GET nach der Umleitung; F5 wiederholt nur das GET, es wird nichts gespeichert. Die Meldung verschwindet, weil das Flash-Attribut schon verbraucht ist (1 Punkt).
Die letzte Anfrage war der POST mit dem leeren Text. Der Browser fragt, ob er die Daten erneut senden soll; tut er es, scheitert der POST wieder an der Prüfung, und es wird nichts gespeichert (1 Punkt).
Aufgabe 2.1: Formular-Objekt und Controller für „Gesuch zurückziehen“ (Kernkompetenz)
Jonas Wolff übernimmt die Serverseite von MON-13g. Die Verwaltungsseite liegt unter /verwaltung/gesuche (die Filterkette aus dem Artikel schützt sie schon, Rolle ORGA) und zeigt die offenen Gesuche nummeriert an. Das Formular schickt drei Felder an POST /verwaltung/gesuche/zurueckziehen: nummer (Nummer des Gesuchs), grund (Freitext, höchstens 80 Zeichen) und informiert (Kontrollkästchen „Die Person ist informiert.“).
a) Schreibe die Klasse RueckzugFormular im Paket de.dbh.mitfahrlabor.web.verwaltung mit Feldern, Bean-Validation-Annotationen und Meldungsschlüsseln, sodass AK-MON-13g.2 für Nummer, Grund und Bestätigung geprüft wird. Getter und Setter darfst Du abkürzen. (4 Punkte)
public class RueckzugFormular {
@NotNull(message = "{rueckzug.nummer.leer}")
@Min(value = 1, message = "{rueckzug.nummer.leer}")
private Integer nummer;
@NotBlank(message = "{rueckzug.grund.leer}")
@Size(max = 80, message = "{rueckzug.grund.lang}")
private String grund;
@AssertTrue(message = "{rueckzug.informiert}")
private boolean informiert;
// Getter und Setter (bei boolean: isInformiert/setInformiert)
}Bewertung: nummer als Integer mit @NotNull und Untergrenze (1 Punkt; ein int wäre bei leerem Feld nicht prüfbar), grund mit @NotBlank und @Size(max = 80) (1 Punkt), informiert mit @AssertTrue (1 Punkt), Meldungen als Schlüssel in {…} (1 Punkt). @Positive statt @Min(1) ist ebenso richtig.
b) Ergänze die Einträge in messages.properties für alle Meldungen, auch für die Erfolgsmeldung und für eine Nummer, zu der es kein Gesuch gibt. (2 Punkte)
rueckzug.nummer.leer=Bitte die Nummer eines Gesuchs angeben.
rueckzug.grund.leer=Bitte einen Grund angeben.
rueckzug.grund.lang=Der Grund darf höchstens {max} Zeichen lang sein.
rueckzug.informiert=Bitte bestätigen, dass die Person informiert ist.
rueckzug.unbekannt=Ein offenes Gesuch mit dieser Nummer gibt es nicht.
rueckzug.erledigt=Gesuch zurückgezogen.
Je drei passende Einträge 1 Punkt; die Schlüssel müssen zu denen aus a) und c) passen.
c) Schreibe den Controller GesucheVerwaltungController mit einer GET-Methode für die Seite verwaltung/gesuche und einer POST-Methode zum Zurückziehen. Die POST-Methode prüft das Formular, meldet eine unbekannte Nummer am Feld nummer, zeigt bei Fehlern die Seite erneut und leitet nach Erfolg mit einer Meldung um. (8 Punkte)
@Controller
@RequestMapping("/verwaltung/gesuche")
public class GesucheVerwaltungController {
private final GesuchService gesuchService;
public GesucheVerwaltungController(GesuchService gesuchService) {
this.gesuchService = gesuchService;
}
@GetMapping
public String anzeigen(Model model) {
model.addAttribute("rueckzug", new RueckzugFormular());
model.addAttribute("gesuche", gesuchService.offeneGesuche());
return "verwaltung/gesuche";
}
@PostMapping("/zurueckziehen")
public String zurueckziehen(@Valid @ModelAttribute("rueckzug") RueckzugFormular formular,
BindingResult pruefung, Model model, RedirectAttributes weiterleitung) {
if (!pruefung.hasErrors() && !gesuchService.zurueckziehen(formular.getNummer(), formular.getGrund())) {
pruefung.rejectValue("nummer", "rueckzug.unbekannt"); // fachlicher Fehler am Feld
}
if (pruefung.hasErrors()) {
model.addAttribute("gesuche", gesuchService.offeneGesuche());
return "verwaltung/gesuche";
}
weiterleitung.addFlashAttribute("meldung", "rueckzug.erledigt");
return "redirect:/verwaltung/gesuche";
}
}Bewertung: GET legt leeres Formular-Objekt und Liste ins Model (2 Punkte); @Valid mit BindingResult direkt dahinter (2 Punkte); unbekannte Nummer über rejectValue am Feld, Service nur bei gültigen Eingaben aufgerufen (2 Punkte); bei Fehlern dieselbe Seite mit Liste, sonst Flash-Attribut und redirect: (2 Punkte). Der Name des Model-Attributs (hier rueckzug) ist frei, muss aber in GET, POST und Template gleich sein.
Aufgabe 2.2: Template und Test für „Gesuch zurückziehen“ (Kernkompetenz)
Oksana Melnyk übernimmt die Oberfläche und die Tests zu Jonas’ Controller aus Aufgabe 2.1.
a) Schreibe das Formular in templates/verwaltung/gesuche.html mit den drei Feldern aus Aufgabe 2.1. Jedes Feld hat ein <label>, wird bei Fehlern rot markiert und zeigt seine Meldung darunter. Den Rahmen der Seite und die Liste der Gesuche darfst Du weglassen. (6 Punkte)
<form th:action="@{/verwaltung/gesuche/zurueckziehen}" th:object="${rueckzug}" method="post" novalidate>
<div class="mb-3">
<label for="nummer" class="form-label">Nummer des Gesuchs</label>
<input type="number" min="1" th:field="*{nummer}" class="form-control" th:errorclass="is-invalid">
<p class="invalid-feedback" th:if="${#fields.hasErrors('nummer')}" th:errors="*{nummer}">Fehler</p>
</div>
<div class="mb-3">
<label for="grund" class="form-label">Grund</label>
<input type="text" maxlength="80" th:field="*{grund}" class="form-control" th:errorclass="is-invalid">
<p class="invalid-feedback" th:if="${#fields.hasErrors('grund')}" th:errors="*{grund}">Fehler</p>
</div>
<div class="form-check mb-3">
<input type="checkbox" th:field="*{informiert}" class="form-check-input" th:errorclass="is-invalid">
<label class="form-check-label" th:for="${#ids.prev('informiert')}">Die Person ist informiert.</label>
<p class="invalid-feedback" th:if="${#fields.hasErrors('informiert')}" th:errors="*{informiert}">Fehler</p>
</div>
<button type="submit" class="btn btn-primary">Gesuch zurückziehen</button>
</form>Bewertung: th:action mit POST und th:object (1 Punkt); th:field an allen drei Feldern (2 Punkte); Meldungen mit th:errors und Bedingung, Markierung mit th:errorclass (2 Punkte); passende Labels, beim Kontrollkästchen über #ids.prev oder eine feste ID (1 Punkt). th:field an einem Kontrollkästchen erzeugt zusätzlich ein verstecktes Feld _informiert, damit Spring ein nicht angehaktes Kästchen als false erkennt; das muss man nicht von Hand schreiben.
b) Im Seitenquelltext steht im Formular ein Feld <input type="hidden" name="_csrf" …>, das im Template nicht vorkommt. Erläutere, woher es kommt und was passiert, wenn ein Formular mit action statt th:action es nicht enthält. (2 Punkte)
Thymeleaf fügt das CSRF-Token bei th:action mit POST selbst ein, weil die Filterkette der Verwaltung den CSRF-Schutz eingeschaltet hat (1 Punkt). Fehlt es, lehnt Spring Security den POST mit 403 Forbidden ab, bevor der Controller ihn sieht; es wird nichts zurückgezogen (1 Punkt).
c) Schreibe zwei Testmethoden für einen @WebMvcTest(GesucheVerwaltungController.class) mit @Import(SicherheitsKonfiguration.class) und gemocktem GesuchService: Ein gültiger Rückzug wird umgeleitet und meldet Erfolg (AK-MON-13g.1); ohne Bestätigung bleibt das Formular mit Meldung und erhaltenem Grund stehen, und der Service wird nicht aufgerufen (AK-MON-13g.2). (4 Punkte)
@Test
@WithMockUser(roles = "ORGA")
void gueltigerRueckzugLeitetUm() {
given(gesuchService.zurueckziehen(1, "Fahrt gefunden")).willReturn(true);
assertThat(mvc.post().uri("/verwaltung/gesuche/zurueckziehen").with(csrf())
.param("nummer", "1").param("grund", "Fahrt gefunden").param("informiert", "true"))
.hasStatus(HttpStatus.FOUND)
.hasRedirectedUrl("/verwaltung/gesuche")
.flash().containsEntry("meldung", "rueckzug.erledigt");
}
@Test
@WithMockUser(roles = "ORGA")
void ohneBestaetigungBleibtDasFormularStehen() {
assertThat(mvc.post().uri("/verwaltung/gesuche/zurueckziehen").with(csrf())
.param("nummer", "1").param("grund", "Fahrt gefunden"))
.hasStatusOk()
.hasViewName("verwaltung/gesuche")
.bodyText().contains("Bitte bestätigen, dass die Person informiert ist.", "value=\"Fahrt gefunden\"");
then(gesuchService).should(never()).zurueckziehen(anyInt(), anyString());
}Bewertung: Anmeldung mit Rolle und csrf() (1 Punkt); Status und Ziel der Umleitung (1 Punkt); Flash-Attribut bzw. Meldung (1 Punkt); zweiter Test mit Status 200, Meldung, erhaltener Eingabe und never() (1 Punkt). Wer andExpect-Ketten von MockMvc nutzt, ist ebenso richtig.
Aufgabe 3.1: Doppelte Hinweise auf dem Monitor (Profilkompetenz)
In einer frühen Fassung des Codes für MON-07 hat Jonas Wolff die POST-Methode so geschrieben (Fassung A, absichtlich fehlerhaft):
@PostMapping
public String anlegen(@Valid @ModelAttribute("formular") HinweisFormular formular, BindingResult pruefung,
Model model, Principal angemeldet) {
if (!pruefung.hasErrors()) {
hinweisService.legeAn(formular.getText(), formular.getHaltepunkt(), formular.getBis(),
formular.getWichtigkeit());
model.addAttribute("meldung", "hinweis.gespeichert");
model.addAttribute("formular", new HinweisFormular());
}
model.addAttribute("angemeldet", angemeldet.getName());
model.addAttribute("hinweise", hinweisService.alle());
model.addAttribute("haltepunkte", haltepunkte.findAll());
return "verwaltung/hinweise";
}Alle Tests aus dem Artikel bis auf einen waren grün. Bei der Sichtprüfung im Foyer steht „Linie 61 fällt morgen aus.“ zweimal auf dem Monitor. Heike Brinkmann erzählt: „Nach dem Speichern sah die Liste komisch aus, da habe ich F5 gedrückt. Der Browser hat etwas gefragt, und ich habe auf ‚Weiter‘ geklickt.“
a) Erkläre anhand der HTTP-Anfragen, wie der zweite Hinweis entstanden ist. (3 Punkte)
Die Methode antwortet auf den POST direkt mit 200 OK und der Seite (1 Punkt). Für den Browser ist damit der POST die letzte Anfrage; F5 wiederholt ihn, nach der Rückfrage „Formular erneut senden?“ mit denselben Daten (1 Punkt). Der Controller prüft und speichert ein zweites Mal, weil nichts den zweiten POST vom ersten unterscheidet (1 Punkt).
b) Korrigiere die Methode. (3 Punkte)
Post-Redirect-Get wie im Artikel: bei Fehlern Seite mit Formular, sonst speichern, Flash-Attribut, Umleitung.
@PostMapping
public String anlegen(@Valid @ModelAttribute("formular") HinweisFormular formular, BindingResult pruefung,
Model model, Principal angemeldet, RedirectAttributes weiterleitung) {
if (pruefung.hasErrors()) {
model.addAttribute("angemeldet", angemeldet.getName());
model.addAttribute("hinweise", hinweisService.alle());
model.addAttribute("haltepunkte", haltepunkte.findAll());
return "verwaltung/hinweise";
}
hinweisService.legeAn(formular.getText(), formular.getHaltepunkt(), formular.getBis(),
formular.getWichtigkeit());
weiterleitung.addFlashAttribute("meldung", "hinweis.gespeichert");
return "redirect:/verwaltung/hinweise";
}Bewertung: Umleitung nach dem Speichern (1 Punkt), Meldung als Flash-Attribut (1 Punkt), Fehlerfall weiter ohne Umleitung (1 Punkt).
c) Oksana Melnyk hatte vorher eine andere Korrektur versucht (Fassung B, absichtlich fehlerhaft). Damit gibt es keine doppelten Hinweise mehr, aber zwei neue Beschwerden: Die Meldung „Hinweis gespeichert.“ erscheint nie, und wer das Datum vergisst, steht vor einem leeren Formular ohne jede Meldung. Erkläre beide Ursachen. (4 Punkte)
@PostMapping
public String anlegen(@Valid @ModelAttribute("formular") HinweisFormular formular, BindingResult pruefung,
Model model) {
if (pruefung.hasErrors()) {
return "redirect:/verwaltung/hinweise";
}
hinweisService.legeAn(formular.getText(), formular.getHaltepunkt(), formular.getBis(),
formular.getWichtigkeit());
model.addAttribute("meldung", "hinweis.gespeichert");
return "redirect:/verwaltung/hinweise";
}Meldung: Bei einer Umleitung verwirft Spring MVC das Model; die GET-Anfrage danach ist ein neuer Request mit neuem Model, in dem meldung fehlt (1 Punkt). Abhilfe: RedirectAttributes als Parameter und addFlashAttribute("meldung", …) (1 Punkt).
Leeres Formular: Auch bei Fehlern leitet die Methode um. Formular-Objekt mit den Eingaben und BindingResult mit den Meldungen gehören zum POST-Request und sind nach der Umleitung weg; die GET-Methode legt ein neues, leeres Formular ins Model (1 Punkt). Abhilfe: bei Fehlern nicht umleiten, sondern die Seite direkt zurückgeben, wie in b) (1 Punkt).
d) Beschreibe einen Test, der Fassung A schon vor der Sichtprüfung als fehlerhaft erkannt hätte, und gib die entscheidende Prüfung als Code an. (3 Punkte)
Ein @WebMvcTest schickt einen gültigen POST mit csrf() und erwartet eine Umleitung statt einer Seite (1 Punkt). Fassung A antwortet mit 200, der Test schlägt fehl (1 Punkt):
assertThat(mvc.post().uri("/verwaltung/hinweise").with(csrf())
.param("text", "Linie 61 fällt morgen aus.").param("bis", MORGEN.toString()).param("wichtigkeit", "WARNUNG"))
.hasStatus(HttpStatus.FOUND)
.hasRedirectedUrl("/verwaltung/hinweise");Für Fassung B ergänzt .flash().containsEntry("meldung", "hinweis.gespeichert") die Prüfung der Meldung, und ein zweiter Test mit ungültigen Eingaben erwartet Status 200 und die Meldung im HTML (1 Punkt). Der Test mit der Erwartung 302 Found (im Artikel gueltigerHinweisWirdGespeichertUndUmgeleitet) war der, der bei Jonas als einziger rot war; das Team hatte ihn für „zu streng“ gehalten.
e) Die Story MON-07 war im Sprint Backlog schon als „fertig“ markiert, und auf dem Monitor stehen zwei gleiche Hinweise. Nimm Stellung, wie das Team mit Story und Daten umgehen soll. (2 Punkte)
Ein roter Test verstößt gegen die Definition of Done; MON-07 war also nicht fertig und wird zurückgesetzt, bis Korrektur und Test grün sind, noch im laufenden Sprint, weil der Fehler klein ist (1 Punkt). Den doppelten Hinweis löscht Heike Brinkmann über die Verwaltungsseite; einen Datenbankeingriff braucht es nicht. In der Retrospektive lohnt die Frage, warum ein roter Test als „zu streng“ übergangen werden konnte (1 Punkt).
Links und weitere Informationen
zum Artikel: Formulare mit Thymeleaf: Die Schulverwaltung legt Hinweise für den Flurmonitor an
als Grundlage: Integrationstest der Web-Schicht und HTML-Grundlagen (Formulare)
zum Szenario: Szenario Mitfahrlabor mit Personas und Flurmonitoren
als Nachschlagewerk: Tutorial: Thymeleaf + Spring, Kapitel Creating a Form
als Nachschlagewerk: Spring Security Reference: Testing with CSRF Protection
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 Formularen mit Thymeleaf: ein Mitfahrgesuch zurückziehen” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/flurmonitor-hinweise-formulare-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]
