๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

[Spring] Validation ์ถ”์ƒํ™”

by Leica 2020. 3. 5.
๋ฐ˜์‘ํ˜•

[Spring] Validation ์ถ”์ƒํ™”

org.springframework.validation.Validator๋Š” spring์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด ๊ฒ€์ฆ์šฉ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

์ฃผ๋กœ spring mvc์—์„œ ์‚ฌ์šฉํ•˜์ง€๋งŒ web ๊ณ„์ธต ์ „์šฉ ๊ฐœ๋…์€ ์•„๋‹ˆ๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

Validator๋Š” Java EE ํ‘œ์ค€ ์ŠคํŽ™ ์ค‘ ํ•˜๋‚˜์ธ Bean Validation์„ ์ง€์›ํ•˜์—ฌ Bean Validation์ด ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ์• ๋…ธํ…Œ์ด์…˜๋“ค์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

 

1. Validator ์ธํ„ฐํŽ˜์ด์Šค

Validator ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด์žˆ๋‹ค.

 

1
2
3
4
5
6
boolean supports(Class<?> clazz) {
    // ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฒ€์ฆ ๋Œ€์ƒ ํƒ€์ž…์ธ์ง€ ํ™•์ธ
}
void validate(Object target, Errors errors) {
    // ์‹ค์งˆ์ ์ธ ๊ฒ€์ฆ ์ž‘์—…
}
cs

 

2. Validator ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

๊ฒ€์ฆ ๋Œ€์ƒ ํด๋ž˜์Šค Event๋ฅผ ๋งŒ๋“ ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Event {
    
    Integer id;
    
    String title;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
}
cs

 

Event ์ธ์Šคํ„ด์Šค๋Š” title ํ•„๋“œ๊ฐ€ null์ด๋ฉด ์•ˆ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

 

๋‹ค์Œ์œผ๋กœ Event์— ๋Œ€ํ•œ validation์„ ์ฒ˜๋ฆฌํ•  Validator๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
 
public class EventValidator implements Validator {
 
    @Override
    public boolean supports(Class<?> clazz) {
        return Event.class.equals(clazz);
    }
 
    @Override
    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title""notempty""Empty title is not allowed");
    }
}
cs

 

validate()๋Š” ValidationUtils๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

rejectIfEmptyOrWhitespace() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ์— Errors ๊ฐ์ฒด, ํ•„๋“œ๋ช…, ์—๋Ÿฌ์ฝ”๋“œ, ๋””ํดํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

์„ธ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ ์—๋Ÿฌ์ฝ”๋“œ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•  key๊ฐ€ ๋œ๋‹ค.

์ง€์ •ํ•œ ์—๋Ÿฌ์ฝ”๋“œ์— ํ•ด๋‹นํ•˜๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ชป์ฐพ์„ ๊ฒฝ์šฐ ๋””ํดํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

์ด์ œ ๊ตฌํ˜„ํ•œ Validator๋ฅผ ์ด์šฉํ•ด validation์„ ์‹คํ–‰ํ•ด๋ณด์ž.

 

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
32
33
34
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
 
import java.util.Arrays;
 
@Component
public class AppRunner implements ApplicationRunner {
 
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด title ์„ค์ • ์•ˆํ•จ
        Event event = new Event();
 
        // ๊ฒ€์ฆํ•  ๊ฐ์ฒด event๋ฅผ ์ „๋‹ฌํ•˜์—ฌ Errors ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        Errors errors = new BeanPropertyBindingResult(event, "event");
 
        // Validation ์‹คํ–‰
        EventValidator eventValidator = new EventValidator();
        eventValidator.validate(event, errors);
 
        // ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š”์ง€
        System.out.println("hasErrors(): " + errors.hasErrors());
 
        // ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉฐ ์—๋Ÿฌ์ฝ”๋“œ์™€ default message ์ถœ๋ ฅ
        errors.getAllErrors().forEach( e -> {
            System.out.println("=== Error Code ===");
            Arrays.stream(e.getCodes()).forEach(System.out::println);
            System.out.println(e.getDefaultMessage());
        });
    }
}
cs

 

๊ฒ€์ฆ ๋Œ€์ƒ Event ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•˜๋ฏ€๋กœ title ํ•„๋“œ๋Š” ์„ธํŒ…ํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

๊ฒ€์ฆํ•  ๊ฐ์ฒด event๋ฅผ ์ „๋‹ฌํ•˜์—ฌ Errors ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

Errors ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ• ๋•Œ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„์ฒด BeanPropertyBindingResult๋Š” spring mvc๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋ฏ€๋กœ ์‹ค์ œ๋กœ ์ด ๊ตฌํ˜„์ฒด๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ๋Š” ๊ฑฐ์˜ ์—†๋‹ค.

 

๊ตฌํ˜„ํ•œ Validator ํด๋ž˜์Šค EventValidator์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  validate() ๋ฉ”์†Œ๋“œ๋กœ ๊ฒ€์ฆ์„ ์‹คํ–‰ํ•œ๋‹ค.

๊ฒ€์ฆํ•  ๊ฐ์ฒด event์™€ ์œ„์—์„œ ์ƒ์„ฑํ•œ errors๋ฅผ ๋„˜๊ฒจ์„œ ํ˜ธ์ถœํ•œ๋‹ค.

validate() ์‹คํ–‰ ์ดํ›„ ์ด errors๋ฅผ ์ด์šฉํ•ด ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

 

์˜ˆ์ œ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉ๋œ hasErrors()๋Š” ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ณ  getAllErrors()๋Š” ๋ฐœ์ƒํ•œ ๋ชจ๋“  ์—๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

forEach๋ฌธ์œผ๋กœ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ ์—๋Ÿฌ์ฝ”๋“œ๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•˜์˜€๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ getDefaultMessage()๋กœ ๋””ํดํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

 

์‹คํ–‰ ๊ฒฐ๊ณผ

Validator๋ฅผ ๊ตฌํ˜„ํ• ๋•Œ ์—๋Ÿฌ ์ฝ”๋“œ๋ฅผ 'notempty'๋งŒ ์„ค์ •ํ–ˆ์ง€๋งŒ Validator์—์„œ ์ž๋™์œผ๋กœ notempty.event.title, notempty.title ๋“ฑ์˜ ๊ตฌ์ฒด์ ์ธ ์—๋Ÿฌ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์—ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์ž๋™์œผ๋กœ ์—๋Ÿฌ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋ฏ€๋กœ Validator ๊ตฌํ˜„ ์‹œ ์—๋Ÿฌ์ฝ”๋“œ๋Š” prefix๋งŒ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด ์—๋Ÿฌ์ฝ”๋“œ๋Š” MessageSource์—์„œ ์‹ค์ œ ์—๋Ÿฌ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์–ด์˜ค๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

validate()๋ฅผ ๊ตฌํ˜„ํ• ๋•Œ ValidationUtils๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ValidationUtils๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ์ด๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
 
public class EventValidator implements Validator {
 
    @Override
    public boolean supports(Class<?> clazz) {
        return Event.class.equals(clazz);
    }
 
    @Override
    public void validate(Object target, Errors errors) {
        Event event = (Event) target;
        if (event.getTitle() == null) {
            errors.rejectValue("title""notempty""Empty title is not allowed");
        }
    }
}
cs

 

์ด๋ ‡๊ฒŒ ValidationUtils์˜ rejectIfEmptyOrWhitespace() ๋Œ€์‹  Event์˜ reject()๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.

 

์‹คํ–‰ ๊ฒฐ๊ณผ

์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๋‹ค.

 

3. LocalValidatorFactoryBean

Spring ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Validator๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ๋ณด๋‹ค๋Š” spring์ด ์ œ๊ณตํ•ด์ฃผ๋Š” LocalValidatorFactoryBean์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด ํด๋ž˜์Šค๋Š” Java EE์˜ Bean Validation ์• ๋…ธํ…Œ์ด์…˜๋“ค์„ ์ง€์›ํ•œ๋‹ค. ํŠนํžˆ Spring Boot๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ๋นˆ์„ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•ด์ค€๋‹ค.

 

์œ„์—์„œ ์ž‘์„ฑํ•œ Event ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•œ Validator๊ฐ€ ์•„๋‹Œ LocalValidatorFactoryBean์„ ์‚ฌ์šฉํ•ด์„œ ๊ฒ€์ฆํ•ด๋ณด์ž.

 

๋จผ์ € ์ด ๊ฐ์ฒด๋กœ ๊ฒ€์ฆ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Bean Validation ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ค˜์•ผํ•œ๋‹ค.

Validation ๋Œ€์ƒ์ธ Event ํด๋ž˜์Šค์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ธ๋‹ค.

 

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
32
33
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
 
public class Event {
 
    Integer id;
 
    @NotEmpty
    String title;
 
    @Min(0)
    Integer limit;
 
    @Email
    String email;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
}
cs

 

@NotEmpty๋Š” ๋นˆ ๊ฐ’ ์—ฌ๋ถ€, @Min์€ ์ตœ์†Œ๊ฐ’, @Email์€ ์ด๋ฉ”์ผ ์ฃผ์†Œ ํ˜•์‹์„ validateํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

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
32
33
34
35
36
37
38
39
40
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
 
import java.util.Arrays;
 
@Component
public class AppRunner implements ApplicationRunner {
 
 
    @Autowired
    LocalValidatorFactoryBean validatorFactoryBean;
 
    @Override
    public void run(ApplicationArguments args) throws Exception {
        Event event = new Event();
        event.setLimit(-1);
        event.setEmail("1234");
 
        // ๊ฒ€์ฆํ•  ๊ฐ์ฒด event๋ฅผ ์ „๋‹ฌํ•˜์—ฌ Errors ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        Errors errors = new BeanPropertyBindingResult(event, "event");
 
        // Validation ์‹คํ–‰
        validatorFactoryBean.validate(event, errors);
 
        // ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š”์ง€
        System.out.println("hasErrors(): " + errors.hasErrors());
 
        // ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉฐ ์—๋Ÿฌ์ฝ”๋“œ์™€ default message ์ถœ๋ ฅ
        errors.getAllErrors().forEach( e -> {
            System.out.println("=== Error Code ===");
            Arrays.stream(e.getCodes()).forEach(System.out::println);
            System.out.println(e.getDefaultMessage());
        });
    }
}
cs

 

Spring boot์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” LocalValidatorFactoryBean์„ ์ฃผ์ž…๋ฐ›๋Š”๋‹ค.

Event ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—๋Ÿฌ๋ฅผ ์˜๋„์ ์œผ๋กœ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๊ฐ’์„ ์„ธํŒ…ํ•˜์˜€๋‹ค.

์ง์ ‘ ๊ตฌํ˜„ํ•œ Validator๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  LocalValidatorFactoryBean ๊ฐ์ฒด๋กœ validate()์„ ์‹คํ–‰ํ•œ๋‹ค.

 

์‹คํ–‰ ๊ฒฐ๊ณผ

title, limit, email ์„ธ ํ•„๋“œ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ  ๊ฐ ์—๋Ÿฌ๋งˆ๋‹ค LocalValidatorFactoryBean์ด ์ œ๊ณตํ•ด์ค€ ์—๋Ÿฌ ์ฝ”๋“œ์™€ ๋””ํดํŠธ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค.

์ด๋ ‡๊ฒŒ LocalValidatorFactoryBean์€ ์—๋Ÿฌ ์ฝ”๋“œ์™€ ๋””ํดํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ณตํ•ด์ค€๋‹ค.

 

์ด์™€ ๊ฐ™์ด Bean Validation ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค์€ Validator๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ ๋„ LocalValidatorFactoryBean์„ ์‚ฌ์šฉํ•ด์„œ validation ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์™ธ์— ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์œผ๋กœ validation ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ์— Validator๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

 

References

์ธํ”„๋Ÿฐ - ๋ฐฑ๊ธฐ์„ ๋‹˜์˜ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ ํ•ต์‹ฌ ๊ธฐ์ˆ 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€