북스터디 : 스프링 부트 핵심가이드(6)

윤장원·2023년 4월 15일
0

10. 유효성 검사와 예외 처리

스프링 부트에서의 유효성 검사

pom.xml 파일에 유효성 검사 라이브러리를 의존성으로 추가하면 사용할 수 있다.

<dependency>
	<groupId>org.springframwork.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

유효성 검사는 각 계층으로 데이터가 넘어오는 시점에 해당 데이터에 대한 검사를 실시한다. 스프링 부트 프로젝트에서는 계층 간 데이터 전송에 대체로 DTO 객체를 활용하고 있기 때문에 유효성 검사를 DTO 객체를 대상으로 수행하는 것이 일반적이다.

문자열 검증

  • @Null : null 값만 허용한다.
  • @NotNull : null을 허용하지 않는다. ""," "는 허용한다.
  • @NotEmpty : null, ""을 허용하지 않는다. " "는 허용한다.
  • @NotBlank : null, "", " "을 허용하지 않는다.

최댓값/최솟값 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @DecimalMax(value = "$numberString") : $numberString보다 작은 값을 허용한다.
  • @DecimalMin(value = "$numberString") : $numberString보다 큰 값을 허용한다.
  • @Min(value = $number) : $number 이상의 값을 허용한다.
  • @Max(value = $number) : $number 이하의 값을 허용한다.

값의 범위 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @Positive : 양수를 허용한다.
  • @PositiveOrZero : 0을 포함한 양수를 허용한다.
  • @Negative : 음수를 허용한다.
  • @ NegativeOrZero : 0을 포함한 음수를 허용한다.

시간에 대한 검증

  • Date, LocalDate, LocalDateTime 등의 타입을 지원한다.
  • @Future : 현재보다 미래의 날짜를 허용한다.
  • @FutureOrPresent : 현재를 포함한 미래의 날짜를 허용한다.
  • @Past : 현재보다 과거의 날짜를 허용한다.
  • @PastOrPresent : 현재를 포함한 과거의 날짜를 허용한다.

이메일 검증

  • @Email : 이메일 형식을 검사한다. ""는 허용한다.

자릿수 범위 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @Digits(integer = $number1, fraction = $number2) : $number1의 정수 자릿수와 $number2의 소수 자릿수를 허용한다.

Boolean 검증

  • @AssertTrue : true인지 체크한다. null 값은 체크하지 않는다.
  • @AssertFalse : false인지 체크한다. null 값은 체크하지 않는다.

문자열 길이 검증

  • @Size(min = $number1, max = $number2) : $number1 이상 $number2 이하의 범위를 허용한다.

정규식 검증

  • @Pattern(regexp = "$expression") : 정규식을 검사한다. 정규식은 자바의 java.util.regex.Pattern 패키지의 컨벤션을 따른다.

유효성 검사를 수행하기 위해서는 @Valid 어노테이션을 지정해야한다.

@Validated 활용

@Valid 어노테이션은 자바에서 지원하는 어노테이션이며, 스프링도 @Validated라는 별도의 어노테이션으로 유효성 검사를 지원한다. @Validated은 @Valid 어노테이션의 기능을 포함하고 있기 때문에 @Validated로 변경할 수 있다. 또한 @Validated는 유효성 검사를 그룹으로 묶어 대상을 특정할 수 있는 기능이 있다.

예외 처리 방법

예외 처리 방법은 크게 세 가지가 있다.

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

예외 복구 방법은 예외 상황을 파악해서 문제를 해결하는 방식이다. 대표적인 방법이 try/catch 구문이다. try 블록에는 예외가 발생할 수 있는 코드를 작성한다. 그리고 catch 블록을 통해 try 블록에서 발생하는 예외 상황을 처리하는 내용을 작성한다. 이때 catch 블록은 여러 개를 작성할 수 있다. 이 경우 예외 상황이 발생하면 애플리케이션은 여러 개의 catch 블록을 순차적으로 거치면서 예외 유형과 매칭되는 블록을 찾아 예외 처리 동작을 수행한다.

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

예외 전환 방법은 앞의 두 방식을 적절하게 섞은 방식이다. 예외가 발생했을 때 어떤 예외가 발생했느냐에 따라 호출부로 예외 내용을 전달하면서 좀 더 적합한 예외 타입으로 전달할 필요가 있다. 또는 애플리케이션에서 예외 처리를 좀더 단순하게 하기 위해 래핑(wrapping)해야 하는 경우도 있다. 이런 경우에는 try/catch 방식을 사용하면서 catch 블록에서 throw 키워드를 사용해 다른 예외 타입으로 전달하면 된다.

스프링 부트의 예외 처리 방식

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

  • @(Rest)ControllerAdvice와 @ExceptionHandler를 통해 모든 컨트롤러의 예외를 처리
  • @ExceptionHandler를 통해 특정 컨트롤러의 예외를 처리

만약 @ControllerAdvice와 컨트롤러 내에 동일한 예외 타입을 처리한다면 구체적인 클래스가 지정된 쪽, 범위가 좁은 컨트롤러의 핸들러 메서드가 우선순위를 갖게 된다.

커스텀 예외

커스텀 예외를 만들어서 사용하면 네이밍에 개발자의 의도를 담을 수 있기 때문에 이름만으로도 어느 정도 예외 상황을 짐작할 수 있다. 또한 커스텀 예외를 사용하면 애플리케이션에서 발생하는 예외를 개발자가 직접 관리하기가 수월해진다. 표준 예외를 상속받은 커스텀 예외들을 개발자가 직접 코드로 관리하기 때문에 책임 소재를 애플리케이션 내부로 가져올 수 있게 된다. 이를 통해 동일한 예외 상황이 발생할 경우 한 곳에서 처리하며 특정 상황에 맞는 예외 코들르 적용할 수 있게 된다.

커스텀 예외는 예외가 발생하는 상황에 해당하는 상위 예외 클래스를 상속받는다. 그래서 커스텀 예외는 상위 예외 클래스보다 좀 더 구체적인 이름을 사용하기도 한다.

커스텀 예외 클래스를 생성하는 데 필요한 내용은 다음과 같다.

  • 에러 타입 : HttpStatus의 reasonPrase
  • 에러 코드 : HttpStatus의 value
  • 메시지 : 상황별 상세 메시지

0개의 댓글