티스토리 뷰

TIL(Today I Learn)

TIL 220603

minji_6119 2022. 6. 3. 21:34

💡 ORM: Object-Relational Mapping

  • Object: **"객체"**지향 언어 (자바, 파이썬) Relational: "관계형" 데이터베이스 (H2, MySQL)

https://jeong-pro.tistory.com/195

 

@ControllerAdvice, @ExceptionHandler를 이용한 예외처리 분리, 통합하기(Spring에서 예외 관리하는 방법, 실

예외 처리 과정 프로그래밍에서 예외 처리는 아주 중요하면서도 아주 어렵다. 과하다할 만큼 상세하고 다양하게 예외를 잡아 처리해준다면, 클라이언트도 그렇고 서버도 그렇고 더 안정적인 프

jeong-pro.tistory.com

스프링에서 예외처리는 크게 3가지로 나눌 수 있다.

  1. 컨트롤러단에서 처리 Controller Level - @ExceptionHandler
  2. 전역 처리 Global Level - @ControllerAdvice
  3. 메서드단위 처리 Method Level - try/catch

(@ExceptionHandler, @ControllerAdvice)

- @ControllerAdvice 를 통한 모든 Controller에서 발생한 예외를 처리

- @Exceptionhandler를 통한 특정 Controller의 예외처리

- @ControllerAdvice로 모든 컨트롤러에서 발생할 예외를 정의하고, @ExceptionHandler를 통해 발생하는 예외마다 처리할 몌소드를 정의 

  Checked Exception Unchecked Exception
처리여부 반드시 예외처리 필요 명시적 처리 강제하지 않음
확인시점 컴파일 단계 실행중 단계
예외발생시 트랜잭션 롤백하지 않음 롤백함
대표 예외 IOException
SQLException
NullPointException
IlligalArgumentException

@ControllerAdvice / RestControllerAdvice

@Controller나 @RestController에서 발생하는 예외를 한 곳에서 관리하고 처리할 수 있게 하는 어노테이션

: 설정을 통해 범위 지정이 가능하며, Default 값으로는 모든 Controller에 대해 예외처리 관리

- ex) @RestControllerAdvice(basePackages= "com.example.board")

예외 발생시 json 형태로 결과를 반환하기 위해서는 @RestControllerAdvice를 사용

@ExceptionHandler

예외 처리 상황이 발생하면 해당 Handler로 처리하겠다고 명시

어노테이션 뒤에 괄호를 붙여 어떤 ExceptionClass를 처리할지 설정

 - @ExceptionHandler(00Exception.class)

전역설정(ControllerAdvice)보다 지역 설정(Controller)로 정의한 Handler가 우선순위를 가

Custom Exception

Custom Exception 을 발생시키는 기준은 해당 Request 가 과연 Server Application의 잘못으로 일어난 잘못인가 사용자의 잘못된 요청으로 발생하는 문제인가를 잘 판단해야 한다. 

 

HttpStatus

HttpStatus는 Enum Class

EnumClass란?: 클래스처럼 보이는 상수, 서로 관련있는 상수들을 모아 심볼릭한 명칭의 집합으로 정의 한 것

error type: HttpStatus의 reasonPrase

error code: HttpStatus의 Value

message: 상황별 디테일 메세지

 

@ExceptionHandler 같은 경우는 @Controller, @RestController가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 한다.

 

외래키 설정

OneToMany
ManyToOne
OneToOne
ManyToMany

 

일대다(1:N) 단방향 연관 관계 매핑이 필요한 경우는 그냥 다대일(N:1) 양방향 연관 관계를 매핑해버리는게 추후에 유지보수에 훨씬 수월하기 때문에 이 방식을 채택하는 것을 추천

 

Mock Object

각 테스트 케이스는 서로 분리되어야 한다.

 

설정한 Custom Exception

Constants.java

public class Constants {
    public enum ExceptionClass {

        MIN_ORDER_PRICE("최소 주문 금액"), DELIVERY_FEE("배달비");

        private String exceptionClass;

        ExceptionClass(String exceptionClass) {
            this.exceptionClass = exceptionClass;
        }

        public String getExceptionClass() {
            return exceptionClass;
        }

        @Override
        public String toString() {
            return getExceptionClass() + " 오류 발생. ";
        }

    }
}

exception 패키지 내: RestaurantRegisterException

public class RestaurantRegisterException extends Exception{
    private static final long serialVersionUID = 827419284719293L;

    private Constants.ExceptionClass exceptionClass;
    private HttpStatus httpStatus;

    public RestaurantRegisterException(Constants.ExceptionClass exceptionClass, HttpStatus httpStatus, String message) {
        super(exceptionClass.toString() + message);
        this.exceptionClass = exceptionClass;
        this.httpStatus = httpStatus;
    }

    public Constants.ExceptionClass getExceptionClass(){
        return exceptionClass;
    }

    public int getHttpStatusCode() {
        return httpStatus.value();
    }

    public String getHttpStatusType() {
        return httpStatus.getReasonPhrase();
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }
}

exception 패키지 내: RestaurantRegisterExceptionHandler

@ExceptionHandler(value = RestaurantRegisterException.class)
public ResponseEntity<Map<String, String>> ExceptionHandler(RestaurantRegisterException e) {
    HttpHeaders responseHeaders = new HttpHeaders();

    Map<String, String> map = new HashMap<>();
    map.put("error type", e.getHttpStatusType());
    map.put("code", Integer.toString(e.getHttpStatusCode()));
    map.put("message", e.getMessage());

    return new ResponseEntity<>(map, responseHeaders, e.getHttpStatus());
}

validator 패키지 내

@Component
public class RestaurantValidator {
    public static void isValidPrice(int minOrderPrice, int deliveryFee) throws RestaurantRegisterException {
        if(minOrderPrice < 1000 || minOrderPrice > 100000){
            throw new RestaurantRegisterException(Constants.ExceptionClass.MIN_ORDER_PRICE, HttpStatus.BAD_REQUEST, "최소주문 가격은 1,000 ~ 100,000원 사이의 값으로 입력해주세요.");
        }
        if(minOrderPrice % 100 != 0){
            throw new RestaurantRegisterException(Constants.ExceptionClass.MIN_ORDER_PRICE, HttpStatus.BAD_REQUEST, "최소주문 가격은 100원 단위로 입력해주세요.");
        }
        if(deliveryFee < 0 || deliveryFee > 10000){
            throw new RestaurantRegisterException(Constants.ExceptionClass.DELIVERY_FEE, HttpStatus.BAD_REQUEST, "기본 배달비는 0 ~ 10,000원 사이의 값으로 입력해주세요.");
        }
        if(deliveryFee % 500 != 0){
            throw new RestaurantRegisterException(Constants.ExceptionClass.DELIVERY_FEE, HttpStatus.BAD_REQUEST, "기본 배달비는 500원 단위로 입력해주세요.");
        }
    }
}

테스트 코드

class RestaurantControllerTest {

    private String name;
    private int minOrderPrice;
    private int deliveryFee;

    @BeforeEach
    void setup() {
        name = "동대문 엽기 떡볶이";
        minOrderPrice = 14000;
        deliveryFee = 1000;
    }

    @Nested
    @DisplayName("최소주문 가격")
    class CheckMinOrderPrice{
        @Test
        @DisplayName("1000원 미만 에러")
        void fail1(){
            //given
            minOrderPrice = 500;
            RestaurantDto restaurantDto = new RestaurantDto(name, minOrderPrice, deliveryFee);

            //when
            RestaurantRegisterException exception = assertThrows(RestaurantRegisterException.class, () -> {
                new Restaurant(restaurantDto);
            });

            //then
            assertEquals(exception.getExceptionClass(), Constants.ExceptionClass.MIN_ORDER_PRICE);
        }
    }
 }

'TIL(Today I Learn)' 카테고리의 다른 글

TIL 220609  (0) 2022.06.09
TIL 220606  (0) 2022.06.06
TIL 220603  (0) 2022.06.03
TIL 220602  (0) 2022.06.02
TIL 220531  (0) 2022.06.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함