guardia-mes/backend/src/main/java/com/zioinfo/mes/common/GlobalExceptionHandler.java

57 lines
2.2 KiB
Java

package com.zioinfo.mes.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
/**
* 전역 예외 처리.
*
* <p>보안 불변 규칙: 스택트레이스를 응답에 절대 노출하지 않는다.
* 에러 코드 + 요약 메시지만 반환한다.
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
@ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE)
public ApiResponse<Void> handleMaxSize(MaxUploadSizeExceededException e) {
log.warn("업로드 크기 초과: {}", e.getMessage());
return ApiResponse.fail("ERR-MES-413: 파일 크기 초과 (최대 20MB)");
}
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public ApiResponse<Void> handleAccessDenied(AccessDeniedException e) {
log.warn("권한 거부: {}", e.getMessage());
return ApiResponse.fail("ERR-MES-403: 권한이 없습니다");
}
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleIllegalArg(IllegalArgumentException e) {
log.warn("잘못된 요청: {}", e.getMessage());
return ApiResponse.fail(e.getMessage());
}
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleRuntime(RuntimeException e) {
// 스택트레이스 미노출 — 에러 코드/요약만 반환
log.warn("업무 오류: {}", e.getMessage());
return ApiResponse.fail(e.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResponse<Void> handleGeneral(Exception e) {
log.error("시스템 오류", e);
return ApiResponse.fail("ERR-SYS-001");
}
}