유효성 검사
유효성 검사 : 입력으로 들어오는 데이터의 형식을 검증한다. 잘못된 값이 들어왔을 때는 알맞은 예외처리를 한다.
- Bean Validation : 조건문으로 모든 유효성 검사를 하면 코드가 길어지므로 어노테이션을 통한 필드값 검증
-> spring-boot-starter-validation dependency 추가
유효성 검사 시점
클라이언트 -> 컨트롤러 -> 서비스 -> 리포지토리 -> DB
- 각 계층이 이동될 때 전달되는 데이터를 유효성 검사한다.
-> 데이터 전송에 쓰이는 DTO에서 유효성 검사를 수행한다.
@PostMapping("/valid")
public ResponseEntity<?> validate(
@Valid @RequestBody Dto dto
) {
return ResponseEntity.ok();
}
-> DTO를 받는 부분에서 @Valid 를 써주어야 검증을 수행한다.
검증 어노테이션
문자열 검증
- @Null : null 값만 가능하다.
- @NotNull : null 값은 넣을 수 없다.
- @NotEmpty : null, "" (빈 문자열) 을 넣을 수 없다.
- @NotBlank : null, "", " " (공백) 을 넣을 수 없다.
최댓값/최솟값 검증
: 입력값은 int, long, bigDecimal, bigInt 타입이 가능하다.
- @Min(value=) : 최솟값이 num이다.
- @Max(value=) : 최댓값이 num이다.
- @DecimalMin(value=) : 최솟값이 num이다. 문자열로 받을 수도 있다.
- @DecimalMax(value=) : 최댓값이 num이다. 문자열로 받을 수도 있다.
양수, 음수 검증
- @Positive : 양수를 허용한다.
- @PositiveOrZero : 0과 양수를 허용한다.
- @Negative : 음수를 허용한다.
- @NegativeOrZero : 0과 음수를 허용한다.
시간 검증
: 입력값은 Date, LocalDate, LocalDateTime 타입이 가능하다.
- @Future : 현재보다 미래의 날짜를 허용한다.
- @FutureOrPresent : 현재 포함 미래의 날짜를 허용한다.
- @Past : 현재보다 과거의 날짜를 허용한다.
- @PastOrPresent : 현재 포함 과거의 날짜를 허용한다.
이메일 검증
- @Email : 이메일 형식 (id@aaa.com)을 검증한다. ("" 는 허용)
자릿수 검증
- @Digits(integer=, fraction=) : 정수 자릿수 integer와 소수 자릿수 fraction을 지정한다.
Boolean 검증
- @AssertTrue : true만 허용
- @AssertFalse : false만 허용
문자열 길이 검증
- @Size(min=, max=) : min 이상 max 이하 값을 허용
정규식 검증
: https://regexr.com/ : 정규식 테스트
- @Pattern(regexp="") : 정규 표현식을 이용해 검증한다.
- ^ : 문자열의 시작 (^a : a로 시작하는 문자)
- $ : 문자열의 종료 (z& : z로 끝나는 문자)
- . : 임의의 한 문자 (1)
- * : 앞에 있는 문자가 없거나 여러개 (0~n)
- + : 앞에 있는 문자가 하나 이상 (1~n)
- ? : 앞에 있는 문자가 없거나 하나 존재 (0~1)
- [ ] : 문자 집합([ab])이나 범위([1-3])
- { } : 횟수 또는 범위 - a{n} : n번 반복, a{n,m} : n번~m번 사이에서 반복
- ( ) : 괄호로 묶어서 하나의 문자로 사용 (ab)*
- | : OR
- \ : 확장 문자로 다음에 특수문자(+, ^ 등)가 오면 문자로 인식
- \b : 문자와 공백(not 문자)사이의 문자 (^\b = \B)
- \A : 문자열의 시작 부분 (=^)
- \G : 이전 매치의 끝을 연속적으로 매치
- \Z : 문자열의 끝 부분 (=$) \n 이 있으면 앞부분을 비교
- \s : 공백 문자 (^\s = \S)
- \w : 알파벳이나 숫자 (^\w = \W)
- \d : 숫자 (0~9) (^\d = \D)
-> 검증에서 허용하지 않은 값을 넣을 경우 400 error를 리턴한다.
유효성 그룹
@Min(value=20, groups=ValidationGroup.class)
int age;
public ResponseEntity<?> validation(
@Validated(ValidationGroup.class) @RequestBody Dto dto
) {
return ResponseEntity.ok();
}
- @__(groups=__.class) : 인터페이스 class로 검증 어노테이션에 그룹을 지정한다.
- @Validated({__.class}) : 검증할 그룹을 지정한다.
-> @Validated에서 그룹을 지정하면 groups에 해당하는 검증만 수행한다.
-> @Validated에서 그룹을 지정하지 않으면 groups가 설정되지 않은 검증만 수행한다.
커스텀 Validation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CustomValidator.class)
public @interface T {
String message() default "";
Class[] groups() default {};
Class[] payload() default {};
}
public class CustomValidator implements ConstraintValidator<T, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return false;
}
return value.matches(" "); // 표현식과 value가 일치하면 true를 리턴
}
}
@T
private String t; // t에 값이 들어오면 CustomValidator로 검증한다.
- ConstraintValidator를 구현하여 isValid 메서드를 통해 직접 유효성 검증을 수행한다.
- false가 리턴되면 MethodArgumentNotValidException 발생
- ContraintValidator에서 지정한 Annotation T = Entity에서 사용할 유효성 검증 어노테이션
- Target : 해당 어노테이션을 어디서 선언할 수 있는지 정의한다.
- PACKAGE, TYPE, CONSTRUCTOR, FIELD, METHOD, ANNOTATION_TYPE, LOCAL_VARIABLE, PARAMETER, TYPE_PARAMETER, TYPE_USE
- Retention : 어노테이션이 실제로 적용되고 유지되는 범위
- RUNTIME(컴파일 이후에도), CLASS, SOURCE
- Constraint : CustomValidator를 매핑한다.
- message() : 유효성 검사가 실패할 경우 리턴할 메시지
- groups() : 유효성 검사를 사용하는 그룹 설정
- payload() : 사용자가 추가 정보를 위해 전달하는 값
- Target : 해당 어노테이션을 어디서 선언할 수 있는지 정의한다.
예외 처리
- 예외 (Exception) : 애플리케이션에 정상적으로 동작할 수 없는 상황에 발생하며 try-catch 로 발생한 예외를 처리하거나 throw로 원하는 예외를 발생시킬 수도 있다.
- 에러 : StackOverFlow, OutOfMemory 등 자바 가상머신에서 발생하는 문제로, 코드에서 처리할 수 없고 발생 가능성을 원천 차단해야 한다.

-> 모든 예외는 Throwable 을 상속 받는다.
-> Exception의 자식 클래스는 Checked Exception, Unchecked Exception으로 나뉜다.
- CheckedException : 컴파일 과정에서 확인 가능한 예외이므로 무조건 예외 처리를 해주어야 한다.
- IOException, SQLException 등
- UncheckedException : 실행 중에 발생을 알 수 있는 예외로 처리하지 않아도 따로 에러가 뜨지 않는다.
- RuntimeException, NullPointerException, IllegalArgumentException, IndexOutOfBound 등
예외 처리 방법
- 예외 복구 : 예외 상황을 파악해 처리 -> try-catch
- 예외 처리 회피 : 예외를 다시 발생시켜 해당 메서드를 호출한 곳으로 예외 처리를 전가 -> 해당 메서드는 throw를 하므로 호출하는 곳에서 예외처리가 강제적으로 필요하다.
- 예외 전환 : 발생한 예외를 다른 적합한 예외로 다시 발생시켜 처리를 위임 -> throw new otherException
스프링의 예외 처리
: 스프링에서는 주로 클라이언트에게 문제 발생/원인을 알리기 위해 컨트롤러로 오류메시지를 전달하는 방식으로 예외를 처리한다.
@(Rest)ControllerAdvice : 모든 컨트롤러의 예외를 처리하는 클래스에 사용한다.
@RestControllerAdvice(basePackages="com.org.*")
public class CustomExceptionHandler {
@ExceptionHandler(value=Exception.class)
public ResponseEntity<?> handle(Exception e, HttpServletRequest request) {
HttpHeaders header = new HttpHeaders();
HttpStatus status = HttpStatus.BAD_REQUEST;
Map<String, Object> map = new HashMap<>();
map.put("message", "");
map.put("code", 500);
return ResponseEntity<>(map, header, status);
}
}
- basePackage로 해당 예외 처리를 하게 될 패키지 범위를 지정할 수 있다.
- 컨트롤러에서 리턴하는 것과 무관하게 해당 ExceptionHandler 메서드에서 리턴하는 값을 클라이언트로 리턴한다.
- @ExceptionHandler : value에서 발생하는 예외를 처리하는 메서드를 정의하는데 사용하며, value는 배열로 입력하여 여러 예외를 처리할 수도 있다. 특정 컨트롤러에 작성하면 해당 컨트롤러에서 발생하는 예외만 처리한다.
Exception 우선순위
: Exception Handler가 여러개 있고, 발생한 Exception이 여러 개에 해당되는 경우 우선순위에 따라 처리된다.
- 전역 Handler (ControllerAdvice) < 컨트롤러 내 Handler
- 구체적인 (하위) Exception : Exception < RuntimeException < NullPointerException
커스텀 예외
: 직접 Throwable 하위(Exception 등)클래스를 상속받아 만들어서 호출(throw)하고 처리할 수 있는 예외.
장점 및 효과
- 발생하는 예외에 적합한 원하는 이름을 지을 수 있다.
- 직접 코드로 예외를 관리하며 상황에 맞게 처리 할 수 있다.
- 의도하지 않은 경우에서는 커스텀 Exception이 발생하지 않는다.
public class CustomException extends Exception {
private HttpStatus httpStatus;
public CustomException(String message, HttpStatus httpStatus) {
super(message);
this.httpStatus = httpStatus;
}
}
- 부모 클래스인 Exception(String message)로 생성자 호출
- HttpStatus의 value(error code), series, resonPhrase(error type)를 이용해서 필요한 값을 편리하게 정의할 수 있고 status에 맞는 예외 처리를 할 수 있다.
- throw new CustomException("message", HttpStatus.__) 로 호출
'공부 > 백엔드' 카테고리의 다른 글
| [스프링 부트 핵심 가이드] 12 : 서버 간 통신 (0) | 2024.06.10 |
|---|---|
| [스프링 부트 핵심 가이드] 11 : 액추에이터 활용하기 (1) | 2024.06.08 |
| [스프링 부트 핵심 가이드] 9 : 연관관계 매핑 (0) | 2024.05.25 |
| [스프링 부트 핵심 가이드] 8 : Spring Data Jpa (0) | 2024.05.19 |
| [스프링 부트 핵심 가이드] 6 : 스프링 데이터베이스 연동 (0) | 2024.05.10 |