Übungsaufgaben zum Projekt und ersten Endpunkt: Mitfahrgesuche abrufen

https://bildung.social/@oerinformatik/

https://oer-informatik.de/spring-boot-projekt-anlegen-uebungsaufgaben

Spring Boot, REST-Controller, Annotationen, Record, Projektstruktur, HTTP-Statuscodes, Fehlersuche, Query-Parameter, Übungsaufgaben, Prüfungsvorbereitung

tl/dr; (ca. 39 min Lese- und Bearbeitungszeit): Übungen zum Spring-Boot-Projekt des Mitfahr-Backends: Du ordnest Annotationen und Dateien zu, schreibst einen Controller für Mitfahrgesuche mit Record und Pfadvariable, sagst Antworten auf Anfragen voraus, findest Fehler in einem Controller anhand ihrer Symptome und ergänzt einen Filter über einen Query-Parameter [AI-Assisted]. (Zuletzt geändert am 11.11.2026)

Dieser Artikel ist Teil einer Artikelreihe über ein REST-Backend mit Spring Boot: Überblick und Fahrplan / 01 Anforderungen und API-Vertrag / 02 Projekt anlegen / Übungsaufgaben zu 02

Diese Übungsaufgaben gehören zum Artikel Das Projekt anlegen: der erste Endpunkt für das Mitfahrlabor-Backend. Sie setzen den Übungsstrang zu den Mitfahrgesuchen aus den Übungen zu Artikel 01 fort. Als Ausgangspunkt eignet sich das Projekt im Ordner src/02-projekt-anlegen des Repositorys.

Fahrplan der Artikelreihe im V-Modell, hervorgehoben ist die Implementierung, zu der Artikel 02 gehört (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 und Aufgabe 3.2) keine Probleme bereiten. Notiere Deine Antworten zuerst vollständig, bevor Du die Beispiellösung aufklappst. Den Code kannst Du im Projekt aus dem Repository ausprobieren; andere fachlich richtige Lösungen sind 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 „Das Projekt anlegen:
Mitfahrgesuche abrufen“.

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/spring-boot-projekt-anlegen
- https://oer-informatik.de/rest-grundlagen
- Stilbeispiel: https://oer-informatik.de/spring-boot-projekt-anlegen-uebungsaufgaben

Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Spring Boot
- REST-Controller
- Annotationen
- Record
- Projektstruktur
- HTTP-Statuscodes
- Fehlersuche
- Query-Parameter

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: Annotationen zuordnen (Basiskompetenz)

Ordne jeder Annotation ihre Aufgabe im Mitfahrlabor-Backend zu. (5 Punkte)

Annotationen in einem Spring-Boot-Controller
Annotation Aufgabe
@SpringBootApplication
@RestController
@RequestMapping("/v1/gesuche")
@GetMapping("/{gesuchId}")
@PathVariable

Je Zeile 1 Punkt:

Annotation Aufgabe
@SpringBootApplication kennzeichnet die Startklasse; schaltet Komponentenscan im eigenen Paket und darunter sowie die Autokonfiguration ein
@RestController macht die Klasse zu einer Bean, die HTTP-Anfragen beantwortet; Rückgabewerte werden als JSON in den Body geschrieben
@RequestMapping("/v1/gesuche") legt den gemeinsamen Pfad aller Methoden der Klasse fest
@GetMapping("/{gesuchId}") ordnet die Methode GET-Anfragen auf /v1/gesuche/{gesuchId} zu
@PathVariable übergibt den Wert aus dem Platzhalter des Pfads an den gleichnamigen Parameter

Aufgabe 1.2: Dateien im Projekt finden (Basiskompetenz)

Das Projektteam ergänzt das Backend um Mitfahrgesuche. Gib für jede Datei den Ordner im Projekt mitfahrlabor an, in den sie gehört. (5 Punkte)

Neue Dateien und Änderungen für die Mitfahrgesuche
Datei Ordner
GesuchController.java (Paket de.dbh.mitfahrlabor.web)
GesuchControllerTest.java (Paket de.dbh.mitfahrlabor.web)
application.properties mit server.port=8081
gesuche.http mit Testanfragen für die Entwicklungsumgebung
neue Abhängigkeit für die Datenbank (Gradle)

Je Zeile 1 Punkt:

Datei Ordner
GesuchController.java src/main/java/de/dbh/mitfahrlabor/web/
GesuchControllerTest.java src/test/java/de/dbh/mitfahrlabor/web/
application.properties src/main/resources/ (die Datei gibt es schon, die Zeile wird ergänzt)
gesuche.http Projektordner mitfahrlabor/ (neben haltepunkte.http)
Abhängigkeit für die Datenbank keine eigene Datei: Zeile im Block dependencies von build.gradle.kts im Projektordner

Aufgabe 2.1: Einen Controller für Gesuche schreiben (Kernkompetenz)

Bis die Datenbank angebunden ist, sollen die Gesuche wie die Haltepunkte in einer Liste im Controller stehen. Ein Gesuch hat eine id, die haltepunktId, die richtung (zur-schule oder nach-hause), das datum und ein Zeitfenster aus zeitVon und zeitBis (jeweils HH:MM). Für den Anfang genügen diese drei Gesuche, alle für Montag, 23.11.2026:

Startdaten der Gesuche
id Haltepunkt Richtung von bis
1 1 zur-schule 06:45 07:15
2 3 zur-schule 07:00 07:20
3 1 nach-hause 15:00 16:00

a) Notiere einen Record GesuchDto im Paket de.dbh.mitfahrlabor.web. Wähle für das Datum einen passenden Java-Typ. (3 Punkte)

package de.dbh.mitfahrlabor.web;

import java.time.LocalDate;

public record GesuchDto(long id, long haltepunktId, String richtung, LocalDate datum,
        String zeitVon, String zeitBis) {
}

Bewertung: Record mit allen sechs Komponenten (2 Punkte), LocalDate für das Datum (1 Punkt). Jackson schreibt ein LocalDate als Text im Format "2026-11-23", so wie es der Vertrag mit format: date verlangt. Für die Uhrzeiten ist auch LocalTime richtig.

b) Notiere die Klasse GesuchController mit den Endpunkten GET /v1/gesuche (alle Gesuche) und GET /v1/gesuche/{gesuchId} (ein Gesuch oder 404 Not Found). (8 Punkte)

package de.dbh.mitfahrlabor.web;

import java.time.LocalDate;
import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/gesuche")
public class GesuchController {

    private final List<GesuchDto> gesuche = List.of(
            new GesuchDto(1, 1, "zur-schule", LocalDate.of(2026, 11, 23), "06:45", "07:15"),
            new GesuchDto(2, 3, "zur-schule", LocalDate.of(2026, 11, 23), "07:00", "07:20"),
            new GesuchDto(3, 1, "nach-hause", LocalDate.of(2026, 11, 23), "15:00", "16:00"));

    @GetMapping
    public List<GesuchDto> listeGesuche() {
        return gesuche;
    }

    @GetMapping("/{gesuchId}")
    public ResponseEntity<GesuchDto> holeGesuch(@PathVariable long gesuchId) {
        return gesuche.stream()
                .filter(g -> g.id() == gesuchId)
                .findFirst()
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
}

Bewertung: @RestController und @RequestMapping mit Pfad (2 Punkte), Liste mit den drei Gesuchen (1 Punkt), Methode für alle Gesuche mit @GetMapping (1 Punkt), Methode für ein Gesuch mit Platzhalter und @PathVariable (2 Punkte), Rückgabe 200 mit Gesuch bzw. 404 über ResponseEntity (2 Punkte). Eine Schleife statt des Streams ist ebenso richtig.

Aufgabe 2.2: Antworten vorhersagen (Kernkompetenz)

Die Anwendung mit dem Controller aus Aufgabe 2.1 läuft auf Port 8080. Gib für jede Anfrage den Statuscode und den Inhalt des Bodys an. (6 Punkte)

  1. GET http://localhost:8080/v1/gesuche/2
  2. GET http://localhost:8080/v1/gesuche/7
  3. GET http://localhost:8080/v1/gesuche/zwei
  4. GET http://localhost:8080/v1/gesuch/2
  1. 200 OK, Body {"id":2,"haltepunktId":3,"richtung":"zur-schule","datum":"2026-11-23","zeitVon":"07:00","zeitBis":"07:20"} (2 Punkte: Code und Body)
  2. 404 Not Found, kein Body, weil ResponseEntity.notFound().build() keinen Inhalt hat (1 Punkt)
  3. 400 Bad Request: zwei lässt sich nicht in ein long umwandeln, Spring antwortet, bevor die Methode aufgerufen wird; im Body steht eine Fehlerbeschreibung von Spring mit "status":400 (2 Punkte: Code und Begründung)
  4. 404 Not Found: Für den Pfad /v1/gesuch (ohne e) gibt es keinen Controller; Spring liefert eine Fehlerbeschreibung mit "status":404 (1 Punkt)

Aufgabe 3.1: Fehler anhand der Symptome finden (Profilkompetenz)

Ein Teammitglied hat seinen eigenen GesuchController geschrieben. Die Anwendung startet ohne Fehlermeldung, aber die Anfragen liefern seltsame Antworten.

package de.dbh.gesuche;

import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import de.dbh.mitfahrlabor.web.GesuchDto;

@RestController
@RequestMapping("/v1/gesuche")
public class GesuchController {

    private final List<GesuchDto> gesuche = List.of(/* drei Gesuche wie in Aufgabe 2.1 */);

    @GetMapping
    public List<GesuchDto> listeGesuche() {
        return gesuche;
    }

    @GetMapping("/{id}")
    public GesuchDto holeGesuch(@PathVariable long gesuchId) {
        return gesuche.stream()
                .filter(g -> g.id() == gesuchId)
                .findFirst()
                .orElse(null);
    }
}

a) Jede Anfrage an /v1/gesuche beantwortet die Anwendung mit 404 Not Found, obwohl der Pfad stimmt. Erläutere die Ursache und korrigiere sie. (3 Punkte)

Die Klasse liegt im Paket de.dbh.gesuche. Der Komponentenscan von @SpringBootApplication durchsucht nur das Paket der Startklasse de.dbh.mitfahrlabor und dessen Unterpakete (1 Punkt). Der Controller wird deshalb nie als Bean angelegt, und es gibt keinen Endpunkt für den Pfad (1 Punkt). Korrektur: Klasse ins Paket de.dbh.mitfahrlabor.web verschieben, package-Zeile anpassen (1 Punkt).

Nach der Korrektur aus a) liefert GET /v1/gesuche die Liste. Es bleiben zwei Probleme:

b) GET /v1/gesuche/1 endet mit 500 Internal Server Error. Im Log steht: MissingPathVariableException: Required URI template variable 'gesuchId' for method parameter type long is not present. Erläutere die Ursache und gib zwei verschiedene Korrekturen an. (4 Punkte)

Der Platzhalter im Pfad heißt {id}, der Parameter gesuchId. @PathVariable ohne Angabe sucht einen Platzhalter mit dem Namen des Parameters und findet ihn nicht (2 Punkte). Korrekturen (je 1 Punkt):

  • Pfad anpassen: @GetMapping("/{gesuchId}")
  • Namen angeben: @PathVariable("id") long gesuchId

c) GET /v1/gesuche/7 liefert 200 OK mit leerem Body. Erläutere, warum das nicht zum API-Vertrag passt, und korrigiere die Methode. (3 Punkte)

Für ein unbekanntes Gesuch gibt die Methode null zurück. Spring sendet dann 200 OK ohne Body; der Client hält die Anfrage für erfolgreich, obwohl es das Gesuch nicht gibt. Der Vertrag verlangt 404 Not Found (1 Punkt). Korrektur mit ResponseEntity (2 Punkte):

@GetMapping("/{gesuchId}")
public ResponseEntity<GesuchDto> holeGesuch(@PathVariable long gesuchId) {
    return gesuche.stream()
            .filter(g -> g.id() == gesuchId)
            .findFirst()
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
}

Aufgabe 3.2: Gesuche nach Richtung filtern (Profilkompetenz)

Die Flurmonitore sollen morgens nur Gesuche in Richtung Schule zeigen. Dafür soll GET /v1/gesuche?richtung=zur-schule nur die passenden Gesuche liefern. Ohne den Parameter bleibt es bei allen Gesuchen.

a) Ändere die Methode listeGesuche() aus Aufgabe 2.1 entsprechend. Nutze die Annotation @RequestParam. (4 Punkte)

@GetMapping
public List<GesuchDto> listeGesuche(@RequestParam(required = false) String richtung) {
    if (richtung == null) {
        return gesuche;
    }
    return gesuche.stream()
            .filter(g -> g.richtung().equals(richtung))
            .toList();
}

Dazu der Import org.springframework.web.bind.annotation.RequestParam. Bewertung: @RequestParam mit required = false (2 Punkte), Fall ohne Parameter (1 Punkt), Filter mit Stream oder Schleife (1 Punkt).

b) Begründe, warum die Richtung hier als Query-Parameter übergeben wird und nicht als Teil des Pfads wie bei /v1/gesuche/{gesuchId}. (2 Punkte)

Der Pfad bezeichnet eine Ressource: /v1/gesuche/2 ist genau ein Gesuch. Die Richtung wählt dagegen nur einen Teil der Sammlung /v1/gesuche aus und ist ein Filter, der fehlen oder mit anderen Filtern wie dem Datum kombiniert werden kann (1 Punkt). Als Query-Parameter bleibt die Adresse der Sammlung gleich, und Filter lassen sich in beliebiger Reihenfolge ergänzen (1 Punkt).


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 zum Projekt und ersten Endpunkt: Mitfahrgesuche abrufen” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/spring-boot-projekt-anlegen-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: