애플리케이션의 안정성을 높이고 사용자에게 유용한 오류 메세지를 제공하는 데 중요한 역할을 함.
스프링 MVC는 다양한 방법으로 예외를 처리할 수 있으며, 이러한 방법들을 적절히 활용하면, 더 나은 사용자 경험과 유지보수성을 제공할 수 있음.
스프링 MVC는 기본적으로 @Controller 와 @RestController 에서 발생하는 예외를 처리할 수 있는 기능을 제공
@Controller
public class MyController {
@GetMapping("/example")
public String example() {
if (true) {
throw new RuntimeException("예외발생!");
}
return "exampleView";
}
}
RuntimeException 이 발생하면, 기본적으로 스프링은 Whitelabel Error Page 를 사용자에게 보여줌.
ExceptionHandler 를 사용하여 특정 예외를 처리하는 메서드를 정의할 수 있음. 이 메서드는 해당 컨트롤러에서 발생하는 예외를 처리하는 데 사용됨.
@Controller
public class MyController {
@GetMapping("/example")
public String example() {
if (true) { //임의의 조건으로 예외 발생
throw new RuntimeException("예외발생!");
}
return "exampleView";
}
@ExceptionHandler(RuntimeException.class)
public String handleRuntimeException(RuntimeException e, Model model) {
model.addAttribute("errorMessage", e.getMessage());
return "errorPage";
}
}
ExceptionHandler 메서드는 예외가 발생하면 호출되며, 예외를 처리하고 적절한 뷰로 이동할 수 있음.
ControllerAdvice 를 사용하면 애플리케이션 전체에서 공통적으로 예외를 처리할 수 있음.
특정 컨트롤러에만 국한되지 않고, 모든 컨트ㅗㄹ러에서 발생하는 예외를 처리할 수 있음.
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException e) {
return new ResponseEntity<>("글로벌 예외 처리: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
ControllerAdvice 클래스는 모든 컨트롤러에서 발생하는 예외를 전역적으로 처리
ExceptionHandler 메서드는 예외를 처리하고 적절한 응답을 반환
@ResponseStatus 를 사용하여 예외 클래스에 HTTP 상태 코드를 매필할 수 있음. 이를 통해 특정 예외가 발생했을 때 자동으로 HTTP 응답 상태를 설정할 수 있음.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
@Controller
public class MyController {
@GetMapping("/resource/{id}")
public String getResource(@PathVariable("id") Long id) {
if (id == null) { // 임의의 조건으로 예외 발생
throw new ResourceNotFoundException("리소스가 존재하지 않습니다.")
}
return "resourceView";
}
}
ResourceNotFoundException 이 발생하면 HTTP 404 상태 코드와 함께 적절한 메세지가 반환
스프링 부트에서는 ErrorController 인터페이스를 구현하여 애플리케이션의 전역 오류 페이지를 사용자 정의할 수 있음.
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public String handleError() {
return "customErrorPage"; // 사용자 정의 오류 메세지
}
@Override
public String getErrorPath() {
return "/error";
}
}
/error 경로에 대한 요청이 발생하면 handleError() 메서드가 호출되어 사용자 정의 오류 페이지로 리디렉션됨.
RestControllerAdvice 는 @ControllerAdvice 와 @ResponseBody 의 조합.
이 어노테이션을 사용하면 RESTful 웹 서비스에서 발생하는 예외를 처리하고, JSON 또는 XML 형식으로 응답할 수 있음.
즉, @ControllerAdvice 와 동일한 방식으로 전역 예외 처리를 수행하면서, RESTful API 응답을 JSON 형태로 쉽게 반환할 수 있음.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ResponseStatus;
// 사용자 정의 예외 클래스
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
// 글로벌 예외 처리 클래스
@RestControllerAdvice
public class GlobalRestExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 오류 응답 클래스
public class ErrorResponse {
private String errorCode;
private String message;
// Constructors, getters, setters
public ErrorResponse(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
// Getters and Setters
public String getErrorCode() { return errorCode; }
public void setErrorCode(String errorCode) { this.errorCode = errorCode }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message }
}