Woche 4, Tag 1 — Spring MVC Mental Model: DispatcherServlet, Controller, HandlerMapping und REST-Flow
Ziel
Heute verstehst du den Spring-MVC-Request-Flow.
Die Kernfragen:
- Was ist Spring MVC?
- Welches Problem löst Spring MVC?
- Was ist
DispatcherServlet? - Warum heißt
DispatcherServletFront Controller? - Was ist ein Controller?
- Was ist
HandlerMapping? - Was ist
HandlerAdapter? - Was ist der Unterschied zwischen
@Controllerund@RestController? - Wie wird aus einem HTTP-Request ein Java-Methodenaufruf?
- Wie wird aus einem Java-Objekt JSON?
- Welche typischen Prüfungsfallen gibt es?
1. Kurz-Wiederholung aus Woche 3
In Woche 3 hast du gelernt:
- Spring Boot macht Spring einfacher zu konfigurieren, auszuführen, zu überwachen und zu deployen.
@SpringBootApplicationenthält:
@Configuration
@EnableAutoConfiguration
@ComponentScan
- Starters bringen Dependencies.
- Auto-Configuration konfiguriert Beans.
- Actuator hilft, eine laufende Anwendung zu überwachen.
SpringApplication.run(...)startet die Anwendung.
Merksatz:
Spring Boot startet die App und auto-konfiguriert gängige Infrastruktur.
Heute lernst du eine der wichtigsten Infrastrukturen in Web-Apps:
Spring MVC
2. Was ist Spring MVC?
Spring MVC ist das Spring-Framework-Modul zum Bau von Web-Anwendungen.
MVC steht für:
Model
View
Controller
In modernen REST APIs nutzt du Spring MVC oft ohne klassische serverseitig gerenderte Views.
Einfache Definition:
Spring MVC verarbeitet HTTP-Requests und mappt sie auf Java-Controller-Methoden.
Beispiel:
HTTP-Request:
GET /api/tasks
Java-Methode:
@GetMapping("/api/tasks")
public List<TaskDto> getTasks() {
return taskService.findAll();
}
Spring MVC verbindet diese beiden Welten.
3. Welches Problem löst Spring MVC?
Ohne Spring MVC müsstest du manuell handhaben:
HTTP-Routing
Request-Parsing
Query-Parameter
Path Variables
JSON-Request-Body-Parsing
JSON-Response-Schreiben
Status Codes
Header
Validation
Exception Handling
Content Negotiation
Spring MVC gibt dir einen strukturierten Weg, Web-Endpunkte zu schreiben.
Statt Low-Level-Servlet-Requests manuell zu parsen, schreibst du:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping
public List<TaskDto> listTasks() {
return List.of();
}
}
Merksatz:
Spring MVC mappt HTTP-Requests auf Java-Methoden und Java-Rückgabewerte zurück auf HTTP-Responses.
4. Spring MVC in einer Spring-Boot-App
In Spring Boot fügst du normalerweise hinzu:
implementation("org.springframework.boot:spring-boot-starter-web")
Das bringt:
Spring MVC
embedded Tomcat
Jackson JSON support
web auto-configuration
HTTP message converters
Dann auto-konfiguriert Spring Boot Spring MVC.
Du kannst Controller schreiben, ohne DispatcherServlet manuell zu konfigurieren.
5. Der große Request-Flow
Wenn ein Request reinkommt:
GET /api/tasks/123
Spring-MVC-Flow:
1. Client sendet HTTP-Request.
2. Embedded Tomcat empfängt ihn.
3. Request geht an DispatcherServlet.
4. DispatcherServlet fragt HandlerMapping: Welche Controller-Methode soll das handhaben?
5. HandlerAdapter ruft die Controller-Methode auf.
6. Controller ruft die Service-Schicht auf.
7. Service liefert Daten zurück.
8. Controller gibt ein Java-Objekt zurück.
9. HttpMessageConverter konvertiert das Java-Objekt zu JSON.
10. DispatcherServlet sendet die HTTP-Response.
Kurz-Merksatz:
Request -> DispatcherServlet -> HandlerMapping -> Controller -> Service -> JSON Response
6. Was ist DispatcherServlet?
DispatcherServlet ist das zentrale Servlet in Spring MVC.
Es empfängt eingehende HTTP-Requests und dispatcht sie an den richtigen Handler.
Einfache Definition:
DispatcherServletist der Front Controller von Spring MVC.
Es koordiniert den Request-Flow.
Es enthält nicht deine Business-Logik.
Es delegiert an andere Components.
7. Warum heißt es Front Controller?
Front Controller bedeutet:
Ein zentraler Einstiegspunkt empfängt Requests und delegiert sie an den richtigen Handler.
Statt dass jeder Controller Requests direkt empfängt, gehen Requests zuerst durch:
DispatcherServlet
Mental Model:
Client
↓
DispatcherServlet
↓
Richtige Controller-Methode
Merksatz:
DispatcherServletist der zentrale Einstiegspunkt für Spring-MVC-Requests.
8. Was macht DispatcherServlet?
DispatcherServlet koordiniert viele Dinge:
findet die richtige Handler-Methode
ruft den Handler über HandlerAdapter auf
verarbeitet Request-Parameter und Path Variables
arbeitet mit Message Converters
handhabt Exceptions
wählt Views in klassischem MVC
schreibt REST-Responses
koordiniert Interceptors
gibt HTTP-Response zurück
Wichtig:
DispatcherServletkoordiniert den Flow, macht aber nicht alles selbst.
9. Was ist ein Controller?
Ein Controller ist eine Spring Bean, die Web-Requests handhabt.
Beispiel:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping
public List<String> getTasks() {
return List.of("Task 1", "Task 2");
}
}
Dieser Controller handhabt:
GET /api/tasks
Einfache Definition:
Ein Controller enthält Methoden, die HTTP-Requests handhaben.
10. Controller sollten schlank sein
Ein Controller sollte normalerweise schlank sein.
Verantwortlichkeiten eines Controllers:
HTTP-Request empfangen
Request-Daten lesen
Service-Schicht aufrufen
Response-DTO zurückgeben
Status Code wählen
Ein Controller sollte keine schwere Business-Logik enthalten.
Schlecht:
@RestController
public class InvoiceController {
@PostMapping("/api/invoices")
public Invoice create(@RequestBody CreateInvoiceRequest request) {
// 200 lines of tax calculation here
// database logic here
// email sending here
return invoice;
}
}
Besser:
@RestController
@RequestMapping("/api/invoices")
public class InvoiceController {
private final InvoiceService invoiceService;
public InvoiceController(InvoiceService invoiceService) {
this.invoiceService = invoiceService;
}
@PostMapping
public InvoiceDto create(@RequestBody CreateInvoiceRequest request) {
return invoiceService.create(request);
}
}
Merksatz:
Controller handhaben HTTP. Services handhaben Business-Logik.
11. Was ist @RequestMapping?
@RequestMapping mappt HTTP-Requests auf Controller-Klassen oder -Methoden.
Mapping auf Klassenebene:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
}
Mapping auf Methodenebene:
@GetMapping("/{id}")
public TaskDto getTask(@PathVariable Long id) {
return taskService.findById(id);
}
Kombinierter Pfad:
GET /api/tasks/{id}
12. Shortcut-Mapping-Annotationen
Statt zu schreiben:
@RequestMapping(method = RequestMethod.GET)
bietet Spring Shortcuts:
@GetMapping
@PostMapping
@PutMapping
@PatchMapping
@DeleteMapping
Beispiele:
@GetMapping("/tasks")
@PostMapping("/tasks")
@PutMapping("/tasks/{id}")
@PatchMapping("/tasks/{id}")
@DeleteMapping("/tasks/{id}")
Diese passen zu HTTP-Methoden.
13. REST-Beispiel
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping
public List<TaskDto> list() {
return taskService.findAll();
}
@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
@PostMapping
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
taskService.delete(id);
}
}
Mappings:
GET /api/tasks -> list()
GET /api/tasks/123 -> get(123)
POST /api/tasks -> create(request)
DELETE /api/tasks/123 -> delete(123)
14. Was ist HandlerMapping?
HandlerMapping findet den richtigen Handler für einen Request.
Einfache Definition:
HandlerMappingmappt einen HTTP-Request auf eine Controller-Methode.
Beispiel-Request:
GET /api/tasks/123
Controller:
@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
}
HandlerMapping sagt:
Dieser Request soll von getTask(...) gehandhabt werden
Merksatz:
HandlerMappingbeantwortet: Welche Controller-Methode soll diesen Request handhaben?
15. Was ist HandlerAdapter?
HandlerAdapter ruft die ausgewählte Handler-Methode auf.
Einfache Definition:
HandlerAdapterweiß, wie die vonHandlerMappingausgewählte Controller-Methode aufgerufen wird.
Warum nötig?
Weil Spring MVC verschiedene Handler-Arten unterstützt.
DispatcherServlet weiß nicht direkt, wie jeder mögliche Handler-Typ aufgerufen wird.
Deshalb delegiert es den Aufruf an einen HandlerAdapter.
Merksatz:
HandlerMappingfindet die Methode.HandlerAdapterruft die Methode auf.
16. HandlerMapping vs. HandlerAdapter
| Component | Aufgabe |
|---|---|
HandlerMapping | findet den Handler für den Request |
HandlerAdapter | ruft den Handler auf |
DispatcherServlet | koordiniert den gesamten Flow |
Merksatz für die Prüfung:
Mapping finds.
Adapter invokes.
Dispatcher coordinates.
17. Was ist ein Handler?
In Spring MVC ist ein Handler normalerweise eine Controller-Methode.
Beispiel:
@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
return taskService.findById(id);
}
Diese Methode ist der Handler für:
GET /api/tasks/{id}
Wenn Spring MVC „Handler“ sagt, denk an:
Controller-Methode
Meistens.
18. Was ist @Controller?
@Controller markiert eine Klasse als Spring-MVC-Controller.
Beispiel:
@Controller
public class PageController {
@GetMapping("/home")
public String home() {
return "home";
}
}
In klassischem MVC bedeutet die Rückgabe von "home":
Rendere die View namens home.
Zum Beispiel:
templates/home.html
19. Was ist @RestController?
@RestController wird für REST APIs genutzt.
Beispiel:
@RestController
public class TaskController {
@GetMapping("/api/tasks")
public List<String> tasks() {
return List.of("Task 1", "Task 2");
}
}
Der Rückgabewert wird direkt in den HTTP-Response-Body geschrieben.
Diese Java-Liste wird also zu JSON.
Merksatz:
@RestControllergibt Daten zurück, keine Views.
20. @RestController = @Controller + @ResponseBody
Sehr wichtiger Prüfungssatz:
@RestController = @Controller + @ResponseBody
Bedeutung:
@RestController
public class TaskController {
}
ist konzeptionell ähnlich zu:
@Controller
@ResponseBody
public class TaskController {
}
@ResponseBody bedeutet:
Schreibe den Methoden-Rückgabewert direkt in den HTTP-Response-Body.
21. @Controller vs. @RestController
| Thema | @Controller | @RestController |
|---|---|---|
| Typischer Einsatz | serverseitig gerenderte Views | REST APIs |
| String-Rückgabe | View-Name | Response-Body-Text |
| JSON-Response | braucht @ResponseBody | automatisch |
Enthält @ResponseBody | nein | ja |
Beispiel mit @Controller:
@Controller
public class PageController {
@GetMapping("/home")
public String home() {
return "home";
}
}
Spring sucht eine View namens:
home
Beispiel mit @RestController:
@RestController
public class ApiController {
@GetMapping("/api/hello")
public String hello() {
return "hello";
}
}
Spring gibt den Body zurück:
hello
22. Was ist @ResponseBody?
@ResponseBody sagt Spring:
Behandle den Rückgabewert nicht als View-Namen. Schreibe ihn direkt in den HTTP-Response-Body.
Beispiel:
@Controller
public class TaskController {
@GetMapping("/api/tasks")
@ResponseBody
public List<String> tasks() {
return List.of("Task 1", "Task 2");
}
}
Das liefert JSON.
Mit @RestController musst du @ResponseBody nicht auf jede Methode setzen.
23. Wie Java-Objekte zu JSON werden
Controller:
@GetMapping("/api/tasks")
public List<TaskDto> tasks() {
return List.of(
new TaskDto(1L, "Learn Spring MVC"),
new TaskDto(2L, "Practice REST")
);
}
DTO:
public record TaskDto(Long id, String title) {
}
Response:
[
{
"id": 1,
"title": "Learn Spring MVC"
},
{
"id": 2,
"title": "Practice REST"
}
]
Wer konvertiert das?
HttpMessageConverter
Normalerweise mit Jackson für JSON.
24. Was ist HttpMessageConverter?
HttpMessageConverter konvertiert zwischen HTTP-Body-Daten und Java-Objekten.
Zwei Richtungen:
HTTP-Request-Body -> Java-Objekt
Java-Objekt -> HTTP-Response-Body
Beispiel-Request:
{
"title": "Learn Spring"
}
Java-Objekt:
public record CreateTaskRequest(String title) {
}
Controller:
@PostMapping("/api/tasks")
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Spring nutzt einen HttpMessageConverter, um JSON in CreateTaskRequest zu konvertieren.
25. Jackson und JSON
In den meisten Spring-Boot-MVC-Apps übernimmt Jackson die JSON-Konvertierung.
Wenn du hinzufügst:
implementation("org.springframework.boot:spring-boot-starter-web")
bringt Spring Boot normalerweise Jackson-Support mit.
Deshalb funktioniert das:
@RestController
public class UserController {
@GetMapping("/api/users/1")
public UserDto getUser() {
return new UserDto(1L, "Steve");
}
}
Response:
{
"id": 1,
"name": "Steve"
}
Merksatz:
Jackson konvertiert Java-Objekte zu JSON und JSON zu Java-Objekten.
26. Was ist @RequestBody?
@RequestBody sagt Spring:
Lies den HTTP-Request-Body und konvertiere ihn in ein Java-Objekt.
Beispiel:
POST /api/tasks
Content-Type: application/json
{
"title": "Learn Spring MVC"
}
Controller:
@PostMapping("/api/tasks")
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Spring konvertiert JSON in:
CreateTaskRequest
27. Was ist @PathVariable?
@PathVariable liest einen Wert aus dem URL-Pfad.
Beispiel:
GET /api/tasks/123
Controller:
@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
return taskService.findById(id);
}
Spring bindet:
123 -> id
28. Benanntes @PathVariable
Wenn der Variablenname anders ist:
@GetMapping("/api/tasks/{taskId}")
public TaskDto getTask(@PathVariable("taskId") Long id) {
return taskService.findById(id);
}
Path Variable:
taskId
Java-Parameter:
id
Spring bindet taskId an id.
29. Was ist @RequestParam?
@RequestParam liest Query-Parameter.
Beispiel:
GET /api/tasks?page=0&size=20
Controller:
@GetMapping("/api/tasks")
public List<TaskDto> listTasks(
@RequestParam int page,
@RequestParam int size
) {
return taskService.findPage(page, size);
}
Spring bindet:
page=0 -> page
size=20 -> size
30. Optionales @RequestParam
Beispiel:
@GetMapping("/api/tasks")
public List<TaskDto> listTasks(
@RequestParam(required = false) String status
) {
return taskService.findByStatus(status);
}
Wenn der Query-Parameter fehlt:
status = null
Besser mit Default:
@GetMapping("/api/tasks")
public List<TaskDto> listTasks(
@RequestParam(defaultValue = "OPEN") String status
) {
return taskService.findByStatus(status);
}
31. @RequestBody vs. @RequestParam vs. @PathVariable
| Annotation | Liest aus | Beispiel |
|---|---|---|
@PathVariable | URL-Pfad | /tasks/123 |
@RequestParam | Query String | /tasks?page=0 |
@RequestBody | HTTP-Body | JSON-Body |
Merksatz:
PathVariable = path.
RequestParam = query.
RequestBody = body.
32. Vollständiges REST-Flow-Beispiel
Request:
POST /api/tasks
Content-Type: application/json
{
"title": "Learn DispatcherServlet"
}
Controller:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@PostMapping
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
}
Request-DTO:
public record CreateTaskRequest(String title) {
}
Response-DTO:
public record TaskDto(Long id, String title) {
}
Flow:
1. Client sendet POST /api/tasks.
2. Tomcat empfängt den Request.
3. DispatcherServlet empfängt den Request.
4. HandlerMapping findet TaskController.create().
5. HttpMessageConverter konvertiert den JSON-Body zu CreateTaskRequest.
6. HandlerAdapter ruft create(request) auf.
7. Controller ruft TaskService auf.
8. Service liefert TaskDto zurück.
9. HttpMessageConverter konvertiert TaskDto zu JSON.
10. DispatcherServlet sendet die HTTP-Response.
33. Status Codes zurückgeben
Standardmäßig:
@PostMapping
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
liefert oft:
HTTP 200 OK
Für Create-Operationen aber besser:
HTTP 201 Created
Nutze ResponseEntity:
@PostMapping
public ResponseEntity<TaskDto> create(@RequestBody CreateTaskRequest request) {
TaskDto created = taskService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
34. ResponseEntity
Mit ResponseEntity steuerst du:
Status Code
Header
Body
Beispiel:
@GetMapping("/{id}")
public ResponseEntity<TaskDto> getTask(@PathVariable Long id) {
TaskDto task = taskService.findById(id);
return ResponseEntity.ok(task);
}
Beispiel No Content:
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteTask(@PathVariable Long id) {
taskService.delete(id);
return ResponseEntity.noContent().build();
}
Response:
HTTP 204 No Content
35. @ResponseStatus
Ein anderer Weg, den Status zu setzen:
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Das liefert immer:
201 Created
außer eine Exception ändert die Response.
Nutze ResponseEntity, wenn du mehr Kontrolle brauchst.
Nutze @ResponseStatus, wenn der Status fest und einfach ist.
36. Häufige HTTP-Status-Codes in REST
| Status | Bedeutung |
|---|---|
200 OK | erfolgreicher Request mit Response Body |
201 Created | Ressource erstellt |
204 No Content | erfolgreicher Request ohne Body |
400 Bad Request | ungültiger Client-Request |
401 Unauthorized | Authentifizierung erforderlich oder fehlgeschlagen |
403 Forbidden | authentifiziert, aber nicht berechtigt |
404 Not Found | Ressource nicht gefunden |
409 Conflict | Konflikt mit dem aktuellen Zustand |
500 Internal Server Error | Server-Fehler |
Für die Zertifizierung solltest du die häufigsten kennen.
37. Was passiert, wenn kein Mapping passt?
Request:
GET /api/unknown
Es gibt kein Controller-Mapping.
Spring MVC liefert normalerweise:
404 Not Found
Weil HandlerMapping keinen passenden Handler finden konnte.
Merksatz:
Kein passender Handler bedeutet normalerweise 404.
38. Was passiert, wenn die Methode nicht unterstützt wird?
Controller:
@GetMapping("/api/tasks")
public List<TaskDto> list() {
return taskService.findAll();
}
Request:
POST /api/tasks
Wenn kein POST-Mapping existiert, ist die Response normalerweise:
405 Method Not Allowed
Merksatz:
Pfad existiert, aber HTTP-Methode ist falsch: 405.
39. Was passiert, wenn JSON nicht geparst werden kann?
Request:
POST /api/tasks
Content-Type: application/json
{
"title":
}
Ungültiges JSON.
Spring kann den Body nicht in ein Java-Objekt konvertieren.
Die Response ist normalerweise:
400 Bad Request
Weil der Client ungültige Eingaben gesendet hat.
40. Was passiert, wenn die Typkonvertierung fehlschlägt?
Request:
GET /api/tasks/abc
Controller erwartet:
@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
}
Spring kann nicht konvertieren:
abc -> Long
Die Response ist normalerweise:
400 Bad Request
41. @RequestMapping-Bedingungen
Mappings können auf mehr als nur den Pfad passen.
Sie können passen auf:
Pfad
HTTP-Methode
Request-Parameter
Header
consumes Content Type
produces Content Type
Beispiel:
@PostMapping(
value = "/api/tasks",
consumes = "application/json",
produces = "application/json"
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Bedeutung:
JSON-Request-Body akzeptieren.
JSON-Response zurückgeben.
42. Content Negotiation
Content Negotiation bedeutet:
Spring entscheidet, welches Response-Format produziert wird — basierend auf Request-Headern und verfügbaren Converters.
Beispiel-Request-Header:
Accept: application/json
Spring wählt JSON, wenn es JSON produzieren kann.
Für normale REST APIs ist JSON üblich.
Spring nutzt dafür HttpMessageConverter.
Merksatz:
Content Negotiation hilft, das Response-Format zu wählen.
43. consumes und produces
consumes bedeutet:
Welchen Request-Content-Type diese Methode akzeptiert.
produces bedeutet:
Welchen Response-Content-Type diese Methode zurückgibt.
Beispiel:
@PostMapping(
value = "/api/tasks",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
44. Typische REST-Controller-Struktur
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@GetMapping
public List<TaskDto> list() {
return taskService.findAll();
}
@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
@PostMapping
public ResponseEntity<TaskDto> create(@RequestBody CreateTaskRequest request) {
TaskDto created = taskService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
taskService.delete(id);
return ResponseEntity.noContent().build();
}
}
Das ist ein sauberer, grundlegender REST-Controller.
45. DTOs vs. Entities
Vermeide es, JPA-Entities direkt aus Controllern zurückzugeben.
Besser:
Controller gibt DTOs zurück.
Service arbeitet mit Domain-Logik.
Repository arbeitet mit Entities.
Schlecht:
@GetMapping("/api/users/{id}")
public UserEntity getUser(@PathVariable Long id) {
return userRepository.findById(id).orElseThrow();
}
Besser:
@GetMapping("/api/users/{id}")
public UserDto getUser(@PathVariable Long id) {
return userService.findById(id);
}
Warum?
interne Datenbankstruktur nicht exponieren
Lazy-Loading-Serialisierungsprobleme vermeiden
Response-Form steuern
sensible Felder nicht leaken
API-Vertrag vom Persistence-Model trennen
Merksatz:
REST APIs sollten normalerweise DTOs exponieren, nicht Entities.
46. Spring MVC vs. Spring WebFlux
Spring MVC:
servlet-basiert
blocking Model
nutzt häufig Tomcat
Starter: spring-boot-starter-web
Spring WebFlux:
reactive
non-blocking Model
nutzt häufig Reactor Netty
Starter: spring-boot-starter-webflux
Für normale REST APIs und die meisten Prüfungsfragen:
Spring MVC + spring-boot-starter-web
Merksatz:
Spring MVC ist servlet-basiert. WebFlux ist reactive.
47. Typische Prüfungsfallen
Falle 1
DispatcherServlet ist nicht dein Controller.
Es ist der zentrale Front Controller, der Requests an Handler dispatcht.
Falle 2
HandlerMapping ruft den Controller nicht auf.
Es findet den passenden Handler.
Falle 3
HandlerAdapter ruft den Handler auf.
Falle 4
@RestController ist @Controller plus @ResponseBody.
Falle 5
Mit @Controller bedeutet ein zurückgegebener String normalerweise View-Namen.
Mit @RestController bedeutet ein zurückgegebener String Response Body.
Falle 6
@RequestBody liest den HTTP-Body.
@RequestParam liest Query-Parameter.
@PathVariable liest Pfadwerte.
Falle 7
Java-Objekte werden über HttpMessageConverter zu JSON — normalerweise mit Jackson.
Falle 8
Kein passender Pfad bedeutet normalerweise 404.
Falsche HTTP-Methode bedeutet normalerweise 405.
Ungültiger Request-Body oder Typkonvertierung bedeutet normalerweise 400.
Falle 9
Controller sollten schlank sein.
Business-Logik gehört in Services.
Falle 10
In den meisten echten Projekten solltest du JPA-Entities nicht direkt aus REST APIs exponieren.
48. Prüfungsfrage: Spring MVC
Frage:
Was ist Spring MVC?
Antwort:
Spring MVC ist das Spring-Framework-Modul zum Bau von Web-Anwendungen. Es mappt HTTP-Requests auf Java-Controller-Methoden und hilft bei Request-Daten, Response-Daten, Validation, Exceptions, Views und REST-Responses.
49. Prüfungsfrage: DispatcherServlet
Frage:
Was ist DispatcherServlet?
Antwort:
DispatcherServlet ist der zentrale Front Controller in Spring MVC. Es empfängt eingehende HTTP-Requests und koordiniert den Prozess: den richtigen Handler finden, ihn aufrufen, das Ergebnis verarbeiten und eine HTTP-Response zurückgeben.
50. Prüfungsfrage: HandlerMapping
Frage:
Was macht HandlerMapping?
Antwort:
HandlerMapping findet, welcher Handler — normalerweise eine Controller-Methode — einen gegebenen HTTP-Request handhaben soll.
51. Prüfungsfrage: HandlerAdapter
Frage:
Was macht HandlerAdapter?
Antwort:
HandlerAdapter ruft die von HandlerMapping ausgewählte Handler-Methode auf.
52. Prüfungsfrage: @Controller vs. @RestController
Frage:
Was ist der Unterschied zwischen @Controller und @RestController?
Antwort:
@Controller wird häufig für klassische MVC-Controller genutzt, die View-Namen zurückgeben. @RestController wird für REST APIs genutzt und schreibt Rückgabewerte direkt in den HTTP-Response-Body. @RestController entspricht @Controller plus @ResponseBody.
53. Prüfungsfrage: @ResponseBody
Frage:
Was macht @ResponseBody?
Antwort:
@ResponseBody sagt Spring, den Methoden-Rückgabewert direkt in den HTTP-Response-Body zu schreiben — statt ihn als View-Namen zu behandeln.
54. Prüfungsfrage: JSON-Konvertierung
Frage:
Wie konvertiert Spring Java-Objekte in REST-Controllern zu JSON?
Antwort:
Spring nutzt HttpMessageConverters. In einer typischen Spring-Boot-MVC-Anwendung konvertiert Jackson Java-Objekte zu JSON und JSON-Request-Bodies zu Java-Objekten.
55. Prüfungsfrage: @RequestBody
Frage:
Was macht @RequestBody?
Antwort:
@RequestBody sagt Spring, den HTTP-Request-Body zu lesen und mit einem HttpMessageConverter in ein Java-Objekt zu konvertieren.
56. Prüfungsfrage: @PathVariable
Frage:
Was macht @PathVariable?
Antwort:
@PathVariable bindet einen Wert aus dem URL-Pfad an einen Controller-Methoden-Parameter.
57. Prüfungsfrage: @RequestParam
Frage:
Was macht @RequestParam?
Antwort:
@RequestParam bindet einen Query-Parameter aus der Request-URL an einen Controller-Methoden-Parameter.
58. Prüfungsfrage: ResponseEntity
Frage:
Warum ResponseEntity nutzen?
Antwort:
ResponseEntity erlaubt einer Controller-Methode, HTTP-Status-Code, Response-Header und Response-Body zu steuern.
59. Prüfungsfrage: Kein Mapping
Frage:
Was passiert normalerweise, wenn kein Controller-Mapping zu einem Request passt?
Antwort:
Spring MVC liefert normalerweise 404 Not Found.
60. Prüfungsfrage: Falsche HTTP-Methode
Frage:
Was passiert normalerweise, wenn der Pfad existiert, aber die HTTP-Methode nicht unterstützt wird?
Antwort:
Spring MVC liefert normalerweise 405 Method Not Allowed.
61. Interview-Antwort
Frage:
Explain the Spring MVC request flow.
Gute Antwort:
Wenn ein HTTP-Request reinkommt, empfängt der embedded Servlet Container ihn und leitet ihn an Spring MVCs DispatcherServlet weiter. DispatcherServlet fragt HandlerMapping, welche Controller-Methode zuständig ist. Dann ruft ein HandlerAdapter diese Methode auf. Der Controller ruft normalerweise einen Service auf und gibt ein Java-Objekt oder ResponseEntity zurück. Für REST APIs konvertiert ein HttpMessageConverter — normalerweise mit Jackson — das Java-Objekt zu JSON. Zum Schluss sendet DispatcherServlet die HTTP-Response an den Client zurück.
62. Interview-Antwort
Frage:
What is the role of
DispatcherServlet?
Gute Antwort:
DispatcherServlet ist der Front Controller von Spring MVC. Es empfängt eingehende HTTP-Requests und koordiniert die Request-Verarbeitung. Es delegiert an HandlerMapping, um den richtigen Handler zu finden, nutzt einen HandlerAdapter zum Aufruf, arbeitet mit Message Converters und Exception Handlers und gibt die finale HTTP-Response zurück. Es ist der zentrale Einstiegspunkt für Spring-MVC-Requests.
63. Interview-Antwort
Frage:
What is the difference between
@Controllerand@RestController?
Gute Antwort:
@Controller markiert eine Klasse als Spring-MVC-Controller — oft für klassische serverseitig gerenderte Views. Gibt eine Methode einen String zurück, kann Spring ihn als View-Namen behandeln. @RestController wird für REST APIs genutzt. Es enthält @ResponseBody, sodass Methoden-Rückgabewerte direkt in den HTTP-Response-Body geschrieben werden — normalerweise als JSON.
64. Interview-Antwort
Frage:
How does Spring handle JSON request and response bodies?
Gute Antwort:
Spring nutzt HttpMessageConverters, um zwischen HTTP-Bodies und Java-Objekten zu konvertieren. In einer typischen Spring-Boot-MVC-Anwendung konfiguriert der Web-Starter Jackson automatisch. Für einen Request-Body sagt @RequestBody Spring, JSON in ein Java-Objekt zu konvertieren. Für einen Response-Body konvertiert Spring das zurückgegebene Java-Objekt zu JSON.
65. Interview-Antwort
Frage:
How should a REST controller be structured?
Gute Antwort:
Ein REST-Controller sollte schlank sein. Er sollte HTTP-Themen handhaben: Path Variables, Query-Parameter, Request Bodies, Status Codes und Response-DTOs. Business-Logik delegiert er an die Service-Schicht. Die Service-Schicht enthält Business-Regeln, Repositories handhaben Persistence. Controller sollten normalerweise DTOs statt JPA-Entities zurückgeben, um den API-Vertrag vom Datenbankmodell zu trennen.
66. Kleine Code-Übung
Erstelle einen Controller:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping("/{id}")
public TaskDto getTask(@PathVariable Long id) {
return new TaskDto(id, "Learn Spring MVC");
}
@PostMapping
public ResponseEntity<TaskDto> createTask(@RequestBody CreateTaskRequest request) {
TaskDto created = new TaskDto(1L, request.title());
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
}
DTOs:
public record TaskDto(Long id, String title) {
}
public record CreateTaskRequest(String title) {
}
Fragen:
- Welche Methode handhabt
GET /api/tasks/5? - Woher kommt
id? - Woher kommt
CreateTaskRequest? - Welchen Status liefert
createTask? - Wer konvertiert
TaskDtozu JSON?
Antworten:
getTask- Aus der Path Variable
{id} - Aus dem JSON-Request-Body über
@RequestBody 201 Created- Ein
HttpMessageConverter, normalerweise mit Jackson
67. Kleine Bug-Übung 1
Problem:
@Controller
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public String hello() {
return "hello";
}
}
Erwarteter Response Body:
hello
Aber Spring sucht eine View namens hello.
Frage:
Was ist falsch?
Antwort:
Die Klasse nutzt @Controller. Ein zurückgegebener String wird deshalb als View-Namen behandelt — außer du nutzt @ResponseBody.
Fix-Option 1:
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public String hello() {
return "hello";
}
}
Fix-Option 2:
@Controller
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
@ResponseBody
public String hello() {
return "hello";
}
}
68. Kleine Bug-Übung 2
Problem:
Request:
GET /api/tasks/abc
Controller:
@GetMapping("/api/tasks/{id}")
public TaskDto getTask(@PathVariable Long id) {
return taskService.findById(id);
}
Frage:
Was passiert?
Antwort:
Spring versucht, abc in Long zu konvertieren — die Konvertierung schlägt fehl. Die Response ist normalerweise 400 Bad Request.
69. Kleine Bug-Übung 3
Problem:
Request:
POST /api/tasks
Content-Type: application/json
{
"title":
}
Controller:
@PostMapping("/api/tasks")
public TaskDto create(@RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Frage:
Was passiert?
Antwort:
Das JSON ist ungültig. Spring kann den Request-Body nicht in CreateTaskRequest konvertieren. Die Response ist normalerweise 400 Bad Request.
Übungsfragen
Frage 1
Was ist Spring MVC?
Antwort:
Spring MVC ist das Spring-Framework-Modul zum Bau von Web-Anwendungen. Es mappt HTTP-Requests auf Java-Controller-Methoden und hilft bei Request-Daten, Responses, Validation, Exceptions, Views und REST APIs.
Frage 2
Welches Problem löst Spring MVC?
Antwort:
Spring MVC löst das Problem, HTTP-Routing, Request-Parsing, Response-Schreiben, JSON-Konvertierung, Status Codes, Validation und Exception Handling manuell handhaben zu müssen.
Frage 3
Was ist DispatcherServlet?
Antwort:
DispatcherServlet ist der zentrale Front Controller in Spring MVC. Es empfängt eingehende HTTP-Requests und koordiniert die Request-Verarbeitung.
Frage 4
Warum heißt DispatcherServlet Front Controller?
Antwort:
Es heißt Front Controller, weil es der zentrale Einstiegspunkt für Spring-MVC-Requests ist und an die richtigen Handler delegiert.
Frage 5
Was ist ein Controller?
Antwort:
Ein Controller ist eine Spring Bean mit Methoden zum Handhaben von HTTP-Requests.
Frage 6
Was macht HandlerMapping?
Antwort:
HandlerMapping findet, welcher Handler — normalerweise eine Controller-Methode — einen Request handhaben soll.
Frage 7
Was macht HandlerAdapter?
Antwort:
HandlerAdapter ruft den von HandlerMapping ausgewählten Handler auf.
Frage 8
Was ist der Unterschied zwischen HandlerMapping und HandlerAdapter?
Antwort:
HandlerMapping findet den Handler. HandlerAdapter ruft den Handler auf.
Frage 9
Was ist @RequestMapping?
Antwort:
@RequestMapping mappt HTTP-Requests auf Controller-Klassen oder -Methoden — basierend auf Pfad, Methode, Headern, Parametern, consumes oder produces.
Frage 10
Nenne fünf Shortcut-Mapping-Annotationen.
Antwort:
Fünf Shortcut-Annotationen sind:
@GetMapping
@PostMapping
@PutMapping
@PatchMapping
@DeleteMapping
Frage 11
Was ist der Unterschied zwischen @Controller und @RestController?
Antwort:
@Controller wird oft für klassisches MVC genutzt und kann View-Namen zurückgeben. @RestController wird für REST APIs genutzt und schreibt Rückgabewerte direkt in den Response Body. @RestController entspricht @Controller plus @ResponseBody.
Frage 12
Was macht @ResponseBody?
Antwort:
@ResponseBody sagt Spring, den Methoden-Rückgabewert direkt in den HTTP-Response-Body zu schreiben — statt ihn als View-Namen zu behandeln.
Frage 13
Was macht @RequestBody?
Antwort:
@RequestBody sagt Spring, den HTTP-Request-Body zu lesen und in ein Java-Objekt zu konvertieren.
Frage 14
Was macht @PathVariable?
Antwort:
@PathVariable bindet einen Wert aus dem URL-Pfad an einen Methoden-Parameter.
Frage 15
Was macht @RequestParam?
Antwort:
@RequestParam bindet einen Query-Parameter aus der URL an einen Methoden-Parameter.
Frage 16
Was ist HttpMessageConverter?
Antwort:
HttpMessageConverter konvertiert zwischen HTTP-Request-/Response-Bodies und Java-Objekten.
Frage 17
Wie konvertiert Spring normalerweise Java-Objekte zu JSON?
Antwort:
In einer typischen Spring-Boot-MVC-App nutzt Spring Jackson über einen HttpMessageConverter, um Java-Objekte zu JSON zu konvertieren.
Frage 18
Wofür wird ResponseEntity genutzt?
Antwort:
ResponseEntity steuert HTTP-Status-Code, Header und Response-Body.
Frage 19
Was passiert normalerweise, wenn kein Mapping passt?
Antwort:
Wenn kein Mapping passt, liefert Spring MVC normalerweise 404 Not Found.
Frage 20
Warum sollten Controller normalerweise schlank sein?
Antwort:
Controller sollten schlank sein, weil sie HTTP-Themen handhaben und Business-Logik an Services delegieren sollten. Das hält den Code sauber, testbar und wartbar.
Merksätze zum Mitnehmen
- Spring MVC mappt HTTP-Requests auf Java-Controller-Methoden.
DispatcherServletist der Front Controller von Spring MVC.DispatcherServletkoordiniert den Request-Flow.HandlerMappingfindet den Handler.HandlerAdapterruft den Handler auf.- Ein Controller handhabt HTTP-Requests.
- Controller sollten normalerweise schlank sein.
@RestControllerentspricht@Controllerplus@ResponseBody.@Controllerkann View-Namen zurückgeben.@RestControllergibt Response Bodies zurück.@RequestBodyliest den HTTP-Body.@PathVariableliest Pfadwerte.@RequestParamliest Query-Parameter.HttpMessageConverterkonvertiert zwischen HTTP-Bodies und Java-Objekten.- Jackson konvertiert normalerweise Java-Objekte zu JSON.
ResponseEntitysteuert Status, Header und Body.- Kein passendes Mapping bedeutet normalerweise 404.
- Falsche HTTP-Methode bedeutet normalerweise 405.
- Ungültiger Request-Body oder Typkonvertierung bedeutet normalerweise 400.
- REST-Controller sollten normalerweise DTOs zurückgeben, nicht JPA-Entities.