유효성 검사란?
사용자가 입력한 데이터가 허용하는 형태인지 검사하는 과정
예) 이름을 입력하는 공간에 숫자를 입력하거나 등 원하는 데이터가 맞는지
spring-boot-starter-validation
jakarta Bean Vaolidation
- 유효성 검증을 위한 기술 명세
- 어떤 항목이 어떤 규칙을 지켜야 하는지 표시하는 기준
Hibernate Vailidation
- jakarta beanb validation을 토대로 실제로 검증해주는 프레임 워크
둘의 관계는 JPA와 Hibernate ORM과 유사하다. ⇒ Spring data JPA jpa repository
Jakarta Bean Validation specification
validation 참고 사이트
💻 실습
📌 목표 : usercontrolloer 가 userdto의 요구사항을 유효했는지 확인하는게 목표
- spring project 생성
- dto → userdto 생성
@Data
public class UserDto {
private Long id;
@NotBlank //비어있지 않다.
private String username;
private String email;
private String phone;
}
- controller→ usercontroller 생성
@Slf4j
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<Map<String, String>> addUser(
//UserDto가 우리가 정의한 요구사항
//지키고 있는지 유효성 검사
@RequestBody UserDto dto
){
log.info(dto.toString());
Map<String, String> responseBody = new HashMap<>();
responseBody.put("message", "success!");
return ResponseEntity.ok(responseBody);
}
}
실행
- postman 실행 후 검사
✅ 유효성 검사
@NotBlank : 빈칸이면 안된다.
@Email : 이메일 형식으로 입력해야한다.
@NotNull : 널 값이면 안된다.
추가
- userdto
@Data
public class UserDto {
//요구사항들
private Long id;
@NotBlank //비어있지 않다.
private String username;
@Email //형식이 이메일이어야한다.
private String email;
@NotNull
private String phone;
}
- controller
@Slf4j
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<Map<String, String>> addUser(
//UserDto가 우리가 정의한 요구사항
//지키고 있는지 유효성 검사
@**Valid** @RequestBody UserDto dto
){
log.info(dto.toString());
Map<String, String> responseBody = new HashMap<>();
responseBody.put("message", "success!");
return ResponseEntity.ok(responseBody);
}
}
- 추가 한 뒤에 빌드하면 userdto에서 있던 요구사항들이 빠지면 400 badrequest가 발생한다.
- @Min() 사용 : () 괄호 안에 숫자가 최소 몇글자인지
@Min(14) //나이최소 14
private Integer age;
- @Future : 현재 시점보다 미래시간입력해야한다.
@Future
private LocalDate validUntil;
- @NotNull, @NotEmpty, @NotBlank
@NotNull //notNullString이 널이 아닌지만 검증
private String notNullString;
@NotEmpty //notEmptyString의 길이가 0이 아닌지만 검증
private String notEmptyString;
@NotBlank //notBlankString이 공백 문자로만 이루어지지 않았는지 검증
private String notBlankString;
}
검증 실패시 응답 @ExceptionHandler 사용
예외 처리를 수동으로 해주어 검증실패시 응답하는 것이다.
유효성 검사 실패는 사용자 오류임으로 응답코드를 400으로 설정해준다.
@ExceptionHandler(MethodArgumentNotValidException.class) // 검증 실패시 응답
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String,String> handelValidationException(
MethodArgumentNotValidException exception
){
Map<String, String> errors = new HashMap<>();
for (FieldError error :
exception.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return errors;
}
- userdto
@Data
public class UserDto {
//요구사항들
private Long id;
@NotBlank //비어있지 않다.
@Size(
min = 8,
message = "최소 8글자이어야 합니다.")
private String username;
@Email //형식이 이메일이어야한다.
private String email;
@NotNull
private String phone;
@Min(14)
@Min(
value = 14,
message = "14세 미만은 부모님의 동의가 필요합니다.")
//나이최소 14
private Integer age;
@Future(message = "미래의 시간까지 유효해야합니다.")
private LocalDate validUntil;
@NotNull //notNullString이 널이 아닌지만 검증
private String notNullString;
@NotEmpty //notEmptyString의 길이가 0이 아닌지만 검증
private String notEmptyString;
@NotBlank //notBlankString이 공백 문자로만 이루어지지 않았는지 검증
private String notBlankString;
}
- 결과
사용자 지정 유효성 검사
이미 제공되는 어노테이션만으로 충분하지만, 상황에 따라 그것으로 부족한 경우도 존재한다.
이런 경우에는 직접 사용자가 어노테이션을 만들고, 그 어노테이션이 적용된 필드를 검사하는 방법을 사용하여 사용자가 직접 유효성 검증 방법을 만들 수도 있다.
먼저 어노테이션을 생성한다.
조건
- email 형식이어야한다.
- 이메일이 네이버와 지메일이여야한다.
- constraints 패키지 생성
- annotations 패키지 생성 → EmailWhiteList 어노테이션 생성
@Target(ElementType.FIELD) //어노테이션을 어디에 적용할 것인지 (선택)
@Retention(RetentionPolicy.RUNTIME)
public @interface EmailWhiteList {
}
- EmailWhiteListValidator = 데이터 유효성 검사기 클래스
public class EmailWhiteListValidator
//사용자 지정 유효성 검사를 위해 구현해야 하는 인터페이스
implements ConstraintValidator<EmailWhiteList, String> {
private final Set<String> whiteList;
public EmailWhiteListValidator(){
this.whiteList = new HashSet<>();
this.whiteList.add("gmail.com");
this.whiteList.add("naver.com");
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context){
//유효한 값일 때 true 반환
//유효하지 않은 값을 때 false 반환
String[] split = value.split("@");
String domain = split[split.length -1];
//set whitelist에 domain이 추가되어 있는지
return whiteList.contains(domain);
}
}
- userdto
@Email //형식이 이메일이어야한다.
// 이메일이 지정된 도메인 (gmail.com 등) 이도록
// 검증하는 어노테이션을 만들어봅시다.
@EmailWhiteList
private String email;
결과
전화번호의 조건 넣기 (010-시작 & (010) 시작)
- Phone010 어노테이션
//@Phone010가 붙은 필드는
//유효성 검사시
// (010) 또는 010-으로 시작해야한다.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = Phone010Validator.class)
public @interface Phone010 {
//Annotaion Element
String message() default "010으로 시작하지 않음";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- Phone010Validator 클래스
public class Phone010Validator
implements ConstraintValidator<Phone010, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//010-
boolean withDash = value.startsWith("010-");
//(010)
boolean withPar = value.startsWith("(010)");
return withDash || withPar;
}
}
- userdto
@NotNull //null이 아니다.
@Phone010 //010으로 시작하는 번호 형식인지
private String phone;
- 결과
blacklist
- userdto추가
// UserDto 어노테이션 추가
@NotBlank @Size(min = 8, message = "최소 8글자 이상이여야 합니다.")
@Blacklist(blacklist = {"blacklist"})
private String username;
- blacklist 인터페이스 생성
// Blacklist(@interface)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = BlacklistValidator.class)
public @interface Blacklist {
String message() default "username in blacklist";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] blacklist() default {};
}
- blacklistValidator 생성
// BlacklistValidator
public class BlacklistValidator implements ConstraintValidator<Blacklist, String> {
private Set<String> blacklist;
@Override
public void initialize(Blacklist constraintAnnotation) {
blacklist = new HashSet<>();
for (String target: constraintAnnotation.blacklist()) {
blacklist.add(target);
}
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// this.blacklist 안에 value가 있으면 실패
return !this.blacklist.contains(value);
}
}
- 결과
'Spring' 카테고리의 다른 글
[Spring] Logging (0) | 2023.07.09 |
---|---|
[Spring] 테스트 클래스란? (0) | 2023.07.09 |
POSTMAN 사용하기 (0) | 2023.07.09 |
MyBatis (0) | 2023.07.09 |
[Spring] CRUD란? (0) | 2023.07.09 |