• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (92)
      • 스프링부트 (52)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (0)
      • ETC (8)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      • 반응형
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • Spring REST 서비스 예외 처리 방법
        2023년 11월 09일
        • 알쓸개잡
        • 작성자
        • 2023.11.09.:39

        Spring에서는 전체 예외 처리에 대한 추상화를 제공하고 몇 가지 annotation만으로 예외 처리를 손쉽게 할 수 있다.

        이번 포스팅에서는 Spring REST 서비스에서 예외를 처리하는 방법과 HTTP 응답 상태코드를 반환하는 방법에 대해서 기록한다.

         

        1. 예외 수동 처리

        다음 Controller 코드는 HttpStatus와 함께 응답 body 페이로드를 포함하는 ResponseEntity를 반환한다.

        • 예외가 발생하지 않으면 200 코드와 함께 body 페이로드로 Member를 응답한다.
        • ResourceNotFoundException 예외가 발생하는 경우 empty body와 404 코드를 응답한다.
        • MemberServiceException 예외가 발생하는 경우 empty body 와 500 코드를 응답한다.

        예외 클래스는 RuntimeException을 확장한 ResourceNotFoundException과 MemberServiceException이다.

        package com.example.jpa.exception;
        
        public class ResourceNotFoundException extends RuntimeException{
        	public ResourceNotFoundException() {
        		super();
        	}
        
        	public ResourceNotFoundException(String message) {
        		super(message);
        	}
        }
        package com.example.jpa.exception;
        
        public class MemberServiceException extends RuntimeException{
        	public MemberServiceException() {
        		super();
        	}
        
        	public MemberServiceException(String message) {
        		super(message);
        	}
        }
        @RestController
        @RequestMapping("/members")
        @RequiredArgsConstructor
        public class MemberController {
        	private final MemberService memberService;
        
        	@GetMapping("/{memberId}")
        	public ResponseEntity<Member> getMember(@PathVariable Long memberId) {
        		Member member;
        		try {
        			member = memberService.getMember(memberId);
        		} catch (MemberServiceException e) {
        			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        		} catch (ResourceNotFoundException e) {
        			return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        		}
        
        		return ResponseEntity.ok(member);
        	}
        }

        컨트롤러의 endpoint 메서드 내에서 직접 예외 처리를 하고 있는데 이 방식의 문제점은 중복이다.

        DELETE, POST를 처리하는 다른 endpoint에서도 중복되는 예외 처리 코드가 필요할 수 있다.

         

         

        2. 예외 클래스에 ResponseStatus annotation 사용

        두 번째 방법은 예외 클래스에 @ResponseStatus annotation을 지정하여 해당 예외가 발생했을 때 지정된 ResponseStatus 코드로 자동 응답 하도록 할 수 있다.

        package com.example.jpa.exception;
        
        import org.springframework.http.HttpStatus;
        import org.springframework.web.bind.annotation.ResponseStatus;
        
        @ResponseStatus(HttpStatus.NOT_FOUND)
        public class ResourceNotFoundException extends RuntimeException{
        	public ResourceNotFoundException() {
        		super();
        	}
        
        	public ResourceNotFoundException(String message) {
        		super(message);
        	}
        }
        package com.example.jpa.exception;
        
        import org.springframework.http.HttpStatus;
        import org.springframework.web.bind.annotation.ResponseStatus;
        
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public class MemberServiceException extends RuntimeException{
        	public MemberServiceException() {
        		super();
        	}
        
        	public MemberServiceException(String message) {
        		super(message);
        	}
        }
        @RestController
        @RequestMapping("/members")
        @RequiredArgsConstructor
        public class MemberController {
        	private final MemberService memberService;
        
        	@GetMapping("/{memberId}")
        	public ResponseEntity<Member> getMember(@PathVariable Long memberId) {
        		Member member = memberService.getMember(memberId);
        		return ResponseEntity.ok(member);
        	}
        }

        memberService.getMember 메서드 내부에서 MemberServiceException, ResourceNotFoundException이 발생하는 경우 각 예외 클래스에 @ResponseStatus에 지정된 응답 코드로 응답을 한다.

        예외가 발생한 경우 다음과 같이 응답 payload도 함께 전송된다.

        {
            "timestamp": "2023-11-09 00:05:56",
            "status": 404,
            "error": "Not Found",
            "path": "/members/1"
        }

         

         

        3. Controller Advice 클래스 (@ControllerAdvice)

        Spring은 @ControllerAdvice 클래스 annotation 이 지정된 클래스를 통해서 중앙 집중적으로 모든 예외에 대한 처리를 할 수 있도록 지원한다.

        @ControllerAdvice
        public class ControllerAdviser {
        
        	@ExceptionHandler({RuntimeException.class})
        	public ResponseEntity<String> runtimeException(RuntimeException e) {
        		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        	}
        
        	@ExceptionHandler({ResourceNotFoundException.class})
        	public ResponseEntity<String> resourceNotFoundException(ResourceNotFoundException e) {
        		return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
        	}
        
        	@ExceptionHandler({MemberServiceException.class})
        	public ResponseEntity<String> memberServiceException(MemberServiceException e) {
        		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        	}
        }

        @ExceptionHandler annotation에 지정된 예외를 처리하는 handler 메서드를 등록하여 처리한다.

        @RestController
        @RequestMapping("/members")
        @RequiredArgsConstructor
        public class MemberController {
        	private final MemberService memberService;
        
        	@GetMapping("/{memberId}")
        	public ResponseEntity<Member> getMember(@PathVariable Long memberId) {
        		Member member = memberService.getMember(memberId);
        		return ResponseEntity.ok(member);
        	}
        }

         

         

        @ExceptionHandler annotation 이 지정된 handler 메서드에 @ResponseStatus annotation을 지정할 수 있다.

        @ControllerAdvice
        public class ControllerAdviser {
        
        	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        	@ExceptionHandler({RuntimeException.class})
        	public void runtimeException() {}
        
        	@ResponseStatus(HttpStatus.NOT_FOUND)
        	@ExceptionHandler({ResourceNotFoundException.class})
        	public void resourceNotFoundException() {}
        
        	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        	@ExceptionHandler({MemberServiceException.class})
        	public void memberServiceException() {}
        }

        위와 같이 지정된 경우에는 body payload 없이 코드만 응답한다.

        예외 클래스에 @ResponseStatus 어노테이션이 적용되어 있고 @ControllerAdvice 클래스의 예외 핸들러에 @ResponseStatus 어노테이션이 적용되어 있는 경우 @ControllerAdvice 클래스의 예외 핸들러가 동작한다.
        반응형
        저작자표시 비영리 변경금지 (새창열림)

        '스프링부트' 카테고리의 다른 글

        spring scheduler task에 shedlock + redis 적용방법  (0) 2023.11.20
        spring multi module 프로젝트 만들기  (0) 2023.11.19
        Spring Boot Embedded Tomcat 서버 설정  (0) 2023.11.03
        Spring Data JPA 에서 공간 정보(Spatial Data) 사용하기  (0) 2023.11.01
        Spring REST 컨트롤러에서 HTTP 헤더 읽기  (0) 2023.10.29
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바