회원가입을 할 때 특정 형식의 값일 때에만
회원가입이 가능하게 하려면 어떻게 해야할까?
환경
--
- IntelliJ community 2023.1.5
- Spring Boot 3.2.1
- JDK 17
build.gradle [ dependencies ]
implementation 'org.springframework.boot:spring-boot-starter-validation'
기존 'org.springframework.boot:spring-boot-starter-web' 의존성 안에 validation이 포함되어 있었지만
Spring Boot 2.3 부터는 포함되어 있지 않기 때문에 따로 validation 의존성을 추가해야한다.
만약 @Valid가 아니라 @Validated 어노테이션을 사용한다면 해당 의존성은 필요없다.
--
validation 이란?
--
Spring에서 제공하는 기능으로 데이터의 유효성을 검사하고 처리하는데 사용하는 유용한 기능이다.
즉, 주어진 데이터나 입력 받은 데이터가 특정 조건을 충족하는지를 확인하고 결과에 따라 처리할 수 있는 기능며
주로 @Valid과 @Validated 어노테이션을 사용하여 유효성 검사를 수행한다.
ex)
회원가입시 아이디가 비어있는 상태로 가입버튼을 눌러서 서버로 데이터를 전달한다거나
아이디를 입력할 때 8 ~ 20자 내로 입력한 데이터가 맞는지 등을 검사한다.
--
@Valid 란?
--
@Valid는 자바 표준 검증 어노테이션으로 Bean Validation API와 함께 사용되며
주로 컨트롤러에서 메서드의 파라미터나 메서드 내부에서 검사 대상 객체에 대해서 유효성을 검사하는 어노테이션이다.
그리고 @ModelAttribute와 @RequestBody에 적용하여 사용할 수 있다.
Bean Validation API란?
자바에서 제안된 표준 API로, 객체의 유효성 검사를 위한 기능들을 제공한다.
해당 API에서 제공하는 어노테이션들을 이용하여 객체의 속성에 대한 제약 조건을 정의하고,
이를 바탕으로 객체의 유효성을 검사할 수 있다.
그리고 검증에 실패하면 검증 오류에 대한 정보도 제공하여
해당 오류를 적절하게 처리도 할 수 있게 된다.
해당 API에서 제공하는 어노테이션들은
@Valid, @NotNull, @Size, @Max, @Pattern 등이 있다.
해당 어노테이션으로 유효성 검사에 실패하면 MethodArgumentNotValidException 예외가 발생한다.
--
@Validated 는?
--
@Validated또한 @Valid와 동일하지만 스프링 전용 검증 어노테이션으로
내부에 groups라는 기능을 추가로 포함하고 있어서
주로 그룹의 유효성 검사나 컨트롤러가 아닌 다른 계층에서 유효성 검증을 한다.
물론 컨트롤러에서도 유효성 검증이 가능하다.
groups 속성이란?
Bean Validation API에서 제공하는 그룹 유효성 검사를 의미하고
해당 기능은 특정 그룹에 속한 제약 조건만을 검사할 수 있도록 해준다.
그룹 유효성 검사를 하려면 하나의 객체에 대해 여러 그룹의 제약 조건을 정의할 수 있고
필요에 따라 특정 그룹의 제약 조건만을 검사할 수도 있다.
즉, 하나의 객체에 여러 제약 조건을 정의하고 상황에 따라 서로 다른 제약 조건을 적용할 수 있다.
해당 어노테이션으로 유효성 검사에 실패하면 ConstrainViolationException 예외가 발생한다.
--
어노테이션 종류
--
어노테이션 | 설명 |
@Null | null이어야 한다. |
@NotNull | null이 아니어야 한다. |
@NotEmpty | null이 아니고, 빈 문자열이나 빈 컬렉션이 아니어야 한다. |
@NotBlank | null이 아니고, 빈 문자열도 아니며, 공백 문자도 아니어야 한다. |
@Min | 지정된 값 이상이어야 한다. |
@Max | 지정된 값 이하여야 한다. |
@Size(min = , max = ) | 문자열의 길이 또는 컬렉션의 크기가 min 이상 max 이하여야 한다. |
이메일 형식이어야 한다. (중간에 @ 포함되어야 함) | |
@Pattern(regexp = ) | 문자열이 지정된 정규식을 만족해야 한다. |
@Past | 시점이 과거여야 한다. |
@PastOrPresent | 시점이 과거 또는 현재여야 한다. |
@Future | 시점이 미래여야 한다. |
@FutureOrPresent | 시점이 미래 또는 현재여야 한다. |
@AssertTrue | 조건이 참이어야 한다. |
@AssertFalse | 조건이 거짓이어야 한다. |
@Negative | 음수여야 한다. |
@NegativeOrZero | 음수 또는 0이어야 한다. |
@Positive | 양수여야 한다. |
@PositiveOrZero | 양수 또는 0이어야 한다. |
각 어노테이션에는 공통적으로 message 속성이 존재하는데
해당 속성은 유효성 검사에 실패하여 예외가 발생할 때 반환할 메세지이다.
@Pettern에서 정규식 작성하는 방법
정규 표현식 | 설명 |
a | 문자열 내에 "a"라는 문자열이 포함되어 있어야 한다. |
[abcd] | 문자열 내에 "a", "b", "c", "d" 중에 하나라도 포함되어 있어야 한다. |
^ | 문자열의 시작을 의미하는 기호 |
[^] | [ ] 괄호 안에 있는 ^는 제외를 의미 ( [^5] = 5를 제외한 문자 ) |
$ | 문자열의 끝을 의미하는 기호 |
\w | 아무 문자를 의미 (단, 띄어쓰기, 특수문자, 한글은 제외) |
\W | \w의 부정 |
\d | 아무 숫자를 의미 (0 ~ 9 중에 하나) |
\D | \d의 부정 |
\s | 아무 공백 문자를 의미 (띄어쓰기, 엔터, 탭 등) |
\S | \s의 부정 |
\b | 공백, 탭, ",", "/" 등을 의미 |
\B | \b의 부정 |
| | or 를 의미하는 기호 |
[] | [ ] 괄호 안의 문자가 존재하는지 확인 |
- | 사이의 문자 또는 숫자를 표현할 때 사용하는 기호 |
[0-9] | 0부터 9까지의 모든 숫자 허용 |
[ㄱ-힣] | "ㄱ"부터 힣까지의 모든 한글 허용 |
[가-힣] | "가"부터 힣까지의 모든 한글 허용 (즉, 자음만 있거나 모으만 있는 경우는 제외됨) |
[a-z] | 모든 영어 소문자 허용 |
[A-Z] | 모든 영어 대문자 허용 |
a{5} | "a"문자가 5개 존재한다. ( "aaaaa" ) |
a{2,5} | "a"문자가 2개 이상 5개 이하 존재한다. ( "aa", "aaa", "aaaa", "aaaaa" ) |
a{2,} | "a"문자가 2개 이상 존재한다. |
a{,5} | "a"문자가 5개 이하 존재한다. |
전방 탐색 조건 | 설명 |
* | 앞의 표현식이 0개 이상 존재 / 0번 이상 반복 / 있어도 되고, 었어도 된다. |
+ | 앞의 표현식이 1개 이상 존재 / 1번 이상 반복 |
? | 앞의 표현식이 0개 또는 1개 존재 |
. | 1칸의 문자 존재 (개행문자를 제외한 문자 하나) |
() | 그룹 및 캡쳐 |
(?:) | 찾지만 그룹에 포함 안됨 |
(?=) | =앞 문자를 기준으로 전방 탐색 |
(?<=) | =뒤 문자를 기준으로 후방 탐색 |
전방 탐색 이란?
문자열이 특정 패턴에 일치하는지 확인하는 것으로
(?=.*[a-zA-Z])와 비슷한 형식으로 작성하며
위의 전방 탐색을 해석하면 문자열에 소문자 또는 대문자 중에서 하나가 포함되어 있어야 한다는 의미이다.
전방 탐색은 해당 문자열에 전체적으로 적용되는 조건으로
문자열의 시작을 의미하는 ^앞에 있다고 해서 문자열 앞에만 적용되는 것이 아니다.
즉, ^와 상관없이 전체적인 문자열에 적용되는 조건이다.
--
@Valid 를 이용하여 유효성 검사 작성하기
--
MemberDto.java
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class MemberDto{
@NotBlank(message = "아이디를 입력해주세요")
@Size(min = 8, max = 20, message = "아이디는 8자 이상 20자 이하로 입력해주세요.")
@Pattern(regexp = "^[a-zA-Z0-9]{8,20}$", message = "아이디는 영문 대소문자, 숫자입력이 가능합니다.")
private String loginId;
@NotBlank(message = "비밀번호를 입력해주세요")
@Size(min = 8, max = 20, message = "비밀번호는 8자 이상 20자 이하로 입력해주세요.")
@Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*])[A-Za-z0-9!@#$%^&*]{8,20}$", message = "비밀번호는 영문 대소문자, 숫자, 특수기호(!, @, #, $, %, ^, &, *)가 포함되어야 합니다.")
private String loginPassword;
@NotBlank(message = "이메일을 입력해주세요")
@Email(message = "올바른 이메일 주소를 입력해주세요.")
private String email;
@NotBlank(message = "성함을 입력해주세요")
private String name;
@NotBlank(message = "전화번호를 입력해주세요")
@Pattern(regexp = "^(01[016789])-(\\d{3,4})-(\\d{4})$", message = "올바른 휴대폰 번호를 입력해주세요.")
private String tel;
@NotNull(message = "생년월일을 입력해주세요")
@Past(message = "과거 날짜만 입력할 수 있습니다.")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
@NotBlank(message = "성별을 입력해주세요")
@Size(min = 1, max = 1, message = "한 글자가 아닙니다.")
@Pattern(regexp = "^[남여]$", message = "남 또는 여를 입력해주세요")
private String gender;
private String roles;
}
- loginId
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니고
대소문자와 숫자로만 작성할 수 있는 문자열이며
문자열의 크기는 8이상 20이하의 크기여야 한다. - loginPassword
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니고
대소문자와 숫자, 특수기호는 꼭 하나씩은 포함되어 있어야 하며
대소문자, 숫자, 특정 특수기호로만 작성할 수 있는 문자열이고
문자열의 크기는 8이상 20이하의 크기여야 한다. - email
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니고
해당 문자열은 email 형식이어야 한다. (중간에 "@"가 포함된 이메일) - name
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니어야 한다. - tell
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니고
문자열은 "01"로 시작하며 그 다음 문자는 "0", "1", "6", "7", "8", "9" 중 하나만 올 수 있으며
그 다음 문자 "-" 뒤에는 3개의 숫자 또는 4개의 숫자이고
그 다음 문자 "-" 뒤에는 4개의 숫자로 이루어진 문자열이어야 한다. - birthDate
null값이 아니고
과거의 날짜만 입력할 수 있으며
"yyyy-MM-dd" 형식으로 된 문자열이어야 한다. - gender
null과 빈 문자열, 공백으로만 이루어진 문자열이 아니고
한 글자이어야 하며
"남" 또는 "여"인 문자열이어야 한다.
MemberController.java
@PostMapping("/join")
public void memberJoin(@Valid @RequestBody MemberDto request, BindingResult bindingResult){
// 회원가입 유효성 검사
if(bindingResult.hasErrors()){
throw new IllegalArgumentException("형식에 알맞게 입력해주세요");
}
memberService.memberJoin(request);
}
@Valid 어노테이션을 통해서
MemberDto(=request)에 있는 값을 MemberDto에 작성한 어노테이션들을 가지고 유효성을 검사하며
유효성 검증에서 오류가 발생하면 해당 오류에 대해 FieldError, ObjectError를 생성하여 bindingResult에 담는다.
bindingResult에 에러가 담겨져 있는지 확인을 하여
담겨져 있다면 유효성 검증에 실패한 것이고 담겨져 있지 않다면 유효성 검증에 통과한 것이다.
--
'Spring Boot' 카테고리의 다른 글
spring security에서 발생하는 예외 처리하기 (0) | 2024.05.27 |
---|---|
스케줄러(@Scheduled)를 이용하여 특정 로직을 자동으로 동작하게 하기 (0) | 2024.05.03 |
전역으로 예외 처리 통일 시키는 방법 (0) | 2024.04.24 |
결제 API 포트원 (구 아임포트)로 결제 시스템 구현하기 (0) | 2024.04.23 |
JWT를 이용하여 로그인 구현하기 (+ Refresh Token ) (0) | 2024.04.21 |