Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
de:modul:ffit:3-jahr:java:learningunits:lu10:a [2025/11/09 23:16] apeterde:modul:ffit:3-jahr:java:learningunits:lu10:a [2025/11/10 00:02] (aktuell) apeter
Zeile 1: Zeile 1:
 ====== LU10a - Umgang mit Exceptions ====== ====== LU10a - Umgang mit Exceptions ======
 +
 +==== Spring ResponseStatusException ====
 +
 +Allgemein gilt, dass Exceptions in Bezug auf die Performanz schlechter abschneiden als die entsprechenden Checks. Daher sollte man Exceptions nie in "Schönwetter"-Fällen benutzen, sondern höchstens in unerwarteten Situationen. Ein ungültiger API-Aufruf ist in unserem Fall aber unerwartet und kann mittels einer Exception gelöst werden. Werden aber viele ungültige API-Aufrufe erwartet, sollte man eine Exception-freie Alternative in Erwägung ziehen.
 +
 +Spring bietet eine sehr einfache Version, um Fehlerfälle mittels Exceptions abzuhandeln. Dabei wird direkt automatisch eine Antwort mit dem entsprechenden HTTP-Statuscode erstellt und zurückgeschickt.
 +
 +Im nachfolgenden Beispiel wird jeweils ein Project-Objekt geladen und falls kein Objekt in der Datenbank vorhanden ist, wird der Statuscode 404 zurückgegeben. 
 +
 +^ Lange Variante ^ Verkürzte Variante ^ Variante mit Exception ^
 +| <WRAP>
 +<code java>
 +Optional<Project> optionalProject = projectRepository.findById(projectName);
 +if(optionalProject.isEmpty()){
 +    return ResponseEntity.notFound().build();
 +}
 +Project project = optionalProject.get();
 +</code> 
 +</WRAP> | <WRAP>
 +<code java>
 +Project project = projectRepository.findById(projectName).orElse(null);
 +if(null == project){
 +    return ResponseEntity.notFound().build();
 +}
 +</code> 
 +</WRAP> | <WRAP>
 +<code java>
 +Project project = projectRepository.findById(projectName).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Project not found"));
 +</code>
 +</WRAP> |
 +
 +Ein sehr grosser Vorteil der dritten Variante ist die Wiederverwendbarkeit: Ein ResponseEntity-Objekt kann nur in der API-Methode zurückgegeben werden. Eine ResponseStatusException kann aber auch in einer verschachtelten Methode geworfen werden. Das erlaubt, dass man Methoden, die man zum Beispiel bei mehreren API-Methoden benötigt, bequem auslagern kann.
  
 ==== Validierung des JWT ==== ==== Validierung des JWT ====
Zeile 22: Zeile 54:
 </WRAP> </WRAP>
  
- +Wenn nun zudem Informationen wie das "Subject" aus dem JWT herausgelesen werden müssenergibt es keinen Sinn, eine separate "Exception"-basierte Validierung zu machenMan kann die Validierung und das Auslesen direkt kombinierenNutzt man zudem die ResponseStatusExceptionhat man eine Methode, die man in mehreren API-Methoden einsetzen kann.
- +
-Hierbei ist anzumerkendass Exceptions in aller Regel in Bezug auf die Performanz schlechter abschneiden als die entsprechenden Checks. Daher sollte man Exceptions nie in "Schönwetter"-Fällen benutzen, sondern höchstens in unerwarteten SituationenEin invalides Token, bzw. allgemein ein ungültiger API-Aufruf, ist in unserem Fall unerwartet und kann mittels Exceptions gelöst werdenWerden aber viele ungültige API-Aufrufe erwartetsollte man eine Exception-freie Alternative in Erwägung ziehen. +
- +
-Wenn zudem  +
- +
  
 <code java> <code java>
-import org.slf4j.Logger+public String verifyTokenAndExtractSubject() { 
-import org.slf4j.LoggerFactory;+    try{ 
 +        String token = extractTokenFromHeader()
 +        return extractSubject(token); 
 +    } catch (Exception e) { 
 +        // Exception mitschicken 
 +        // throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid token", e);
  
-public class DemoController { +        // Exception loggen 
-    private static final Logger log = LoggerFactory.getLogger(DemoController.class); +        log.warn("Invalid token", e); 
-    ... +        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid token"); 
-        log.error("Error during execution of...:", e); +    } 
-</code>+}
  
-Neu ist, dass wir die dazugehörigen Einstellungen einfach in unser ''application.properties'' schreiben können.+private String extractSubject(String token) { 
 +    return Jwts.parserBuilder() 
 +            .setSigningKey(key) 
 +            .build() 
 +            .parseClaimsJws(token) 
 +            .getBody() 
 +            .getSubject(); 
 +}
  
-<code application.properties> +private String extractTokenFromHeader() { 
-logging.level.root=INFO +    ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 
-logging.level.ch.bzz=DEBUG +    if (attributes == null){ 
-logging.file.name=app.log +        return null; 
-</code> +    } 
-  +    String authHeader = attributes.getRequest().getHeader("Authorization")
- +    if (authHeader == null || !authHeader.startsWith("Bearer ")) { 
-Project Lombok hilft uns auch hier die Erstellung des Logger-Objektes zu vereinfachen +        return null; 
- +    } 
-<code java> +    return authHeader.substring(7); 
-import lombok.extern.slf4j.Slf4j+}
- +
-@Slf4j +
-public class DemoController { +
-    ... +
-        log.error("Error during execution of...:", e);+
 </code> </code>
  
  • de/modul/ffit/3-jahr/java/learningunits/lu10/a.1762726567.txt.gz
  • Zuletzt geändert: 2025/11/09 23:16
  • von apeter