File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub.config;
import kr.itn.itnhub.seed.SeedParseException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 운영자의 흔한 실수를 서버 장애(500)가 아니라 4xx로 돌려준다.
*
* <p>{@link IllegalArgumentException}은 {@code OrganizationService.updateContact}와
* {@code ChannelProvisionService.provision}이 존재하지 않는 기관 id에 대해 던진다 -
* URL에 오타가 있는 것뿐이므로 404가 맞다.</p>
*
* <p>{@link SeedParseException}은 비어 있거나, 형식이 틀렸거나, 시트가 잘못된 업로드에
* 대해 던진다 - 흔한 사용자 실수이므로 400과 함께 무엇이 잘못됐는지 알려줘야 한다.</p>
*
* <p>예외 메시지는 각 예외가 만든 그대로 내려준다(새로 지어내지 않는다) - 스택트레이스,
* SQL, 파일 경로는 어차피 이 메시지들에 담기지 않으므로 그대로 노출해도 안전하다.
* {@code server.error.include-message=NEVER} 기본값은 건드리지 않는다 - 여기서 직접
* {@link ApiError} 본문을 만들어 반환하므로 그 설정과는 무관하게 동작한다.</p>
*
* <p><b>여기에 {@code Exception.class} catch-all을 추가하지 말 것.</b> 예상하지 못한
* 예외까지 4xx로 감싸버리면 진짜 버그가 조용히 묻힌다. 예상 밖 예외는 기본 500 처리
* 그대로 두는 것이 의도다.</p>
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ApiError> handleNotFound(IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ApiError(e.getMessage()));
}
@ExceptionHandler(SeedParseException.class)
public ResponseEntity<ApiError> handleSeedParse(SeedParseException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiError(e.getMessage()));
}
}