Büyük projelerin birden fazla controllerı olduğu için bunları @ControllerAdvice isimli interceptor/filter ile exception sürecinde handlingi gerçekleştirebiliriz.

@ControllerAdvice bir AOP yaklaşımı olduğu için controller da pre-process (controllara gelmeden önce), post-process (exceptionu handle etme) sürecinde de rol alır.

Öncelikle bir Student yok ise bununla ilgili bir hata basalım, not found 404.



StudentErrorResponse.java

public class StudentErrorResponse {
 
    private int status;
    private String message;
    private long timeStamp;
 
    public StudentErrorResponse() {
    }
 
    public StudentErrorResponse(int status, String message, long timeStamp) {
        this.status = status;
        this.message = message;
        this.timeStamp = timeStamp;
    }
 
    public int getStatus() {
        return status;
    }
 
    public void setStatus(int status) {
        this.status = status;
    }
 
    public String getMessage() {
        return message;
    }
 
    public void setMessage(String message) {
        this.message = message;
    }
 
    public long getTimeStamp() {
        return timeStamp;
    }
 
    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }
 
}

Bizim JSON'da dönüş değeri olarak biz StudentErrorResponse'yi kullanıyoruz artık bizim Java POJO olarak exception süreçlerinde StudentErrorResponse.java'yı kullanacağız jackson sayesinde artık bu, api'yi kullanan yerlere dönüş değeri json şeklinde dönecektir.


StudentNotFoundException.java

public class StudentNotFoundException extends RuntimeException {
    public StudentNotFoundException(String message) {
        super(message);
    }
}

Öğrenci bulunamadıysa eğer bu hatayı fırlatacağız.

Peki bu hatayı fırlattığımızda nerde handle edip yakalayacağız ?

Bunun için de @ControllerAdvice ve @ExceptionHandler kullanıyor olacağız.


StudentRestExceptionHandler.java

@ControllerAdvice
public class StudentRestExceptionHandler {
    @ExceptionHandler
    public ResponseEntity<StudentErrorResponse> handleEx(StudentNotFoundException ex){
        StudentErrorResponse studentErrorResponse = new StudentErrorResponse();
        studentErrorResponse.setStatus(HttpStatus.NOT_FOUND.value());
        studentErrorResponse.setMessage(ex.getMessage());
        studentErrorResponse.setTimeStamp(System.currentTimeMillis());
        return ResponseEntity
                .status(HttpStatus.NOT_FOUND).body(studentErrorResponse);
    }
}


Görüldüğü üzere ExceptionHandler ile fırlattığımız hata olan StudentNotFoundExceptionu burda yakalayıp StudentErrorResponse ile json yanıtımızı dönüyoruz.

REST Controllerımızı da güncelleyelim.

StudentRestController.java

@RestController
public class StudentRestController {
    @RequestMapping(path="/students/{studentId}",method=RequestMethod.GET)
    public Student getStudent(@PathVariable(name = "studentId") Long theId){
        if (theId >= 10){
            throw new StudentNotFoundException("Student yok");
        }
        Student student = new Student("Minter","Coder");
        student.setId(theId);
        return student;
    }
}


Peki ya diğer hata çeşitlerinde de böyle tek tek yazacak mıyız ?

Tabii ki hayır Global Handling Exception ile bütün hepsini yakalayabiliriz bunun için de sadece yapmamız gereken StudentRestExecptionHandler.java classını güncellemektir.


@ControllerAdvice
public class StudentRestExceptionHandler {
    
    @ExceptionHandler
    public ResponseEntity<StudentErrorResponse> handleEx(StudentNotFoundException ex){
        StudentErrorResponse studentErrorResponse = new StudentErrorResponse();
        studentErrorResponse.setStatus(HttpStatus.NOT_FOUND.value());
        studentErrorResponse.setMessage(ex.getMessage());
        studentErrorResponse.setTimeStamp(System.currentTimeMillis());
        return ResponseEntity
                .status(HttpStatus.NOT_FOUND).body(studentErrorResponse);
    }
    
    @ExceptionHandler
    public ResponseEntity<StudentErrorResponse> handleEx(Exception ex){
        StudentErrorResponse studentErrorResponse = new StudentErrorResponse();
        studentErrorResponse.setStatus(HttpStatus.BAD_REQUEST.value());
        studentErrorResponse.setMessage(ex.getMessage());
        studentErrorResponse.setTimeStamp(System.currentTimeMillis());
        return ResponseEntity
                .status(HttpStatus.BAD_REQUEST).body(studentErrorResponse);
    }
    
}


Görüldüğü üzere sadece StudentNotFoundException hatasını tek değil geri kalan bütün Exception hatalarını da yakala ve dönüş değerinde status code'si olarak BAD_REQUEST dön.

StudentRestController.java'yı da güncelleyelim.


@RestController
public class StudentRestController {
    @RequestMapping(path="/students/{studentId}",method=RequestMethod.GET)
    public Student getStudent(@PathVariable(name = "studentId") Long theId){
        if (theId >= 10){
            throw new StudentNotFoundException("Student yok");
        }
        if (theId == 7){
            throw new ClassFormatError("Class hatası!");
        }
        Student student = new Student("Minter","Coder");
        student.setId(theId);
        return student;
    }
}