[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
์ธํ๋ฐ - ๋ฐฑ๊ธฐ์ ๋์ ์คํ๋ง ํ๋ ์์ํฌ ํต์ฌ ๊ธฐ์
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] SpEL - Spring Expression Language (0) | 2020.03.07 |
---|---|
[Spring] ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ - PropertyEditor, Converter ๊ทธ๋ฆฌ๊ณ Formatter (1) | 2020.03.06 |
[Spring] Resource ์ถ์ํ (0) | 2020.03.05 |
[Spring] ResourceLoader๋ก ํ ์คํธ ํ์ผ ์ถ๋ ฅํ๊ธฐ (Java 11) (0) | 2020.03.05 |
[Spring] ApplicationEventPublisher๋ฅผ ์ด์ฉํ ์ด๋ฒคํธ ํ๋ก๊ทธ๋๋ฐ (0) | 2020.03.05 |
๋๊ธ