[스프링 부트 핵심가이드] 유효성 검사와 예외처리 (2)🐢

FeelingXD·2023년 4월 16일
0

북스터디

목록 보기
8/13
post-thumbnail

예외 처리 ⚠️

예외(Exception) 과 에러(error)

프로그래밍에서의 예외(Exception)란 입력 값의 처리가 불가능하거나 참조된 값이 잘못된 경우 등 애플리케이션이 정상적으로 동작하지못하는 상황을 의미합니다, 예외는 개발자가 직접 처리할수 있는것이므로 미리 코드 설계를 통해 처리할수 있습니다.

example(divideZero,outOfIndex)등 ..

반면 에러는 개발자가 직접 컨트롤할수 없는부분 (시스템 영역)

  • StackOverFlow(Stack 메모리 부족)
  • OutofMemory(메모리 부족)

예외 처리 방법

예외가 발생했을때 이를 처리하는데에는 크게 3가지 방법을사용합니다.

  • 예외 복구
  • 예외 처리 회피
  • 예외 전환

예외 복구 🤔

예외복구는 예외 상황을 파악해서 문제를 해결하는 방식으로 대표적인 방법으로 try/catch문을 예로들수있습니다. try 에는 예외가 발생할수있는 코드를 catch문에는 예외발생시 필요한 로직을 작성하는것으로 예외시 복구방법을 정의한후 예외 유형에따른 복구동작을 실행합니다.

예외 처리 회피 🙄

예외 처리를 회피 하는 방법은 예외가 발생한 시점에서 바로 처리하는것이 아닌 예외가 발생한 메서드를 호출한 곳에서 에러를 처리할수 있게 전가하는 방식입니다. 이때 throw 키워드를 사용하여 어떤예외가 발생했는지 호출부에 내용을 전달할수있습니다.

예외 전환 ♻️

예외 전환 은 앞의 두 예외처리 방법을 적절하게 섞은 방식으로 예외가 발생했느냐에 따라 호출부로 예외 내용을 전달하면서 좀더 적합한 예외 타입으로 전달 해야하는 경우가 발생합니다.(에러 로그등)

이런 경우에 try/catch 방식을 사용함과 동시에 catch블록을 지정하여 throw 키워드로 다른 예외 타입으로 전달합니다.

스프링 부트의 예외처리 🍃

스프링 부트에서 예외가 발생했을 때 클라이언트에 오류 메세지를 전달하려면 각 레이어에서 발생한 예외를 엔드포인트레벨인 컨트롤러로 전달 해야합니다. 이렇게 전달받은 예외를 스프링 부트에서 처리하는 방식으로는

  • @(Rest)ControllerAdvise 와 @ExceptionHandler 을 사용한 컨트롤러의 예외처리

  • @ExceptionHandler 을 이용하여 특정 예외를 처리

하는 방법이 있습니다.

예제

//Controller
@RequestMapping("/test")
public class testController {

    @GetMapping
    public void throwRuntimeException(){
        throw new RuntimeException("기본적인 runtimeException");
    }
}
// ControllerAdvise
@RestControllerAdvice
public class CustomException {

    @ExceptionHandler(value = RuntimeException.class) //-> RuntimeException 발생시 메소드 실행
    public ResponseEntity<Map<String,String>> handleExcept(Exception e, HttpServletRequest req){
        Map<String,String> map=new HashMap<>();
        map.put("error type", HttpStatus.BAD_REQUEST.getReasonPhrase());
        map.put("code","400");
        map.put("message", e.getMessage());

        return new ResponseEntity<>(map,HttpStatus.BAD_REQUEST);
    }

}

위의 예제코드는 RestController에대한 예외처리로 RestControllerAdvise 만들어 주었다.

특정 패키지에대한 (Rest)ControllerAdvise를 설정하고 싶다면 아래와같이 코드를 추가할수있다.

@RestContollerAdvise(basePackages ="com.example.yourpackage") // basePackges  추가

위의 예제는 testController 에서 매핑된 /test 경로를 호출시 RuntimeException을 발생시키고 ControllerAdvice에서 해당 RuntimeException의 error type, code, message 를 받아 반환한다.

이외에도 필요시 @ExceptionHandler 을 추가함으로써 다양한 예외시 어떤 방법으로 처리할지 커스텀할수있다.

예외 처리에서 우선순위

스프링에서는 항상 더 상세한것(하위 클래스, 객체)이 우선순위를 가진다.( 자식 > 부모 , 지역설정 > 전역설정)

같은 예외처리가 있더라도 Controller단에서 해당 Exception에대한 처리가 있다면 ControllerAdvise 에지정되어있더라도 Controller 처리됩니다.

아래와 같이 Controller 수정시 ControllerAdvise 로 넘어가지않고 Controller 에서 우선 적으로 처리됩니다.


//Controller
@RequestMapping("/test")
public class testController {
	@ExceptionHandler(value = RuntimeException.class) 
    public ResponseEntity<Map<String,String>> handleExcept(Exception e, HttpServletRequest req){
        Map<String,String> map=new HashMap<>();
        map.put("error type", HttpStatus.BAD_REQUEST.getReasonPhrase());
        map.put("code","400");
        map.put("message", "Controller handling");

        return new ResponseEntity<>(map,HttpStatus.BAD_REQUEST);
    }
    @GetMapping
    public void throwRuntimeException(){
        throw new RuntimeException("기본적인 runtimeException");
    }
}

한번에 처리하기

같은 메소드 시행이 필요한경우 Exception handler에 묶어서 처리할수 있다.

  @ExceptionHandler(value = {RuntimeException.class,UserException.class}) //-> 
    public CustomErrorResult error(Exception e){
    		// 로직작성 ~.
    }

예외클래스의 생략

예외 클래스 생략시 피라미터로 들어오는 Exception을 핸들링 한다.

@ExceptionHandler
    public CustomErrorResult error(CustomerException e){ //CustomerException 에대한 처리 
    		// 로직작성 ~.
    }

profile
tistory로 이사갑니다. :) https://feelingxd.tistory.com/

0개의 댓글