Java Spring Boot 006-1 | Exception Handling

Yunny.Log ·2022년 3월 3일
0

Spring Boot

목록 보기
27/80
post-thumbnail

Exception

1) try-catch exception 처리

  • finally : 항상 실행하는 코드
    (ex) 파일을 닫는 작업 처리를 finally에 담아준다

2) throws

  • 예외처리를 호출하는 대상에게 예외를 던져버리기
  • Java에서는 Method Signature의 일부로 처리되지 않은 예외는 compile error 발생
    (RuntimeException 제외)

Spring Boot 예외처리

ResponseStatusException : 단발적 예외

  • 따로 메소드 안만들고

1) ExceptionTestController 제작

@RestController
@RequestMapping("except")
public class ExceptTestController {
    @GetMapping("{id}")
    public void throwException(@PathVariable int id){
        switch(id){
            default :
                throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
    }

    @ExceptionHandler()
    //이 함수는 지정된 예외에 대해서 그 예외를 처리 ㅇ
    public void handlerException(){

    }
}
  • 이제 exception들 모아놓은 패키지 만들기

  • exception 패키지 만들기

  • 그 안에 BaseException 클래스 만들기 (모든 예외들이 공통적으로 가질 속성)

  • PostNotExistException 클래스도 만들게여

  • 그리고 아까 만들었던 exceptionController

@ExceptionHandler : Controller 내부 예외

- Controller에 ExceptionHandler 만들기

  • 얘는 자신이 선언된 컨트롤러 내부에서만 작동하게 됨
@RestController
@RequestMapping("except")
public class ExceptTestController {
    @GetMapping("{id}")
    public void throwException(@PathVariable int id){
        switch(id){
            case 1:
                throw new PostNotExistException();
            default :
                throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
    }

    @ExceptionHandler(BaseException.class)
    //이 함수는 지정된 예외에 대해서 그 예외를 처리 ㅇ
    // 컨트롤러 내부에서 발생하는 모든 baseexception(+얘 상속받은)
    // 예외들이 나타나면 이 메소드 실행
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponseDto handleBaseException(BaseException exception){
        //이 안에 넣어줄 예외 아이 -> ErrorResponseDto
        return new ErrorResponseDto(exception.getMessage());
    }
}

ErrorResponseDto

  • 컨트롤러에서 넘겨줄 dto 아이
public class ErrorResponseDto {
    private String message;
  • 근데 아직까지 실질적으로 메세지 존재하지 않음
  • 메시지를 만들어주러 아까 만들어두었던

BaseException

public class BaseException extends RuntimeException{
    //제네레이트 -> overridemethod -> runtimeexception
    public BaseException(String message) {
        super(message);
    }
}

PostNotExistException

public class PostNotExistException extends BaseException{
    public PostNotExistException(){
        super("Post does not exist excpetion");
    }
}
  • 하고 실행하면 예외 처리 메시지 뜬다
    => (id를 1로 넣어줄 때)

  • 다른 예외 제작

  • InconsistentDataException
    : 그 게시판에 게시글이 없었을 때의 예외

public class InconsistentDataException extends BaseException{
    public InconsistentDataException(){
        super("Post not in Board");
    }
}
  • ExceptionController에 case 추가
    => (id를 2로 넣어줄 때 예외 발생하도록 ㅇ)
        switch(id){
            case 1:
                throw new PostNotExistException();
            case 2:
                throw new InconsistentDataException();
            default :
                throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }

  • ExceptionController가 얘가 붙어있는 컨트롤러에서만 발생한다는 것을 알아보기 위한PostController 코드 추가
    @GetMapping("test-exception")
    public void throwException(){
        throw new PostNotExistException();
    }

HandlerExceptionResolver 만들기 : 예외 처리 Handler

  • 프로그램 전체에서 발생하는 예외 처리 가능

  • 이거 하고 돌려보면 메시지로 뜨지 않고 로그에만 남는다 (excpetionHandler이 여기까지 닿지 않음 확인 ㄱㄴ)

  • HandlerExceptionResolver 제작하기

  • 이를 위해서 handler 이라는 패키지 만들기

  • 그 패키지 안에 PostExceptionResolver 클래스 제작

@Component
public class PostExceptionResolver extends AbstractHandlerExceptionResolver {
    @Override//추상클래스의 메소드 받아오기
    protected ModelAndView doResolveException(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler,
            Exception ex) {
        return null;//null은 예외가 처리되지 못했을 때 반환되는 값
    }
}
  • 이 HandlerExceptionResolver 아이는 예외가 발생되면 그 예외를 처리할 수 있는 애가 있는지 쭉 둘러보면서 처리가능한 애 있으면 처리 ㅇ
  • Component 도 붙여줘야 빈으로 등록돼서 작동 ㅇ
  • 그리고 try문에 돌려줄 문자메시지도 지정해줘야 한다, 이를 추가 지정해보자
        if(ex instanceof BaseException) {
            //만약 예외가 BaseException의 구현체라면 ModelandView를 반환하지 않고
            //데이터만 돌려주고 시픔
            //이를 위한 간단한 처리 방법은 아래와 같음
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            try {
                response.getOutputStream().print(
                        //여기에 실제적인 반환문자열 입력해줘야 함
                        new ObjectMapper().writeValueAsString(
                                //자바 객체 -> json 으로 변경해준다
                                new ErrorResponseDto("in resolver, message : " +
                                        ex.getMessage()
                                )
                        )
                );
  • 그리고 헤더에게 우리가 돌려줄 문자열이 json임을 알려주어야 한다 -> 헤더 설정
  • 위의 코드 아래에 바로 넣어준다
                response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
                return new ModelAndView();
  • 우리가 실제 주고받는 것을 ModelandView로 하지 않기 때문에 ModelAndView안에 뭘 따로 넣어줄 필요는 없다

  • 이렇게 하고 아까 PostController에서 만들어뒀던 test-exception 아이 실행시키기

ControllerAdvice 만들기 : ExceptionHandler 모음

  • handler 패키지에 PostControllerAdvice 만들기

    @ControllerAdvice 란?(출처)

  • @Controller나 @RestController에서 발생한 예외를 한 곳에서 관리하고 처리할 수 있게 도와주는 어노테이션
@ControllerAdvice
//@RestControllerAdvice로 어노붙이면 아래서 ResponseBody 없애주기
public class PostControllerAdvice {
    @ExceptionHandler(BaseException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public @ResponseBody ErrorResponseDto handleException(BaseException exception){
        return new ErrorResponseDto(exception.getMessage());
    }
}
  • 지난 시간에 배웠던 Valid와 사용해보기
  • valid하지 않을 때, 실행시킬 예외를 맵핑해주기
  • 위 코드에 아래 코드 추가
    @ExceptionHandler(MethodArgumentNotValidException.class)
    //valid는 에러가 다수일 때도 있어서 해당 경우를 예외처리해주기도 필요할 수도
    public ErrorResponseDto handleValidException(
            MethodArgumentNotValidException exception) {
           return new ErrorResponseDto(exception.getMessage());
    }

0개의 댓글