Young

hibernate validator 본문

Web/Spring Framework

hibernate validator

yyjjang9 2020. 11. 12. 10:10
728x90
반응형

유효성 검사는 매우 중요한데, 이를 위해 hibernate validator 를 사용하면 기본적인 유효성 검사를 편하고, 깔끔하게 할 수 있다.

 

이 hibernate validator 를 만들게 된 이유를 보면, 아래와 같이 객체를 전달할 때마다 유효성 검증을 할텐데, 이 때 코드 중복이 너무 많다는 단점을 보완하기 위해서 이것을 만든 것이다.

 

 

그래서 아래와 같이 dto 에 각 멤버변수에 대한 제약조건을 모두 명시해 놓으면, 각 층으로 객체를 넘길때마다 유효성 검증하는

코드를 쉽게 작성할 수 있게끔 한다는 목적을 가지고 만들었다.

 

 

(docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-gettingstarted)

 

 

 

 

 

1. 빠르게 적용해보기

1) 의존성 추가

compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.1.0.Final'

 

2) 어노테이션으로 제약 조건 추가 및 유효성 검사 시행

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
public class Member {
    private int memberNum;
    @Size(min = 2, max = 10)
    @NotBlank
    private String name;
    @NotBlank
    private String tel;
    @Range(min = 0, max = 120)
    private int age;
    @NotBlank
    @Size(min = 3, max = 20)
    private String id;
    @Null
    private Date regDt;
    @NotBlank        // @Size(min = 1) 설정을 한다고 해서, activation 변수가 null 이 아님을 보장할 수 없음!, 주의.
    @Size(min = 1, max = 1)
    private String activation;
    @NotBlank
    @Size(min = 5, max = 45)
    private String address;
    @NotBlank
    private Date birth;
    @NotBlank
    @Size(min = 1, max = 1)
    private String sex;
}
 
cs

 

@Valid 어노테이션으로 Member dto 유효성 검사를 시도함

1
2
3
4
    @PostMapping("/insert")
    public void insert(@Valid @RequestBody Member member) {
        userService.insert(member);
    }
cs

 

 

 

2. 어노테이션 종류

애노테이션 

주요 속성 

설명 

 지원 타입

@AssertTrue

@AssertFalse

 

값이 true인지 또는 false인지 검사한다. null은 유효하다고 판단한다. 

boolean
Boolean

@DecimalMax

@DecimalMin

String value

- 최댓값 또는 최솟값

 

boolean inclusive

- 지정값 포함 여부

- 기본 값 true

지정한 값보다 작거나 같은지 또는 크거나 같은지 검사한다.

inclusive가 false면 value로 지정한 값은 포함하지 않는다.

null은 유효하다고 판단한다.

BigDecimal

BigInteger

CharSequence

byte, short, int, long 및 각 래퍼 타입

@Max

@Min

long value

지정한 값보다 작거나 같은지 또는 크거나 같은지 검사한다.

null은 유효하다고 판단한다.

BigDecimal
BigInteger
byte, short, int, long 및 관련 래퍼 타입

@Digits

int integer

- 허용 가능한 정수 자릿수

 

int fraction

- 허용 가능한 소수점 이하 자릿수

자릿수가 지정한 크기를 넘지 않는지 검사한다.

null은 유효하다고 판단한다.

BigDecimal

BigInteger

CharSequence

byte, short, int, long 및 관련 래퍼 타입

@Size

int min

- 최소 크기

- 기본 값 0

 

int max

- 최대 크기

- 기본 값 

길이나 크기가 지정한 값 범위에 있는지 검사한다.

null은 유효하다고 판단한다.

CharSequence

Collection

Map

배열

@Null

@NotNull

 

값이 null인지 또는 null이 아닌지 검사한다. 

 

@Pattern

String regexp

- 정규표현식 

값이 정규표현식에 일치하는지 검사한다. 

null은 유효하다고 판단한다.

CharSequence

@NotEmpty (2)

 

문자열나 배열의 경우 null이 아니고 길이가 0이 아닌지 검사한다. 콜렉션의 경우 null이 아니고 크기가 0이 아닌지 검사한다.

CharSequence

Collection

Map

배열

@NotBlank (2)

 

null이 아니고 최소한 한 개 이상의 공백아닌 문자를 포함하는지 검사한다.

CharSequence

@Positive (2)

@PositiveOrZero (2)

 

양수인지 검사한다.

OrZero가 붙은 것은 0 또는 양수인지 검사한다.

null은 유효하다고 판단한다.

BigDecimal
BigInteger
byte, short, int, long 및 관련 래퍼 타입

@Negative (2)

@NegativeOrZero (2)

 

음수인지 검사한다.
OrZero가 붙은 것은 0 또는 음수인지 검사한다. 

null은 유효하다고 판단한다.

BigDecimal
BigInteger
byte, short, int, long 및 관련 래퍼 타입

@Email (2)

 

이메일 주소가 유효한지 검사한다. 
null은 유효하다고 판단한다.
CharSequence 

@Future (2)

@FutureOrPresent (2)

 

해당 시간이 미래 시간인지 검사한다.

OrPresent가 붙은 것은 현재 또는 미래 시간인지 검사한다.

null은 유효하다고 판단한다.

시간 관련 타입

@Past (2)

@PastOrPresent (2)

 

해당 시간이 과거 시간인지 검사한다.

OrPresent가 붙은 것은 현재 또는 과거 시간인지 검사한다.
null은 유효하다고 판단한다.

시간 관련 타입 

* 애노테이션이 속한 패키지: javax.validation.constraints

* 시간 관련 타입: Date, Calendar, Instant, LocalDate, LocalDateTime, MonthDay, OffsetDateTime, OffsetTime, Year, YearMonth, ZonedDateTime 등

 

 

 

 

3. Validator 객체

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CarTest {
 
    private static Validator validator;
 
    @BeforeClass
    public static void setUpValidator() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }
 
    @Test
    public void manufacturerIsNull() {
        Car car = new Car( null"DD-AB-123"4 );
 
        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );
 
        assertEquals( 1, constraintViolations.size() );
        assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
    }
}
cs

 

Validator 객체를 사용하여, Car 클래스에 기술한 제약 조건을 검사할 수 있다.

보통 많은 코드를 보면, 컨트롤러를 통해서 맵핑될 때만 @Valid 어노테이션을 사용해서 유효성 검사를 하는데, 이 때만 사용하기 위해서 만든 라이브러리가 아니다.

객체가 함수 파라미터로 넘어가면서 내부 값이 변경되는데 이 때도 이 Validator 객체를 가져와 간편하게 유효성 검사를 할 수 있다.

 

 

 

 

4. bean 제약 종류 

  • field constraints

  • property constraints

  • container element constraints

  • class constraints

(docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#chapter-bean-constraints)

 

 

 

1) field-level constraints

필드 레벨 제약을 사용하면, getter 메소드가 있어도, 멤버변수 값에 직접 접근하여 값 유효성 검사를 진행한다.

private, public 을 가리지 않고, 검사한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.hibernate.validator.referenceguide.chapter02.fieldlevel;
 
public class Car {
 
    @NotNull
    private String manufacturer;
 
    @AssertTrue
    private boolean isRegistered;
 
    public Car(String manufacturer, boolean isRegistered) {
        this.manufacturer = manufacturer;
        this.isRegistered = isRegistered;
    }
 
    //getters and setters...
}
cs

 

 

 

2) property-level constraints

프로퍼티 레벨 제약을 사용하면, getter 메소드를 통해서 값 유효성 검사를 진행한다.

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
31
package org.hibernate.validator.referenceguide.chapter02.propertylevel;
 
public class Car {
 
    private String manufacturer;
 
    private boolean isRegistered;
 
    public Car(String manufacturer, boolean isRegistered) {
        this.manufacturer = manufacturer;
        this.isRegistered = isRegistered;
    }
 
    @NotNull
    public String getManufacturer() {
        return manufacturer;
    }
 
    public void setManufacturer(String manufacturer) {
        this.manufacturer = manufacturer;
    }
 
    @AssertTrue
    public boolean isRegistered() {
        return isRegistered;
    }
 
    public void setRegistered(boolean isRegistered) {
        this.isRegistered = isRegistered;
    }
}
cs

 

 

3) container element constraints

parameterized type 의 type argument 에 직접 적용시킬 수 있는데, 이를 container element constraints 라고 한다.

아래와 같은 곳에 적용시킬 수 있다.

  • java.util.Iterable 구현체 (List, Set)

  • java.util.Map 의 key, value 모두 지원가능

  • java.util.Optional, java.util.OptionalInt, java.util.OptionalDouble, java.util.OptionalLong

1
2
3
4
5
6
Set<@ValidPart String> parts = new HashSet<>();
List<@ValidPart String> parts = new ArrayList<>();
Map<@NotNull FuelConsumption, @MaxAllowedFuelConsumption Integer> fuelConsumption = new HashMap<>();
Optional<@MinTowingCapacity(1000) Integer> towingCapacity = Optional.empty();
GearBox<@MinTorque(100) Gear> gearBox;        // Custom container type 에도 적용가능
 
cs

 

 

 

4) class-level constraints

클래스 레벨에서 아래와 같이 연관된 멤버변수들 끼리 제약을 설정할 수도 있다.

클래스 내 멤버변수들 사이에 관계가 있는 경우 사용하기에 좋다.

1
2
3
4
5
6
7
8
9
@ValidPassengerCount
public class Car {
 
    private int seatCount;
 
    private List<Person> passengers;
 
    //...
}
cs

 

 

5. constraints inheritance

super 클래스 또는 인터페이스에 적용된 제약관련 어노테이션은 이를 상속받거나 구현한 클래스로 모두 상속된다.

 

 

6. Object graphs

custom 클래스 A 내의 멤버변수 중에 또다른 custom 클래스 B 의 인스턴스를 담는 변수가 있고, 이 인스턴스의 멤버변수에도 제약 어노테이션이 적용되어 있다고 하자. 

클래스 A 를 유효성 검사를 하면서, 멤버변수 중 클래스 B 의 인스턴스 내의 멤버변수까지 한 번에 검사가 가능하다.

아래와 같이 @Valid 어노테이션을 추가해주면 된다.

recursive 하게 @Valid 어노테이션을 달고 있는 객체 내에 제약 어노테이션이 있는지 검사하고, 있다면 제약조건 위배를 검사하는 작업을 반복한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Car {
 
    @NotNull
    @Valid
    private Person driver;
 
    //...
}
 
 
public class Person {
 
    @NotNull
    private String name;
 
    //...
}
cs

 

 

 

 

 

728x90
반응형

'Web > Spring Framework' 카테고리의 다른 글

spring async  (0) 2020.11.02
스프링의 기초  (0) 2020.10.24
스프링 프레임워크 주요 디자인 패턴  (0) 2020.10.24