비지니스 로직 처리 중 발생하는 엣지케이스들은 왠만하면 예외로 처리할려고 한다.
그래서 Custom Exception을 만들것이다.
1. ErrorCode 정의
예외 응답을 위한 ErrorCode는 아래와 같이 작성함
너무 상세하게 원인을 적지는 않고, 예외 타입 정도만 작성함
package com.woopi.safehome.global.exception
import org.springframework.http.HttpStatus
enum class ErrorCode(
val code: String,
val httpStatus: HttpStatus,
val defaultMessage: String
) {
NOT_FOUND("NOT_FOUND", HttpStatus.NOT_FOUND, "데이터를 찾을 수 없습니다."),
VALIDATION_FAILED("VALIDATION_FAILED", HttpStatus.BAD_REQUEST, "요청 값이 유효하지 않습니다."),
CONSTRAINT_VIOLATION("CONSTRAINT_VIOLATION", HttpStatus.BAD_REQUEST, "요청 파라미터가 유효하지 않습니다."),
INTERNAL_SERVER_ERROR("INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다.")
}
2. BusinessException 정의
커스텀 예외를 처리할 BusinessException을 정의한다.
package com.woopi.safehome.global.exception
class BusinessException(
val errorCode: ErrorCode,
override val message: String = errorCode.defaultMessage,
val details: Any? = null
) : RuntimeException(message) {
// 하위 호환성을 위한 프로퍼티
val code: String get() = errorCode.code
}
3. Exception Handler 추가
package com.woopi.safehome.global.exception.handler
import com.woopi.safehome.global.exception.BusinessException
import com.woopi.safehome.global.exception.ErrorCode
import com.woopi.safehome.global.response.ApiResponse
import jakarta.validation.ConstraintViolationException
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
@ControllerAdvice
class GlobalExceptionHandler {
/**
* BusinessException 처리
*/
@ExceptionHandler(BusinessException::class)
fun handleBusinessException(e: BusinessException): ResponseEntity<ApiResponse<Nothing?>> {
return createErrorResponse(e.errorCode, e.details)
}
/**
* DTO @Valid 검증 실패 (RequestBody)
*/
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleValidationException(ex: MethodArgumentNotValidException): ResponseEntity<ApiResponse<Nothing?>> {
val errorDetails = ex.bindingResult.fieldErrors.associate { fieldError ->
fieldError.field to (fieldError.defaultMessage ?: "잘못된 입력입니다.")
}
return createErrorResponse(ErrorCode.VALIDATION_FAILED, errorDetails)
}
/**
* 파라미터 제약조건 실패 (RequestParam, PathVariable)
*/
@ExceptionHandler(ConstraintViolationException::class)
fun handleConstraintViolation(ex: ConstraintViolationException): ResponseEntity<ApiResponse<Nothing?>> {
val errorDetails = ex.constraintViolations.associate { violation ->
violation.propertyPath.toString() to violation.message
}
return createErrorResponse(ErrorCode.CONSTRAINT_VIOLATION, errorDetails)
}
/**
* 일반적인 Exception 처리
*/
@ExceptionHandler(Exception::class)
fun handleGenericException(ex: Exception): ResponseEntity<ApiResponse<Nothing?>> {
return createErrorResponse(ErrorCode.INTERNAL_SERVER_ERROR, ex.localizedMessage)
}
private fun createErrorResponse(
errorCode: ErrorCode,
details: Any? = null
): ResponseEntity<ApiResponse<Nothing?>> {
val response = ApiResponse.error(
code = errorCode.code,
message = errorCode.defaultMessage,
details = details
)
return ResponseEntity.status(errorCode.httpStatus).body(response)
}
}
'개발일지' 카테고리의 다른 글
| [개발일지_safeHome] 10. 등기부등본 분석 설계는 어떻게 할 것인가? (0) | 2025.12.29 |
|---|---|
| [개발일지_safeHome] 9. swagger 세팅 (0) | 2025.12.28 |
| [개발일지_safeHome] 7. sample 도메인 개발 (adapter, usecase, repository, 등등.....) (0) | 2025.12.23 |
| [개발일지_safeHome] 6.JPA Audit 설정 추가 (0) | 2025.12.15 |
| [개발일지_safeHome] 5. sample 도메인 개발 (모델, 엔티티) (0) | 2025.12.14 |