ããã¯ããªã«ãããããŠæžãããã®ïŒ
Spring BootïŒSpring FrameworkïŒã䜿ã£ãŠãBean Validationã®ã¡ãã»ãŒãžãå€æŽãããããã®ãã©ãããã®ããããèŠããŠ
ããªãã£ãã®ã§ã確èªããŠã¿ãããšã«ã
çµå±ãBean Validationã®åŸ©ç¿çãªæãã«ãªããŸãããã©ã
ãã£ãããªã®ã§ãèªåã§Validatorãäœãã察å¿ããã¡ãã»ãŒãžãããããã£ãã¡ã€ã«ã«å®çŸ©ããŠçµã¿èŸŒãããšããã£ãŠã¿ãããš
æããŸãã
ããšããã©ã¹ã§æ¢åã¡ãã»ãŒãžã®äžæžããã
Bean Validationã§èªäœã®Validatorãäœæãã
ããã«ã€ããŠã¯ãHibernate ValidatorãèŠãã®ãããã§ãããã
ããªããŒã·ã§ã³ã§äœ¿ãã¢ãããŒã·ã§ã³ãäœæããŠã
察å¿ããValidatorãäœæããŸãã
ãšã©ãŒã¡ãã»ãŒãžã«é¢ããŠã¯ãValidationMessages.properties
ãšãããã¡ã€ã«ã«çµã¿èŸŒãããšã«ãªã£ãŠããŸãã
ã¡ãã»ãŒãžã解決ããã«ãŒã«ã¯ããã¡ãã«æžãããŠããŸãã
ããã©ã«ãã§ã¯ValidationMessages.properties
ïŒããã¯Bean Validationã®å©çšè
ãäœæããïŒããã¡ãã»ãŒãžãååŸãã
ãªããã°org.hibernate.validator.ValidationMessages
ãšããããã©ã«ãã®ãã¡ã€ã«ããã¡ãã»ãŒãžãååŸããŸãã
ãã®åãã¯ãSpringã§Bean Validationã䜿ãäžã§ãæŒãããŠãããšè¯ãã§ãããã
Spring FrameworkãšBean Validation
äžæ¹ã§ãSpring FrameworkåŽã¯ããã»ã©Bean Validationã«ã€ããŠã¯è©³ããæžããŠããŸããã
LocalValidatorFactoryBean
ãSpringã®æäŸããValidator
ãMethodValidationPostProcessor
ãDataBinder
ãªã©ã
Springåºæã®è©±ãšããŠè§ŠããããŠããŸãã
Spring Bootã«è³ã£ãŠã¯ãã»ãšãã©èšè¿°ããããŸãããã¯ã©ã¹ãã¹äžã«Bean Validationã®å®è£
ãããå Žåã«ãèªåã§æå¹ã«
ãªããŸãããããã§ããã
Spring Frameworkã§äœ¿ãBean Validationã«ãèªäœã®ã¡ãã»ãŒãžãã¡ã€ã«ãçµã¿èŸŒã
ã§ãSpring Bootã§èªåã§çšæããã¡ãã»ãŒãžçšã®ããããã£ãã¡ã€ã«ãçµã¿èŸŒãã«ã¯ïŒãšããæ¹æ³ã§èª¿ã¹ããšã
ã ãããLocalValidatorFactoryBean
ã«å¯ŸããŠãReloadableResourceBundleMessageSource
ãMessageSource
ãšããŠ
çµã¿èŸŒããããªæ¹æ³ãèŠã€ãããšæããŸãã
Custom Validation MessageSource in Spring Boot | Baeldung
Spring Frameworkã®ããªããŒã·ã§ã³ã§ã¯Bean Validationã§ã®ã¡ãã»ãŒãžè§£æ±ºã®éã«MessageSource
ããã³MessageCodesResolver
ã
䜿ãããã«ãªã£ãŠããããã§ãã
Core / Validation, Data Binding, and Type Conversion / Resolving Codes to Error Messages
ã€ãŸããSpring Bootã®å Žåã¯messages.properties
ã«MessageCodesResolver
ã®ã«ãŒã«ã«åŸã£ãŠèšè¿°ã§ããããšã«ãªããŸãã
MessageCodesResolver
ã®ããã©ã«ãã®å®è£
ã¯ãã¡ãã
DefaultMessageCodesResolver (Spring Framework 5.3.6 API)
messages.properties
ã§è§£æ±ºã§ããªãã£ãå Žåã¯ãBean Validationã§ã®ã¡ãã»ãŒãžè§£æ±ºã®ä»çµã¿ã«ãã©ãŒã«ããã¯ããããã§ãã
ãã®å Žåã¯ãçµå±ã®ãšããå
éšã§åãã®ã¯Bean Validationãªã®ã§ãValidationMessages.properties
ãã¡ã€ã«ãååšããã°
ãã¡ããå©çšããæåã«ãªããŸãã
MessageSource
ãæž¡ããå Žåã¯ãæå³ãšããŠã¯ValidationMessages.properties
ã§ã¯ãªãå¥ã®ãã¡ã€ã«ããèªã¿èŸŒãããã«
Bean Validationãã«ã¹ã¿ãã€ãºããããšãšã»ãŒåãã®ããã§ãã
ãœãŒã¹ã³ãŒããšããŠã¯ãuserResourceBundleLocator
ãSpringïŒãšãããã¢ããªã±ãŒã·ã§ã³åŽïŒã§äœã£ãŠæž¡ããã©ãã
ïŒæå®ããªãã£ãå Žåã¯ãããã©ã«ãã®ValidationMessages.properties
ãæ¢ãããšããïŒãšããããšã«ãªããŸãã
Beanå®çŸ©ã§ããããã³ãŒããæžããå Žåã¯ã
localValidatorFactoryBean.setValidationMessageSource(messageSource);
SpringåŽã§ResourceBundleLocator
ã®ã€ã³ã¹ã¿ã³ã¹ãäœã£ãŠãHibernate Validatorã«æž¡ããŠValidationMessages.properties
ã®
代ããã«äœ¿ãããšããæãã§ãã
ãã£ãšããSpringãæäŸããMessageSource
ã®å®è£
ã«ã¯è¯ãããããŸãããããããSpringã®ããªããŒã·ã§ã³ã®ä»çµã¿ã§ã¡ãã»ãŒãžè§£æ±ºã«
䜿ãããã®ã¯MessageSource
ãªã®ã§ããã¡ãã«åŸãæ¹ãçŽ çŽãªã®ãããããŸããã
ReloadableResourceBundleMessageSource (Spring Framework 5.3.6 API)
ResourceBundleMessageSource (Spring Framework 5.3.6 API)
ãªããHibernate Validatorã䜿ãã¡ãã»ãŒãžã¯æ¬¡ã®3çš®é¡ããããŸãã
ValidationMessages.properties
ContributorValidationMessages.properties
org.hibernate.validator.ValidationMessages
ã¡ãã»ãŒãžã®è§£æ±ºã¯ãValidationMessages.properties
â ContributorValidationMessages.properties
â
org.hibernate.validator.ValidationMessages
ã®é ã«è¡ãããŸãã
â»ãœãŒã¹ã³ãŒããèŠãŠãããšãContributorValidationMessages.properties
ã䜿ãããã®ã«ã¯æ¡ä»¶ãããã¿ããã§ããã©ã
ãã®ãããValidationMessages.properties
ã«ããã©ã«ãã§å®çŸ©ãããã¡ãã»ãŒãžïŒorg.hibernate.validator.ValidationMessages
ã§
å®çŸ©ãããã¡ãã»ãŒãžïŒãšåãããŒãçšæãããšããã®ã¡ãã»ãŒãžãäžæžãããããšãã§ããããšã«ãªããŸãã
ããã©ã«ãã®ã¡ãã»ãŒãžãå®çŸ©ãããŠããã®ã¯ããã¡ãã
ãšãŸãã説æã¯ãããããã«ããŠãå®éã«è©ŠããŠã¿ãŸãããã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã§ãã
$ java --version openjdk 11.0.11 2021-04-20 OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04) OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing) $ mvn --version Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-73-generic", arch: "amd64", family: "unix"
æºå
Spring Bootãããžã§ã¯ããäœæããŸããäŸåé¢ä¿ã¯ãvalidation
ã®ã¿ãå«ããŸããã
$ curl -s https://start.spring.io/starter.tgz \ -d bootVersion=2.4.5 \ -d javaVersion=11 \ -d name=my-validator-and-message \ -d groupId=org.littlewings \ -d artifactId=my-validator-and-message \ -d version=0.0.1-SNAPSHOT \ -d packageName=org.littlewings.spring.beanvalidation \ -d dependencies=validation \ -d baseDir=my-validator-and-message | tar zxvf - $ cd my-validator-and-message $ find src -name '*.java' | xargs rm
Spring Bootã®ããŒãžã§ã³ã¯2.4.5ã§ãæåããå ¥ã£ãŠãããœãŒã¹ã³ãŒãã¯åé€ã
Mavenã®äŸåé¢ä¿ãªã©ã¯ããã¡ãã§ãã
<properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
èªäœã®Validatorãäœæãã
ãŸãã¯ãèªåã§ValidatorãäœæããŸãããé¡ãšããŠã¯ãã¢ãããŒã·ã§ã³ã§æå®ããå€ã®ã©ããã§ããããšããšããã«ãŒã«ã«
ããŸãããã
ãããªæãã§äœæã
src/main/java/org/littlewings/spring/beanvalidation/Select.java
package org.littlewings.spring.beanvalidation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = SelectValidator.class) @Documented @Repeatable(Select.List.class) public @interface Select { String message() default "{org.littlewings.spring.beanvalidation.Select.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String[] value(); @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { Select[] value(); } }
ã¡ãã»ãŒãžã¯ãèšå®ãã¡ã€ã«ãåç §ããããã«ããŠããŸãã
ValidatoråŽã
src/main/java/org/littlewings/spring/beanvalidation/SelectValidator.java
package org.littlewings.spring.beanvalidation; import java.util.Arrays; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class SelectValidator implements ConstraintValidator<Select, String> { Select select; @Override public void initialize(Select select) { this.select = select; } @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { return Arrays.asList(select.value()).contains(value); } }
ã¡ãã»ãŒãžãã¡ã€ã«ã«ã€ããŠã¯ãããããå€ããªããè©ŠããŠããã®ã§åŸã§èŒããŸãã
@SpringBootApplicationãä»äžããã¯ã©ã¹
åäœç¢ºèªã¯ããã¹ãã³ãŒãã§è¡ãããšã«ããŸããã
ãšã¯ããã@SpringBootApplication
ã¢ãããŒã·ã§ã³ãä»äžãããã¯ã©ã¹ã¯å¿
èŠã«ãªãã®ã§ãäœã£ãŠãããŸãã
src/main/java/org/littlewings/spring/beanvalidation/App.java
package org.littlewings.spring.beanvalidation; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { }
ãã¹ãã³ãŒã
ãŸãã¯ãããªããŒã·ã§ã³ãè¡ã察象ã®ã¯ã©ã¹ãçšæããŸãã
src/test/java/org/littlewings/spring/beanvalidation/Person.java
package org.littlewings.spring.beanvalidation; import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; public class Person { @NotEmpty String firstName; @NotNull @Select({"磯é", "ãã°ç°"}) String lastName; @Min(1) int age; // getterïŒsetterã¯çç¥ }
æšæºã®ã¢ãããŒã·ã§ã³ãå©çšã
èªåã§äœã£ã@Select
ã¢ãããŒã·ã§ã³ã¯lastName
ã«ä»äžããŠãã磯éããšããã°ç°ãã®ã¿OKãšããããã«ããŠããŸãã
ãã¹ãã³ãŒãã¯ããã¡ãã
src/test/java/org/littlewings/spring/beanvalidation/ValidationTest.java
package org.littlewings.spring.beanvalidation; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.Validator; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest public class ValidationTest { @Autowired Validator validator; @Test public void valid() { Person katsuo = new Person(); katsuo.setLastName("磯é"); katsuo.setFirstName("ã«ããª"); katsuo.setAge(11); BeanPropertyBindingResult errors1 = new BeanPropertyBindingResult(katsuo, "bean"); validator.validate(katsuo, errors1); assertThat(errors1.hasErrors()).isFalse(); Person masuo = new Person(); masuo.setLastName("ãã°ç°"); masuo.setFirstName("ãã¹ãª"); masuo.setAge(28); BeanPropertyBindingResult errors2 = new BeanPropertyBindingResult(masuo, "bean"); validator.validate(masuo, errors2); assertThat(errors2.hasErrors()).isFalse(); } @Test public void notValid() { Person taro = new Person(); taro.setFirstName("倪é"); taro.setAge(-1); BeanPropertyBindingResult errors1 = new BeanPropertyBindingResult(taro, "bean"); validator.validate(taro, errors1); assertThat(errors1.hasErrors()).isTrue(); assertThat(errors1.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( // ãšã©ãŒæã®ã¡ãã»ãŒãž ); Person suzuki = new Person(); suzuki.setLastName("éŽæš"); suzuki.setAge(-1); BeanPropertyBindingResult errors2 = new BeanPropertyBindingResult(suzuki, "bean"); validator.validate(suzuki, errors2); assertThat(errors2.hasErrors()).isTrue(); assertThat(errors2.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( // ãšã©ãŒæã®ã¡ãã»ãŒãž ); } }
ããªããŒã·ã§ã³ã«ã¯ãSpringã®Validator
ãš
@Autowired
Validator validator;
BeanPropertyBindingResult
ã䜿ãããšã«ããŸããã
Person katsuo = new Person(); katsuo.setLastName("磯é"); katsuo.setFirstName("ã«ããª"); katsuo.setAge(11); BeanPropertyBindingResult errors1 = new BeanPropertyBindingResult(katsuo, "bean"); validator.validate(katsuo, errors1); assertThat(errors1.hasErrors()).isFalse();
ããªããŒã·ã§ã³ãOKãšãªãæ¹ã¯ããã§ããããããããã¯ãNGãšãªãæ¹ã®ã¡ãã»ãŒãžå®çŸ©ãäžå¿ã«èŠãŠãããŸãã
ã¡ãã»ãŒãžå®çŸ©ã®ãããã
ValidationMessages.propertiesã䜿ã
ãŸãã¯ãValidationMessages.properties
ãçšæããŸãããã
src/main/resources/ValidationMessages.properties
org.littlewings.spring.beanvalidation.Select.message={value} ã®ããããããéžæããŠãã ãã
ãã¡ããé 眮ããæã¯ããšã©ãŒã¡ãã»ãŒãžãå«ãããã¹ãçµæã¯ããã®ããã«ãªããŸãã
@Test public void notValid() { Person taro = new Person(); taro.setFirstName("倪é"); taro.setAge(-1); BeanPropertyBindingResult errors1 = new BeanPropertyBindingResult(taro, "bean"); validator.validate(taro, errors1); assertThat(errors1.hasErrors()).isTrue(); assertThat(errors1.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "lastName : null ã¯èš±å¯ãããŠããŸãã", "age : 1 以äžã®å€ã«ããŠãã ãã" ); Person suzuki = new Person(); suzuki.setLastName("éŽæš"); suzuki.setAge(-1); BeanPropertyBindingResult errors2 = new BeanPropertyBindingResult(suzuki, "bean"); validator.validate(suzuki, errors2); assertThat(errors2.hasErrors()).isTrue(); assertThat(errors2.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "firstName : 空èŠçŽ ã¯èš±å¯ãããŠããŸãã", "age : 1 以äžã®å€ã«ããŠãã ãã" ); }
ä»ã®2ã€ã®ãã®ã¯ãæšæºã®ã¢ãããŒã·ã§ã³ã§ã®ã¡ãã»ãŒãžã§ããã
ãã®ãã¡ã€ã«ã®å 容ã§ãã
ã§ã¯ããã§ãæšæºã®ã¢ãããŒã·ã§ã³ã«å¯Ÿå¿ããã¡ãã»ãŒãžãå®çŸ©ããŠã¿ãŸãã@NotNull
ãš@Min
ã«å¯ŸããŠå®çŸ©ãã圢ã§ãã
@NotEmpty
ã¯ãç¹ã«å€ããŸããã
src/main/resources/ValidationMessages.properties
org.littlewings.spring.beanvalidation.Select.message={value} ã®ããããããéžæããŠãã ãã javax.validation.constraints.NotNull.message = null ã¯ãã¡ã§ã javax.validation.constraints.Min.message = {value} 以äžã§ãé¡ãããŸã
ãããããšãã¡ãã»ãŒãžã¯ãããããã®ããã«å€åããŸãã
assertThat(errors1.hasErrors()).isTrue(); assertThat(errors1.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", //"lastName : null ã¯èš±å¯ãããŠããŸãã", "lastName : null ã¯ãã¡ã§ã", //"age : 1 以äžã®å€ã«ããŠãã ãã" "age : 1 以äžã§ãé¡ãããŸã" ); assertThat(errors2.hasErrors()).isTrue(); assertThat(errors2.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "firstName : 空èŠçŽ ã¯èš±å¯ãããŠããŸãã", //"age : 1 以äžã®å€ã«ããŠãã ãã" "age : 1 以äžã§ãé¡ãããŸã" );
@NotNull
ãš@Min
ã¯å®çŸ©ããã¡ãã»ãŒãžã«å€æŽããã@NotEmpty
ã¯ãã®ãŸãŸã§ããã
ã€ãŸããå¿
èŠãªãã®ã ãäžæžãã§ããŸãããšããŸããæåã®ç¢ºèªçµæãããç¬èªã«ã¡ãã»ãŒãžãã¡ã€ã«ãçšæãããããšãã£ãŠ
ããã©ã«ãã®å
容ãå¡ãã€ã¶ããšããããã§ããªãããã§ãã
LocalValidatorFactoryBeanãšMessageSourceã䜿ã
次ã¯ãLocalValidatorFactoryBean
ãšMessageSource
ã䜿ã£ãŠã¿ãŸãããã
ãŸããã¡ãã»ãŒãžãã¡ã€ã«ã¯ValidationMessages.properties
ãããªããŒã ããŠãããŸãã
$ mv src/main/resources/ValidationMessages.properties src/main/resources/my-validation-messages.properties
ãã®æç¹ã§ããã¹ãã³ãŒãã¯èªåã®ããªããŒã·ã§ã³ã®ã¡ãã»ãŒãžãå€æŽããæšæºã¢ãããŒã·ã§ã³ã®ã¡ãã»ãŒãžãããããªããªãã
ãã¹ãã¯å€±æããŸãã
ãªããŒã åŸã®ãã¡ã€ã«ã
src/main/resources/my-validation-messages.properties
org.littlewings.spring.beanvalidation.Select.message={value} ã®ããããããéžæããŠãã ãã javax.validation.constraints.NotNull.message = null ã¯ãã¡ã§ã javax.validation.constraints.Min.message = {value} 以äžã§ãé¡ãããŸã
ãããŠããã®ãã¡ã€ã«ã䜿ãããã«ReloadableResourceBundleMessageSource
ãMessageSource
ãšããŠèšå®ãã
LocalValidatorFactoryBean
ãBeanå®çŸ©ã
src/main/java/org/littlewings/spring/beanvalidation/ValidatorConfig.java
package org.littlewings.spring.beanvalidation; import java.io.IOException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @Configuration public class ValidatorConfig { @Bean public LocalValidatorFactoryBean localValidatorFactoryBean() throws IOException { LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean(); ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasename("classpath:my-validation-messages"); messageSource.setDefaultEncoding("UTF-8"); localValidatorFactoryBean.setValidationMessageSource(messageSource); return localValidatorFactoryBean; } }
ããã§ãåãã以äžã®ã¡ãã»ãŒãžãæåŸ ãããã¹ãããã¹ããããã«ãªããŸãã
assertThat(errors1.hasErrors()).isTrue(); assertThat(errors1.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", //"lastName : null ã¯èš±å¯ãããŠããŸãã", "lastName : null ã¯ãã¡ã§ã", //"age : 1 以äžã®å€ã«ããŠãã ãã" "age : 1 以äžã§ãé¡ãããŸã" ); assertThat(errors2.hasErrors()).isTrue(); assertThat(errors2.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "firstName : 空èŠçŽ ã¯èš±å¯ãããŠããŸãã", //"age : 1 以äžã®å€ã«ããŠãã ãã" "age : 1 以äžã§ãé¡ãããŸã" );
æšæºã¢ãããŒã·ã§ã³ã«å¯Ÿå¿ããã¡ãã»ãŒãžãã³ã¡ã³ãã¢ãŠããããš
src/main/resources/my-validation-messages.properties
org.littlewings.spring.beanvalidation.Select.message={value} ã®ããããããéžæããŠãã ãã #javax.validation.constraints.NotNull.message = null ã¯ãã¡ã§ã #javax.validation.constraints.Min.message = {value} 以äžã§ãé¡ãããŸã
åœç¶ãšããã°åœç¶ã§ãããæšæºã¢ãããŒã·ã§ã³ã«å¯Ÿããã¡ãã»ãŒãžã¯å ã«æ»ããŸãã
assertThat(errors1.hasErrors()).isTrue(); assertThat(errors1.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "lastName : null ã¯èš±å¯ãããŠããŸãã", //"lastName : null ã¯ãã¡ã§ã", "age : 1 以äžã®å€ã«ããŠãã ãã" //"age : 1 以äžã§ãé¡ãããŸã" ); assertThat(errors2.hasErrors()).isTrue(); assertThat(errors2.getFieldErrors().stream().map(f -> f.getField() + " : " + f.getDefaultMessage()).collect(Collectors.toList())) .hasSize(3) .containsOnly( "lastName : [磯é, ãã°ç°] ã®ããããããéžæããŠãã ãã", "firstName : 空èŠçŽ ã¯èš±å¯ãããŠããŸãã", "age : 1 以äžã®å€ã«ããŠãã ãã" //"age : 1 以äžã§ãé¡ãããŸã" );
ããšãåœéåïŒResourceBundle
ïŒãæ°ã«ããªãã®ãªãããããªæãã§ãããã®ã§ã¯ïŒãšæã£ãããããã®ã§ããã
src/main/java/org/littlewings/spring/beanvalidation/ValidatorConfig.java
package org.littlewings.spring.beanvalidation; import java.io.IOException; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.context.support.StaticMessageSource; import org.springframework.core.io.ClassPathResource; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @Configuration public class ValidatorConfig { @Bean public LocalValidatorFactoryBean localValidatorFactoryBean() throws IOException { LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean(); PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("my-validation-messages.properties")); propertiesFactoryBean.setFileEncoding("UTF-8"); propertiesFactoryBean.afterPropertiesSet(); StaticMessageSource messageSource = new StaticMessageSource(); messageSource.setCommonMessages(propertiesFactoryBean.getObject()); /* ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasename("classpath:my-validation-messages"); messageSource.setDefaultEncoding("UTF-8"); */ localValidatorFactoryBean.setValidationMessageSource(messageSource); return localValidatorFactoryBean; } }
StaticMessageSource
ã¯ãã¹ãã§äœ¿ããããã®æ³å®ã§æããæ¹ãè¯ãããã§ããã
StaticMessageSource (Spring Framework 5.3.6 API)
ãã¡ãã®ã³ãŒãã®å Žåãå®è³ªäœ¿ã£ãŠããã®ã¯ããã«ããProperties
ã ããªãã§ãããã
ãŸããå®é䜿ããªãâŠãšãªããšValidationMessages.properties
ã䜿ããLocalValidatorFactoryBean
ãš
ReloadableResourceBundleMessageSource
ã䜿ã£ãŠBeanå®çŸ©ãããšããæãã§ããããã
ãŸãšã
Spring BootãšBean Validationã䜿ã£ãŠãèªåã§äœã£ãValidatorãšã¡ãã»ãŒãžãã¡ã€ã«ã®çµã¿èŸŒã¿æ¹ã確èªããŠã¿ãŸããã
倧åã®å
容ã¯Bean Validationã®è©±ãªæ°ã¯ããŸãããå¿ããŠããããšãå€ãã£ãã®ã§å確èªã®æå³ã§ããã£ãŠãããŠ
è¯ãã£ãããªãšæããŸãã