이번 심화 주차 개인과제는
- (필수) 숙련 과제 필수사항 보완 및 기능 개선
- (도전) Spring Advanced Repository 의 코드 리팩토링 및 코드 포맷팅, N+1 문제, 테스트 코드 적용
으로 요구사항이 구성되어 있으며, 이전에 했던 과제처럼 서비스 로직을 구현하는 것이 아닌 주어진 기존 코드를 심층적으로 분석하고 이를 개선하는 데 중점을 두며, 코드의 품질을 높이는 작업에 초점을 맞추는 과제이다.
여기서, Lv 5-3 [인터셉터, AOP를 활용한 API 로깅] 부분은 이해도가 부족하여 더 공부하고 문제를 해결해야 할 것 같다💦💦
Lv2. [예외 처리 강화] 요구 사항의 키워드 중에서, GlobalExceptionHandler를 활용한 API 예외처리를 구현하고자 하였다. GlobalExceptionHandler를 실제로 구현해 본 경험이 없었어서.. 이번 기회에 한 번 써보자! 라는 마음 + 앞으로 진행될 과제의 예외처리 부분에서 참고할 수 있을 거 같기 때문에..!!
예외처리를 어떤 식으로 로직이 구성하면 되는 건지.. 코드를 쳐본 경험이 없어서 막막했다.
💥 Trouble. 핸들러가 뭔데.. ㅠ
사실.. "핸들러" 단어를 잘 쓰지 않아서 몰랐지 "특정 작업을 처리하는 코드"라는 포괄적인 개념이라고 생각하면 된다.
핸들러(Handler) 란
- 소프트웨어 개발에서 특정 작업, 요청, 이벤트 또는 데이터 처리를 담당하는 코드
- 이벤트 처리, 요청 처리, 또는 특정 동작을 처리하는 역할
과제를 할 때마다 만드는 컨트롤러, 사실 이것도 "핸들러" 이다. 클라이언트의 요청을 처리하는 핸들러.
// 유저 생성
@PostMapping("/sign-up")
public ResponseEntity<SignUpResponseDto> signUp(
@RequestBody @Valid SignUpRequestDto requestDto
) {
SignUpResponseDto signUpResponseDto = userService.signUp(
requestDto.getEmail(),
bcrypt.encode(requestDto.getPassword()),
requestDto.getUserName()
);
return new ResponseEntity<>(signUpResponseDto, HttpStatus.CREATED);
}
GlobalExceptionHandler은 애플리케이션에서 발생하는 에러를 처리하는 역할을 한다.
스프링에서는 @ControllerAdvice 를 사용하여 글로벌 에러 처리를 한다.
💥 GlobalExceptionHandler 을 사용하여 어떻게 내가 원하는 에러처리를 구현할까?
내가 원하는 에러처리는 아래와 같이, 에러 코드와 함께 에러 메시지를 response body로 보내는 것이다.
{
"errorCode": "ERR001",
"errorMessage": "요청값의 형식이 맞지 않습니다."
}
우선, 에러코드와 에러메시지는 ENUM으로 관리하였다.
- ErrorCode.java
@Getter
public enum ErrorCode {
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "ERR001", "아이디 또는 비밀번호가 잘못되었습니다."),
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "ERR002", "올바르지 않은 입력값입니다."),
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "ERR003", "잘못된 HTTP 메서드입니다."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "ERR004", "서버 에러가 발생했습니다."),
NOT_FOUND_USER(HttpStatus.NOT_FOUND, "ERR005", "존재하지 않는 유저입니다. "),
NOT_FOUND_TODO(HttpStatus.NOT_FOUND, "ERR005", "존재하지 않는 일정입니다. "),
NOT_FOUND_COMMENT(HttpStatus.NOT_FOUND, "ERR005", "존재하지 않는 댓글입니다. "),
ACCESS_DENIED(HttpStatus.FORBIDDEN, "ERR006", "접근 권한이 없습니다.");
private final HttpStatus status;
private final String code;
private final String message;
ErrorCode(HttpStatus status, String code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
}
Custom Exception 클래스 생성
- 에러처리 객체 (이 코드를 수정해서 다르게 커스텀할 수 있다)
@Getter
public class CustomException extends RuntimeException{
private final ErrorCode errorCode;
public CustomException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
}
GlobalExceptionHandler 클래스 생성
- ResponseEntity로 <에러코드, 에러메시지> 쌍을 보낸다.
@RestControllerAdvice // @ControllerAdvice + @ResponseBody : 전역적으로 예외를 처리하고 JSON 형식으로 응답을 반환하는 데 사용
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<Map<String, String>> handleCustomException(CustomException ex) {
Map<String, String> response = new LinkedHashMap<>();
response.put("errorCode", ex.getErrorCode().getCode());
response.put("errorMessage", ex.getErrorCode().getMessage());
log.info("에러 발생 >> 코드 : {}, 메시지 : {}", response.get("errorCode"), response.get("errorMessage"));
return new ResponseEntity<>(response, ex.getErrorCode().getStatus());
}
}
결과 (ex. 특정 유저 조회)
- 해당하는 유저가 없으면 다음과 같이 404 Httpstatus 와 함께 에러코드,메시지를 보낸다.
// 특정 유저 조회
public UserResponseDto findByUserId(Long userId) {
User user = userRepository.findById(userId).
orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_USER)); // NPE 방지
return new UserResponseDto(user);
}
'Trouble Shooting' 카테고리의 다른 글
Spring 일정 관리 앱 Develop 트러블 슈팅 (0) | 2024.12.19 |
---|---|
Spring - 일정 관리 앱 만들기 과제 트러블 슈팅 (0) | 2024.12.10 |
Java 키오스크 과제 - 챌린지 Lv1 트러블 슈팅 (1) | 2024.11.28 |
Java 계산기 과제 - level 2 트러블슈팅 (0) | 2024.11.20 |
JAVA 계산기 과제 - level 1 트러블슈팅 (0) | 2024.11.20 |
댓글