티스토리 뷰

반응형

고객 정보를 찾을 수 없어서 {"error": "404 NOT FOUND"} 형태로 반환하는 예제입니다.

 

 

 

JSON 없이 예외처리

 

{
    "id": 4,
    "name": "test",
}

위와 같이 POST에 이상한 데이터를 넣거나 형식을 지키지 않으면 아래와 같이 스프링이 자동으로 예외 처리를 해줍니다.

{
    "timestamp": "2020-09-08T03:12:11.418+00:00",
    "status": 400,
    "error": "Bad Request",
    "message": "",
    "path": "/customer"
}

 

 

이때 @ControllerAdvice와 @ExceptionHandler 어노테이션을 사용해 예외 처리를 해줄 수 있습니다.

@ControllerAdvice
class ErrorHandler {

    @ExceptionHandler(JsonParseException::class)
    fun jsonParseExceptionHandler(servletRequest: HttpServletRequest, exception: Exception) =
            ResponseEntity("Json Error", HttpStatus.BAD_REQUEST)
}

 

위 클래스는 ControllerAdvice 어노테이션을 추가하여 콘텍스트 스캔을 통해 스프링 콘텍스트에 추가됩니다.

그리고 ExceptionHandler 어노테이션을 추가한 함수를 선언하고 예외 클래스를 참조해 처리할 예외 유형을 나타냅니다.

jsonParseExceptionHandler 에러가 발생할 때 처리할 catch 문이 없고, 스프링이 해당 클래스에 사용 가능한 예외 핸들러를 전송해줍니다.

 

 

아래와 같이 처리가 됩니다.

Json Error

 

 

 

JSON 형식으로 예외처리

RESTful API를 만들어야 하므로 JSON을 사용해 응답해야 됩니다.

 

 

먼저 오류 응답을 처리할 데이터 클래스를 만들어 줍니다.

data class ErrorResponse(
        val error: String,
        val message: String
)

 

그리고 ErrorHandler클래스의 jsonParseExceptionHandler를 아래와 같이 수정하였습니다.

 

@ControllerAdvice
class ErrorHandler {

    @ExceptionHandler(JsonParseException::class)
    fun jsonParseExceptionHandler(servletRequest: HttpServletRequest, exception: Exception) =
            ResponseEntity(ErrorResponse("Json Error", exception.message ?: "invalid json"), HttpStatus.BAD_REQUEST)
}

 

 

이제 요청을 하면 아래와 같이 처리가 됩니다.

{
    "error": "Json Error",
    "message": "JSON parse error: Unexpected character ('}' (code 125)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name\n at [Source: (PushbackInputStream); line: 4, column: 2]"
}

 

 

 

비즈니스 예외 처리 ( ResponseEntity 처리 )

ResponseEntity로 처리하는 방법입니다.

 

 

1. 컨트롤러 어드바이스 사용해서 Exception 클래스로 처리

 

class CustomerNotFoundException (message: String) : Exception(message)

예외 처리할 클래스를 만들었습니다.

 

그리고 아래와 같이 예외 처리를 해주었습니다.

@GetMapping(value = ["/customer/{id}"])
fun getCustomer(@PathVariable id: Int) : ResponseEntity<Any> {

    val customer = customerService.getCustomer(id) ?:
            throw CustomerNotFoundException("'$id'번째 고객을 찾을 수 없습니다.")

    return ResponseEntity(customer, HttpStatus.OK)
}

 

 

마지막으로 ExceptonHandler 클래스에 추가합니다.

@ExceptionHandler(CustomerNotFoundException::class)
fun customerNotFoundException(servletRequest: HttpServletRequest, exception: Exception) =
        ResponseEntity(ErrorResponse("404", exception.message!!), HttpStatus.NOT_FOUND)

 

 

요청을 하면 아래와 같이 처리가 됩니다.

{
    "error": "404",
    "message": "'11'번째 고객을 찾을 수 없습니다."
}

 

2. 컨트롤러 어드바이스 피하기

컨트롤러 어드바이스는 좋지만 특별한 경우에만 사용해야 합니다. 따라서 오류에 응답해야 할 때 비즈니스 로직을 추가하면 컨트롤러 어드바이스 사용을 피할 수 있습니다.

 

@GetMapping(value = ["/customer/{id}"])
fun getCustomer(@PathVariable id: Int) : ResponseEntity<Any> {

    val customer = customerService.getCustomer(id)

    return if (customer == null)
        ResponseEntity(ErrorResponse("404", "${id}번째 고객 정보가 없습니다."), HttpStatus.NOT_FOUND)
    else ResponseEntity(customer, HttpStatus.OK)
}

 

요청을 하면 아래와 같이 처리가 됩니다.

{
    "error": "404",
    "message": "11번째 고객 정보가 없습니다."
}
반응형
댓글