์คํ๋ง ๋ฒจ๋ฆฌ๋ฐ์ด์
์์นด๋ฅดํ ๋ฒจ๋ฆฌ๋ฐ์ด์
์คํ๋ง ๋ถํธ์์ ์ ๊ณตํ๋ ๋ฒจ๋ฆฌ๋ฐ์ด์ ์ spring-boot-starter-validation ๋ชจ๋์ ํฌํจ๋์ด ์์ผ๋ฉฐ Jakarta Bean Validation์ ๋ฐ๋ฅด๋ Hibhernate Validator๋ฅผ ์์กดํ๊ณ ์๋ค. ์คํ๋ง ๋ถํธ์ ์ํ ์๋ ๊ตฌ์ฑ์ ValidationAutoConfiguration์ผ๋ก ์ํํ๋ฉฐ LocalValidatorFactoryBean๋ฅผ ๊ธฐ๋ณธ Validator ๋น์ผ๋ก์จ ๋ฑ๋กํจ์ ํ์ธํ ์ ์๋ค.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
LocalValidatorFactoryBean
์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ์ ์กด์ฌํ๋ ๋ฉ์์ง ์์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ณด๊ฐ์ ์ฒ๋ฆฌํ๋ MessageSourceMessageInterpolator๊ฐ ์ฌ์ฉ๋๋๋ก ๊ตฌํ๋์ด์๋ค. MessageInterpolatorFactory์ ๋ด๋ถ ๊ตฌํ์ ์ดํด๋ณด๋ฉด ๋ฉ์์ง ์์ค๊ฐ ์๋ค๋ฉด ํ์ด๋ฒ๋ค์ดํธ ๋ฒจ๋ฆฌ๋ฐ์ดํฐ์ ResourceBundleMessageInterpolator๊ฐ ์ฌ์ฉ๋๋ ์คํ๋ง ๋ถํธ์ ์ํด ๋ฉ์์ง ์์ค ์์ฒด๋ ์๋ ๊ตฌ์ฑ๋๋ฏ๋ก ๊ฒฐ๊ตญ MessageSourceMessageInterpolator๊ฐ ์ฌ์ฉ๋๋ค๊ณ ์ธ์งํ๋ฉด ๋๋ค.
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext,
ObjectProvider<ValidationConfigurationCustomizer> customizers) {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setConfigurationInitializer((configuration) -> customizers.orderedStream()
.forEach((customizer) -> customizer.customize(configuration)));
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
์ต์ข ์ ์ผ๋ก๋ MessageSourceMessageInterpolator๊ฐ LocaleContextMessageInterpolator๋ก ๋ํ๋๋ฉฐ LocaleContextHolder.getLocale()๋ฅผ ์ฌ์ฉํ์ฌ ์คํ๋ง ์น ์์ฒญ์ ์ํ ์ค๋ ๋์ ๋ํด ๋ก์ผ์ผ ๊ธฐ๋ฐ์ผ๋ก ๋ฉ์์ง ๋ณด๊ฐ์ด ์ฒ๋ฆฌ๋๋๋ก ์ง์ํ๋ค.
๊ธฐ๋ณธ ๋ฒจ๋ฆฌ๋ฐ์ด์ ๋ฉ์์ง
ํ์ด๋ฒ๋ค์ดํธ ๋ฒจ๋ฆฌ๋ฐ์ดํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด์๋ ๊ธฐ๋ณธ์ผ๋ก ์ ์๋ ValidationMessages๋ฅผ ํฌํจํ๊ณ ์๋ค. ๋ฐ๋ผ์, @NotEmpty ๋๋ @Length, @Email ๊ณผ ๊ฐ์ ์์นด๋ฅดํ ๋ฒจ๋ฆฌ๋ฐ์ด์ ์ ์ ์๋์ด์๋ Constraints์ ๋ํด์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉ์์ง ๋ณด๊ฐ์ผ๋ก ์ฒ๋ฆฌ๋ ์ ์๋ค.
์ ํจ์ฑ ๊ฒ์ฌ
Validation ์ด๋๊น์ง ํด๋ดค๋?์์ ์ ์ ์๋ฏ์ด ์์นด๋ฅดํ ๋ฒจ๋ฆฌ๋ฐ์ด์ ์ ํฉํ ๋ฆฌ ํจ์๋ฅผ ํตํด ๊ฐ๋จํ๊ฒ ๋ฒจ๋ฆฌ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ ์๋ฐ ๋น ํด๋์ค์ ์ ์ฅ๋ ์ ๋ณด๊ฐ ์ฌ๋ฐ๋ฅธ์ง ํ๋ ๊ฒ์ฆ์ ์ฝ๊ฒ ์ํํ ์ ์๋ค. ๊ทธ๋ฌ๋, ์คํ๋ง ๋ถํธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์๋ ๊ตฌ์ฑ๋๋ LocalValidatorFactoryBean๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
@Service
public class LoginService {
public boolean validate(Account.Login login) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Account.Login>> constraintViolations = validator.validate(login);
return constraintViolations.isEmpty();
}
}
์ฌ์ฉ์ ์ ์ ๋ฉ์์ง ์ ์ฝ์ฌํญ
์คํ๋ง ๋ฉ์์ง ์์ค์ ์ฌ์ฉ์ ์ ์ ๋ฉ์์ง๋ฅผ ์ง์ ํ๋๋ผ๋ ๋ฉ์์ง ํจํด์์ {value}์ ๊ฐ์ ํ๋ผ๋ฏธํฐ ํํ์ด ๋ถ๊ฐ๋ฅํ๋ค. ์๋ฅผ ๋ค์ด, ๋ค์๊ณผ ๊ฐ์ด ์ด๋ค ๊ฐ์ ๋ํ ๊ธธ์ด๋ฅผ ์ ํํ๋ค๊ณ ๊ฐ์ ํ์ฌ @Min ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
<messages>
<entry key="javax.validation.constraints.Min.message">
<ko_KR><![CDATA[(์ฌ์ฉ์ ์ ์) {value} ๋ณด๋ค ๊ฐ๊ฑฐ๋ ์ปค์ผํฉ๋๋ค]]></ko_KR>
<en_US><![CDATA[(Custom) must be greater than or equal to {value}]]></en_US>
</entry>
</messages>
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ValidationException: HV000149: An exception occurred during message interpolation
...
Caused by: java.lang.IllegalArgumentException: can't parse argument number: value
at java.base/java.text.MessageFormat.makeFormat(MessageFormat.java:1451) ~[na:na]
at java.base/java.text.MessageFormat.applyPattern(MessageFormat.java:491) ~[na:na]
at java.base/java.text.MessageFormat.<init>(MessageFormat.java:390) ~[na:na]
...
Caused by: java.lang.NumberFormatException: For input string: "value"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:na]
at java.base/java.lang.Integer.parseInt(Integer.java:652) ~[na:na]
at java.base/java.lang.Integer.parseInt(Integer.java:770) ~[na:na]
at java.base/java.text.MessageFormat.makeFormat(MessageFormat.java:1449) ~[na:na]
์ด๋ฌํ ํ๋ผ๋ฏธํฐ ํํ์ Hibernate Validator์์ ์ง์ํ๋ ํํ์์ด๋ฏ๋ก MessageFormat์ผ๋ก ์ง์ํ๋ ํํ์๊ณผ๋ ๋ค๋ฅด๋ค. MessageFormat๋ {0}, {1} ์ด๋ ๊ฒ ์ซ์ ๊ธฐ๋ฐ์ ํํ์์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ํํ์ ์ ์ฝ์ด ๋ฐ์ํ๋ค. ์์ฌ์ด ๋ถ๋ถ์ด์ง๋ง ์ฌ์ฉ์ ์ ์ ๋ฉ์์ง์์ ํ๋ผ๋ฏธํฐ ํํ์์ ์ฌ์ฉํด์ผํ๋ค๋ฉด ValidationMessages ๋ฆฌ์์ค ๋ฒ๋ค์ ํด๋์คํจ์ค์ ์ฌ์ ์ํด์ ์ฌ์ฉํ ์ ๋ฐ์ ์์ ๊ฒ ๊ฐ๋ค.