17 Ocak 2020 Cuma

SpringMVC @RestControllerAdvice Anotasyonu

Giriş
Exception döndürmek için 3 yöntem var
- @ControllerAdvice + @ExceptionHandler : Global Exception handling yapar
- Using HandlerExceptionResolver
- Using ResponseStatusException
JSON döndüren REST noktası exception fırlatırsa, exception'ı içeren JSON döndürebilmeyi sağlar. Bu sınıfın kardeşi @ControllerAdvice anotasyonu. Açıklaması şöyle. Yani bu anotasyon yerine @ControllerAdvice kullanılabilir
@RestControllerAdvice is just a syntactic sugar for @ControllerAdvice + @ResponseBody ...

Kullanım
Şeklen şöyle


1. Metodumuz @ExceptionHandler(...) anotasyonuyla işaretlenir. Böylece servis sınıfı bu exception'ı fırlatırsa ilgili metod tetiklenir.
2. Genellikle kendi tanımladığımız bir exception sınıfı ResponseEntity ile sarmalanır ve ResponseEntity döndürülür.
3. ResponseEntity döndürmek yerine Metodumun üzerine @ResponseStatus anotasyonu eklersem de olur
4. Sınıfım ResponseEntityExceptionHandler sınıfından kalıtabilir. Böylece gerekirse Spring tarafından hazırlanan ResponseEntity gerekirse override edilebilir. 

Ben kendi kullanımımda
org.springframework.dao.InvalidDataAccessResourceUsageException'ları yakaladım

1. Exception'ı Decorate Etmek
Bazı kodlarda şöyle yapılıyor. Yani @ResponseStatus kullanılarak veya exception ResponseStatusException'dan kalıtarak bir HTTP sonucu ile exception ilişkilendiriliyor. Ancak bence bu doğru değil. Çünkü exception ve HTTP kodları farklı şeyler.
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NoSuchElementFoundException extends RuntimeException {
  ...
}
veya şöyle yapılıyorResponseStatusException yazısına bakabilirsiniz
public class NoSuchElementFoundException extends ResponseStatusException {

  public NoSuchElementFoundException(String message){
    super(HttpStatus.NOT_FOUND, message);
  }

  @Override
  public HttpHeaders getResponseHeaders() {
      // return response headers
  }
}
ResponseEntity Döndürmek
Ben bu yöntemi çok kısıtlı bilgi döndürdüğü için tercih etmiyorum
Örnek
Şöyle yaparız
@RestControllerAdvice
public class ExceptionAdvice {

  @ExceptionHandler(value = NotFoundException.class)
  public ResponseEntity<CustomErrorResponse> handleException(NotFoundException e) {

    CustomErrorResponse err = new CustomErrorResponse("NOT_FOUND_ERROR", e.getMessage());
    err.setTimestamp(LocalDateTime.now());
    err.setStatus((HttpStatus.NOT_FOUND.value()));
    return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
   }  
}
Örnek
Şöyle yaparız.
@RestControllerAdvice
public class GlobalExceptionHandler {
  @ExceptionHandler(value = {Exception.class})
  public ResponseEntity<ExceptionResponse> unknownException(Exception ex) {
    Foo resp = new Foo (ex, level); // my custom response object
    return new ResponseEntity<ExceptionResponse>(resp, resp.getStatus());
  }
}
Örnek
Şöyle yaparız
@ExceptionHandler(NoSuchElementFoundException.class)
public ResponseEntity<String> handleNoSuchElementFoundException(
  NoSuchElementFoundException exception
) {
  return ResponseEntity
    .status(HttpStatus.NOT_FOUND)
    .body(exception.getMessage());
}
@ResponseStatus Kullanmak
Bu yöntem bence en iyisi. Düzgün bir CustomErrorReponse nesnesi tanımlanırsa bayağı detaylı bilgi dönülebilir.
Örnek
Şöyle yaparız.
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public CustomErrorResponse handle(Exception e) {

  return new CustomErrorResponse(e.getMessage());
}

Hiç yorum yok:

Yorum Gönder