⌂ Index
Kapitel 03 · Web

Spring MVC und REST APIs

Typ: FrameworkVersion 2 ausführlich

Spring MVC ist das klassische Servlet-basierte Webframework für REST APIs, serverseitige Webanwendungen und Controller-basierte HTTP-Kommunikation.

Fachliche Einordnung

Der größte Teil klassischer Enterprise-APIs läuft weiterhin blockierend über Servlet-Container. MVC ist robust, verständlich, gut testbar und passt zu JPA/JDBC-Workloads.

Enterprise-Merksatz: Spring MVC ist das klassische Servlet-basierte Webframework für REST APIs, serverseitige Webanwendungen und Controller-basierte HTTP-Kommunikation.

Technische Darstellung

HTTP Request DispatcherServlet Controller DTO Mapper Use Case HTTP Response
Kernkonzepte
  • DispatcherServlet als Front Controller.
  • @Controller und @RestController für Request Mapping.
  • HandlerMethodArgumentResolver und HttpMessageConverter.
  • Bean Validation für Eingabegrenzen.
  • ExceptionHandler und ProblemDetail für konsistente Fehlerantworten.
Wann einsetzen?
  • Du baust REST APIs mit relationaler Datenbank und synchronem Request/Response.
  • Du migrierst JAX-RS oder Servlet APIs nach Spring.
  • Du willst gut testbare Controller mit MockMvc.
Typische Fehler und Risiken
  • Controller enthält Fachlogik statt nur HTTP-Adapterlogik.
  • DTOs werden mit JPA Entities vermischt.
  • Fehlerantworten sind uneinheitlich und schwer für Clients zu verarbeiten.
Legacy- und Modernisierungssicht

Servlets, Struts Actions oder JAX-RS Ressourcen werden zu dünnen MVC-Controllern, die Application Services aufrufen.

Ausführliches Beispiel

Das Beispiel zeigt bewusst nicht nur Annotationen, sondern auch die Verantwortung der Schicht. In echten Projekten sollte der technische Spring-Code an Adapter- oder Konfigurationsrändern bleiben, während die Fachlogik testbar und möglichst frameworkarm bleibt.

@RestController
@RequestMapping("/api/orders")
class OrderController {
    private final PlaceOrderUseCase placeOrder;

    OrderController(PlaceOrderUseCase placeOrder) { this.placeOrder = placeOrder; }

    @PostMapping
    ResponseEntity<OrderResponse> place(@Valid @RequestBody PlaceOrderRequest request) {
        OrderId id = placeOrder.place(request.toCommand());
        URI location = URI.create("/api/orders/" + id.value());
        return ResponseEntity.created(location).body(new OrderResponse(id.value(), "ACCEPTED"));
    }
}

@RestControllerAdvice
class ApiExceptionHandler {
    @ExceptionHandler(DomainRuleViolation.class)
    ProblemDetail handle(DomainRuleViolation ex) {
        ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.UNPROCESSABLE_ENTITY);
        problem.setTitle("Domain rule violated");
        problem.setDetail(ex.getMessage());
        return problem;
    }
}
Checkliste für Reviews
  • Ist die Verantwortung des Bausteins klar: Framework steuert Lebenszyklus, Library wird gezielt benutzt?
  • Ist die Fachlogik außerhalb von Controller, Listener, Repository-Implementierung oder Konfiguration?
  • Sind Fehlerfälle, Timeouts, Security, Monitoring und Tests sichtbar modelliert?
  • Gibt es klare Grenzen zwischen DTO, Domäne, Persistence und Infrastruktur?