- Direkte Fortsetzung von Teil 1; heute wird aus den Einzelteilen ein durchgehendes Back-End
- Ziel: Nach der Vorlesung kann jedes Team das Back-End seines MVP Schicht fuer Schicht bauen
- Aufbau erklaeren: erst das Ziel (API-Vertrag), dann von unten nach oben bauen
- Reihenfolge entspricht der Reihenfolge, in der man eine Ressource im Projekt tatsaechlich umsetzt
- Kurz abfragen: Wer hat im Praktikum schon ein Spring-Projekt angelegt?
- Thymeleaf aus Teil 1 bleibt legitim; heute geht es um die JSON-Variante, weil die meisten Front-Ends per fetch zugreifen
- Tabelle ist die Bruecke zur REST-Vorlesung: Ressourcen als Nomen, Verben, Statuscodes
- Jede Zeile taucht heute als Controller-Methode wieder auf; die Fehlercodes kommen aus Abschnitt 6
- Tipp fuers Projekt: diese Tabelle gehoert ins Repo (z.B. docs/api.md), am besten mit Beispiel-JSON
- Schichten kennen sie aus Teil 1 abstrakt; neu ist, welcher Datentyp an welcher Grenze liegt
- Package-by-Feature: bei 6er-Teams weniger Merge-Konflikte als ein grosses controller/-Paket
- Grundlagen (@Entity, @Id, JpaRepository) sind aus Teil 1 bekannt
- Heute: was man fuer ein echtes Domaenenmodell zusaetzlich braucht, v.a. Beziehungen
- Ordinal-Falle: neuer Enum-Wert in der Mitte verschiebt alle gespeicherten Zahlen
- Konstruktor setzt den Startzustand OPEN; keine oeffentlichen Setter fuer alles, sondern fachliche Methoden wie update(...)
- TaskStatus ist ein einfaches enum { OPEN, IN_PROGRESS, DONE }
- Abgeleitete Queries kennen sie aus Teil 1; hier nur die Navigation ueber Beziehungen (TeamId → team.id)
- Bidirektional nur, wenn ihr die Gegenseite wirklich braucht; unidirektional ManyToOne reicht oft
- Uebergang: die Warnung fuehrt direkt in den naechsten Abschnitt
- DTO = Data Transfer Object; Frage an den Hoersaal: warum nicht einfach die Entity zurueckgeben?
- Over-Posting ist eine echte Sicherheitsluecke (OWASP: Mass Assignment)
- Lazy: mit open-in-view=false (Abschnitt 7) knallt ein Zugriff auf eine nicht geladene Beziehung im Controller
- Kopplung: DTO ist der stabile Vertrag aus der Tabelle vom Anfang
- Eine Datei pro Record im Paket task/dto; hier nur zusammen gezeigt
- Mapping per statischer Fabrikmethode reicht fuer das MVP; MapStruct erst bei vielen DTOs erwaehnen
- t.getTeam().getId() loest bei Hibernate kein Nachladen aus, die Id steckt schon im Proxy
- Haeufigster Fehler im Praktikum: Annotationen gesetzt, Starter vergessen, Validierung laeuft nie
- Fehlermeldungen kommen lokalisiert aus Hibernate Validator (z.B. "darf nicht leer sein"), eigene per message = "..."
- Uebergang: die Unterscheidung Form vs. Regel entscheidet spaeter ueber 400 vs. 409
- Erwartung: id, Erstellzeitpunkt, Besitzer, Status werden serverseitig gesetzt und fehlen im Create-Request
- Response darf abgeleitete Felder enthalten (z.B. teamName, istUeberfaellig)
- Zwei, drei Teams ihre Records kurz vorlesen lassen; typische Constraints: @NotBlank, @Size, @Positive, @Future
- Der Service ist die Schicht, die das Projekt fachlich ausmacht; Controller und Repository sind eher Adapter
- Service nimmt Request-DTOs an und gibt Response-DTOs zurueck: Entities verlassen die Service-Schicht nicht
- NotFoundException/ConflictException sind eigene RuntimeExceptions, Abschnitt 6 macht Statuscodes daraus
- Der Service kennt kein HTTP: kein ResponseEntity, kein HttpStatus
- Import: org.springframework.transaction.annotation.Transactional (nicht die jakarta-Variante)
- Deshalb eigene Exceptions als RuntimeException: der Rollback ist dann automatisch richtig
- Proxy-Falle anhand der DI-Vorlesung erklaeren: Spring reicht einen Wrapper statt des Originals herein
- Genau diese Punkte stehen in den Bewertungskriterien unter Schichtentrennung
- Bei Code-Reviews im Team gezielt nach diesen Symptomen suchen
- Jetzt die Tabelle vom Anfang Zeile fuer Zeile umsetzen
- Vergleich zu Teil 1: kein Model, kein View-Name, der Rueckgabewert ist die Antwort
- Demo: curl -i http://localhost:8080/api/tasks/1 zeigt Header und JSON
- 201 + Location-Header ist die REST-Konvention fuer "angelegt", siehe REST-Vorlesung
- Achtung: deleteById ignoriert unbekannte Ids stillschweigend; der Service prueft vorher existsById und wirft NotFoundException
- CORS = Cross-Origin Resource Sharing; Ursprung = Schema + Host + Port
- Fuers MVP ist der gleiche Ursprung am einfachsten; CORS nur, wenn ihr bewusst getrennt entwickelt
- Kein allowedOrigins("*") in Produktion; @CrossOrigin am Controller geht auch, global ist uebersichtlicher
- Ohne Fehlerbehandlung liefert Spring bei jeder Exception 500; das Front-End kann nichts damit anfangen
- Eigene Exceptions sind fachlich benannt, nicht nach HTTP (NotFound ist hier bewusst neutral genug)
- ConflictException analog aufgebaut; 500 nie mit Stacktrace an den Client
- Statuscodes aus der REST-Vorlesung: 4xx = Client hat etwas falsch gemacht, 5xx = Server
- Ein Advice fuer alle Controller: keine try/catch-Bloecke im Controller
- title und instance fuellt Spring selbst aus
- @Order ist noetig, weil spring.mvc.problemdetails.enabled=true (Abschnitt 7) einen eigenen Advice registriert, der sonst MethodArgumentNotValidException abfaengt (naechste Folie); mit Spring Boot 4.1 so getestet
- Methode gehoert in denselben GlobalExceptionHandler
- setProperty haengt beliebige Zusatzfelder an das ProblemDetail an
- Sprache der Meldungen folgt dem Accept-Language-Header des Browsers ("darf nicht leer sein" bei de)
- Lokal H2, spaeter PostgreSQL: der Code bleibt gleich, nur die Konfiguration wechselt
- Binding ist tolerant: max-tasks-per-team wird zu maxTasksPerTeam
- Der Record wird wie jede Bean per Konstruktor in den Service injiziert
- open-in-view ist per Default an und verdeckt Lazy-Loading-Probleme; Spring warnt beim Start selbst davor
- Profilspezifische Dateien werden zusaetzlich zur application.properties geladen und ueberschreiben sie
- ddl-auto=create-drop nur mit Wegwerfdaten; in prod validate plus Migrationen (Flyway), sobald echte Daten da sind
- Spring Boot 4: H2-Konsole braucht zusaetzlich die Abhaengigkeit spring-boot-h2console; @Profile("dev") an einer Bean fuer Testdaten
- Nur ein Ausblick; die Grundlagen des Testens vertieft die SWT-Vorlesung Testen
- Spring Boot 4: Test-Starter sind modular, z.B. spring-boot-starter-webmvc-test und spring-boot-starter-data-jpa-test
- @MockBean gibt es in Boot 4 nicht mehr, Nachfolger ist @MockitoBean aus Spring Framework
- Service-Unit-Test: Repositories per Mockito mocken, Konstruktor direkt aufrufen, kein Spring noetig
- @WebMvcTest laedt Controller und @RestControllerAdvice, der Service ist ein Mock: der Test prueft genau Routing, Validierung und Fehlerabbildung
- Zweiter Test erreicht den Service gar nicht, weil @Valid vorher abbricht
- MockMvcTester ist die AssertJ-Variante von MockMvc; in aelteren Tutorials steht mockMvc.perform(...).andExpect(...)
- Kurz den Weg Datenbank → JSON noch einmal an der Flow-Folie zeigen
- Praktikum: erster Durchstich als Ziel fuer den Zwischenstand
- Fragen sammeln; Security kennen sie aus Teil 1, Deployment behandelt die SWT-Vorlesung Deployment