티스토리 뷰
예외처리
프로그래밍을 할 땐 다양한 예외 상황이 발생한다.
이 예외 처리를 잘해야 좋은 프로그램이 될 수 있다.
예외 처리를 try-catch문을 사용하거나 다른 여러가지 방법들로 할수도 있지만, 이는 코드가 복잡해지고 유지보수 하기에도 어렵다는 문제점이 있다.
예외처리를 한번에 다른곳에서 처리하고 비즈니스 로직에서는 비즈니스 로직만 작성하여 코드가 복잡해지지 않도록 할 수 있다.
@ExceptionHandler
이 어노테이션은 메서드에 붙일 수 있는데, @Controller와 @RestController가 적용된 Bean에서 생기는 예외를 캐치하여 이 메서드에서 처리해주도록 한다.
메서드의 인자로 캐치하려는 예외 클래스를 작성하면 된다.
리턴 타입은 하고싶은대로 해도 된다.
@ExceptionHandler를 등록한 Controller나 RestController에서만 적용된다.
@RestController
@RequestMapping("/api")
public class CustomerRestController {
/*
...
*/
@ExceptionHandler
public ResponseEntity<CustomerErrorResponse> handleException(Exception exc){
CustomerErrorResponse error = new CustomerErrorResponse(
HttpStatus.BAD_REQUEST.value(),
exc.getMessage(),
System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}
@ControllerAdvice
그런데 위에서도 말했듯이 @ExceptionHandler를 등록한 그 클래스에서만 적용된다. 모든 Controller나 RestController에서 발생할 수 있는 예외를 잡아 한번에 처리해주는 어노테이션이 @ControllerAdvice와 @RestControllerAdvice이다.
새로운 클래스에 이 어노테이션을 붙이고, @ExceptionHandler로 예외 처리 메서드를 작성하면 된다. 모든 패키지 전역의 컨트롤러에서 발생하는 예외가 해당하는 메서드를 처리하게 된다.
@RestController나 @Controller에서 발생하는 예외들을 @ControllerAdvice + @ExceptionHandler 조합으로 캐치하여 처리할 수 있는 것이다.
@ControllerAdvice
public class CustomerRestExceptionHandler {
@ExceptionHandler
public ResponseEntity<CustomerErrorResponse> handleException(CustomerNotFoundException exc){
CustomerErrorResponse error = new CustomerErrorResponse(
HttpStatus.NOT_FOUND.value(),
exc.getMessage(),
System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler
public ResponseEntity<CustomerErrorResponse> handleException(Exception exc){
CustomerErrorResponse error = new CustomerErrorResponse(
HttpStatus.BAD_REQUEST.value(),
exc.getMessage(),
System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}
모든 Controller와 RestController의 예외를 잡지 않고 속성에서 패키지 단위로 지정할수도 있다.
@RestControllerAdvice("com.example.hello.rest")
에러를 잘 정의하기 위해서 에러 객체를 만들어서 처리하는 것도 좋다. 다음과 같이 에러 객체를 만들고
public class CustomerErrorResponse {
private int status;
private String message;
private long timeStamp;
public CustomerErrorResponse() {
}
public CustomerErrorResponse(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;
}
}
RuntimeException 상속받아 Exception을 만든다.
public class CustomerNotFoundException extends RuntimeException{
public CustomerNotFoundException() {
super();
}
public CustomerNotFoundException(String message) {
super(message);
}
public CustomerNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public CustomerNotFoundException(Throwable cause) {
super(cause);
}
}
위에서 만든 Exception 클래스를 인자로 넣어 @ExceptionHanlder 로 메소드를 만들 수 있다. 에러 객체를 만들어서 리턴한다.
@ExceptionHandler
public ResponseEntity<CustomerErrorResponse> handleException(CustomerNotFoundException exc){
CustomerErrorResponse error = new CustomerErrorResponse(
HttpStatus.NOT_FOUND.value(),
exc.getMessage(),
System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
RestController 클래스의 비즈니스 로직에서 간단하게 예외 발생시에 throw new CustomerNotFoundException; 하고 호출하면 된다. 이렇게 하면 아주 간단하게 에러 호출을 할 수 있다.
@GetMapping("/customers/{customerId}")
public Customer getCustomer(@PathVariable int customerId){
Customer theCustomer = customerService.getCustomer(customerId);
if(theCustomer == null){
throw new CustomerNotFoundException("Customer id not found - " + customerId);
}
return theCustomer;
}
'백엔드 및 서버' 카테고리의 다른 글
[Spring] DTO 사용 시 필요한 lombok annotation (0) | 2023.07.17 |
---|---|
[Spring] JPA Entity 사용 시 쓰이는 lombok annotation (0) | 2023.07.17 |
[ Spring ] Controller와 관련 Annotation (0) | 2021.02.02 |
[ Spring ] css나 js 같은 정적 파일 서비스하기 (0) | 2021.01.27 |
[ Spring ] Service 객체 및 DB연결 정보 분리 (0) | 2021.01.27 |