예외 처리의 필요성
- 특정 서버에 요청하면 서버는 응답을 내려주고, 그 응답은 각각의 API마다 규격이 정해져 있다. 예외 상황에 따라서 응답이 달라지면 통일성이 깨지게 된다. 그래서 예외 처리를 통해서 서버가 동일한 응답(규격에 맞는 응답)을 내려줄 수 있도록 예외 처리를 해야 한다.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class API<T> {
private T data;
private String resultCode;
private String resultMessage;
}
- 서버에서 응답을 줄 때 지키고자 하는 규격을 가진 클래스.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder //객체 생성 시 빌더 패턴을 사용하기 위해
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserResponse {
private String userId;
private String userName;
private Integer userAge;
}
@RestController
@RequestMapping(("/api/user") )
public class UserAPIController {
private static List<UserResponse> userList = List.of(
UserResponse.builder() //빌더를 통해 체이닝된 방식으로 사용
.userId("1")
.userName("홍길동")
.userAge(20)
.build(),
UserResponse.builder()
.userId("2")
.userName("유관순")
.userAge(24)
.build()
);
@GetMapping("/id/{userId}")
public API<UserResponse> getUser(
@PathVariable String userId
){
if(true){
throw new RuntimeException("message");
}
var user = userList.stream().
filter(it -> it.getUserId().equals(userId))
.findFirst()
.get();
API<UserResponse> userResponse = API.<UserResponse>builder()
.resultCode(String.valueOf(HttpStatus.OK.value()))
.resultMessage(HttpStatus.OK.name())
.data(user)
.build();
return userResponse;
}
}
- user에서 특정 id를 가진 사용자를 get매핑으로 데이터를 받겠다.
- 별도의 데이터 베이스가 없기 때문에 builder를 통해 생성해준다.
@ExceptionHandler(value = {NoSuchElementException.class})
public ResponseEntity<API> noSuchElement(
NoSuchElementException exception
){
log.info("", exception);
var reponse = API.builder()
.resultCode(String.valueOf(HttpStatus.NOT_FOUND.value()))
.resultMessage(HttpStatus.NOT_FOUND.getReasonPhrase())
.build();
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(reponse);
}
- resultCode와 Message를 지정해 놓지 않으면 200으로 OK가 전송되기 때문에 오류는 오류라고 전송해주도록 설정해 주어야 한다.
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
//예측하지 못한 모든 예외를 야기서 처리하겠다.
@ExceptionHandler(value = {Exception.class})
public ResponseEntity<API> exception(
Exception e
){
log.error("", e);
var response = API.builder()
.resultCode(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()))
.resultMessage(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
.build();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(response);
}
}
- @ExceptionHandler(value = {Exception.class}) value를 가장 최상위 클래스로 지정해 주면서 RestApiExceptionHandler에서 처리하지 못한 에러를 처리해 주도록 지정.
- 서버 내부 에러로 규정하기 위해 500에러에 대한 code와 message를 설정.