β μΆκ°λ μꡬμ¬ν
νμ κ²μ¦: κ°κ²©, μλμ λ¬Έμκ° λ€μ΄κ°λ©΄ κ²μ¦ μ€λ₯ μ²λ¦¬
νλ κ²μ¦: μνλͺ νμ, κ°κ²© λ²μ μ€μ , μλ νκ³
νΉμ νλμ λ²μλ₯Ό λμ΄μλ κ²μ¦: κ°κ²© * μλμ ν©μ 10,000μ μ΄μ
컨νΈλ‘€λ¬μ μ€μν μν μ€ νλλ HTTP μμ²μ΄ μ μμΈμ§ κ²μ¦νλ κ²
π
- ν΄λΌμ΄μΈνΈ κ²μ¦μ μ‘°μν μ μμΌλ―λ‘ λ³΄μμ μ·¨μ½(ν¬μ€νΈλ§¨μ μκ°ν΄λ΄λΌ)
- μλ²λ§μΌλ‘ κ²μ¦νλ©΄, μ¦κ°μ μΈ κ³ κ° μ¬μ©μ± λΆμ‘±
- λμ μ μ ν μμ΄ μ¬μ©νλ, μ΅μ’ μ μΌλ‘ μλ² κ²μ¦μ νμ
- API λ°©μμ μ¬μ©νλ©΄ API μ€νμ μ μ μν΄ κ²μ¦ μ€λ₯λ₯Ό API μλ΅ κ²°κ³Όμ μ λ¨κ²¨μ£Όμ΄μΌ ν¨
validation νλ‘μ νΈ
Map<String, String> errors = new HashMap<>();
: κ²μ¦ μ€λ₯ λ°μμ μ΄λ€ κ²μ¦μμ μ€λ₯κ° λ°μνλμ§ μ 보λ₯Ό λ΄μλ .
μ΄λ€ νλμμ μ€λ₯κ° λ°μνλμ§ κ΅¬λΆνκΈ° μν΄ μ€λ₯κ° λ°μν νλλͺ
μ key
λ‘ μ¬μ©ν¨.
μ΄ν λ·°μμ μ΄ λ°μ΄ν°λ₯Ό μ¬μ©ν΄ κ³ κ°μκ² μΉμ ν μ€λ₯ λ©μμ§λ₯Ό μΆλ ₯ν μ μμ.
th:if
: 쑰건μ λ§μ‘±ν λλ§ ν΄λΉ HTML νκ·Έλ₯Ό μΆλ ₯ν μ μμ.
π
errorsκ° nullμ΄λΌλ©΄ λ±λ‘νΌμ μ§μ ν μμ μλ errorsκ° μλ€.
λ°λΌμerrors.containskey()
λ₯Ό νΈμΆνλ μκ° NullPointerExceptionμ΄ λ°μνλ€.
errors?.
: errorsκ° nullμΌ λ NullPointerExceptionμ΄ λ°μνλ λμ , nullμ λ°ννλ λ¬Έλ²
th:if
μμ nullμ μ€ν¨λ‘ μ²λ¦¬λλ―λ‘ μ€λ₯ λ©μμ§κ° μΆλ ₯λμ§ μμ.
th=classappend
: ν΄λΉ νλμ μ€λ₯κ° μμΌλ©΄ field-errorλΌλ ν΄λμ€ μ 보λ₯Ό λν΄ νΌμ μμ λΉ¨κ°μμΌλ‘ κ°μ‘°. κ°μ΄ μλ€λ©΄ _
(No-Operation)μ μ¬μ©ν΄ μ무κ²λ νμ§ μμ.
v1μ λ¬Έμ μ
- λ·° ν νλ¦Ώμμ μ€λ³΅ μ²λ¦¬κ° λ§λ€.
- νμ μ€λ₯ μ²λ¦¬κ° μλλ€.
- νμ μ€λ₯κ° λ°μνμ λ κ³ κ°μ΄ μ΄λ€ λ΄μ© λλ¬Έμ μ€λ₯κ° λ°μνλμ§ μ΄ν΄ν μ μλ€.
- κ²°κ΅ κ³ κ°μ΄ μ λ ₯ν κ°λ μ΄λκ° λ³λλ‘ κ΄λ¦¬κ° λμ΄μΌ νλ€.
π mac κΈ°μ€
command+R
μ μ΄μ©ν΄μ 볡μ¬ν v1 νμΌ μ΄λ¦μ v2λ‘ ν λ²μ λ°κΏ μ μμν΄λμ λͺ¨λ v1μ v2λ‘ λ°κΎΈκΈ° μν΄μλ ν΄λΉ ν΄λμ
command+shift+R
BindingResult
π @ModelAttribute
μ BindingResult
νλΌλ―Έν° μμλ₯Ό μ£Όμνμ.
(BindingResult
λ κ²μ¦ν λμ λ°λ‘ λ€μμ μμΌ νλ€.)
(BindingResult
λ Modelμ μλ ν¬ν¨)
νμ리νλ μ€νλ§μ BindingResult
λ₯Ό νμ©ν΄ νΈλ¦¬νκ² κ²μ¦ μ€λ₯λ₯Ό νννλ κΈ°λ₯μ μ 곡
@fields
: μ΄κ±Έλ‘ BindingResultκ° μ 곡νλ κ²μ¦ μ€λ₯μ μ κ·Όth:errors
: ν΄λΉ νλμ μ€λ₯κ° μλ κ²½μ° νκ·Έλ₯Ό μΆλ ₯. th:if
μ νΈμ λ²μ th:errorclass
: th:field
μμ μ§μ ν νλμ μ€λ₯κ° μμΌλ©΄ class μ 보λ₯Ό μΆκ°BindingResult
κ° μμΌλ©΄ @ModelAttribute
μ λ°μ΄ν° λ°μΈλ© μ μ€λ₯κ° λ°μν΄λ 컨νΈλ‘€λ¬κ° νΈμΆλλ€.
BindingResult
κ° μλ€λ©΄ 400 μ€λ₯κ° λ°μνλ©° 컨νΈλ‘€λ¬ νΈμΆ β, μ€λ₯νμ΄μ§λ‘ μ΄λ (μ¦, μ¬μ©μκ° λ³΄κΈ°μ μ΄λ€ μ€λ₯κ° λ°μνλμ§ μ μ μμ)BindingResult
κ° μλ€λ©΄ μ€λ₯ μ 보(FieldError)λ₯Ό BindingResult
μ λ΄μ 컨νΈλ‘€λ¬λ₯Ό μ μ νΈμΆπ BindingResult
μ κ²μ¦ μ€λ₯λ₯Ό μ μ©νλ μΈ κ°μ§ λ°©λ²
1. @ModelAttribute
μ κ°μ²΄μ νμ
μ€λ₯ λ±μΌλ‘ λ°μΈλ©μ΄ μ€ν¨νλ κ²½μ° μ€νλ§μ΄ FieldErrorλ₯Ό μμ±ν΄μ BindingResult
μ λ£μ΄μ€λ€.
κ°λ°μκ° μ§μ λ£μ΄μ€λ€.
Validator
μ¬μ©
BindingResult
λ μΈν°νμ΄μ€μ΄λ©° Errors
μΈν°νμ΄μ€λ₯Ό μμλ°κ³ μλ€.
μ€μ λ‘ λμ΄μ€λ ꡬν체λ BeanPropertyBindingResultλΌλ κ²μΈλ° λ μΈν°νμ΄μ€λ₯Ό ꡬννκ³ μμΌλ―λ‘ BindingResult
μ Errors
λ μ€μ νλλ₯Ό μ¬μ©νλ©΄ λλ€.
Errors
μΈν°νμ΄μ€λ λ¨μν μ€λ₯ μ μ₯κ³Ό μ‘°ν κΈ°λ₯μ μ 곡νμ§λ§ BindingResult
λ μ¬κΈ°μ κΈ°λ₯μ μΆκ°μ μΌλ‘ μ 곡νλ€.
addError()
λ BindingResult
κ° μ 곡νλ―λ‘ μ¬κΈ°μλ BindingResult
λ₯Ό μ¬μ©νλ©° κ΄λ‘μμΌλ‘λ BindingResult
λ₯Ό λ§μ΄ μ¬μ©νλ€.
μμ§ κ³ κ°μ΄ 쑰건μ λ§μ§ μκ² μ λ ₯ν΄ μ μΆνλ©΄ κ³ κ°μ΄ μ λ ₯νλ λ΄μ©λ€μ΄ μ¬λΌμ§λ€.
π FieldError
μμ±μ
π FieldError
νλΌλ―Έν° λͺ©λ‘
objectName
: μ€λ₯κ° λ°μν κ°μ²΄ μ΄λ¦field
: μ€λ₯ νλrejectedValue
: μ¬μ©μκ° μ
λ ₯ν κ° (κ±°μ λ κ°)bindingFailure
: νμ
μ€λ₯ κ°μ λ°μΈλ© μ€ν¨μΈμ§, κ²μ¦ μ€ν¨μΈμ§ κ΅¬λΆ κ°codes
: λ©μμ§ μ½λarguments
: λ©μμ§μμ μ¬μ©νλ μΈμdefaultMessage
: κΈ°λ³Έ μ€λ₯ λ©μμ§μ¬μ©μμ μ
λ ₯ λ°μ΄ν°κ° 컨νΈλ‘€λ¬μ @ModelAttribute
μ λ°μΈλ©λλ μμ μ μ€λ₯κ° λ°μνλ©΄ λͺ¨λΈ κ°μ²΄μ μ¬μ©μ μ
λ ₯ κ°μ μ μ§νκΈ° μ΄λ ΅λ€.
β‘οΈ FieldError
λ μ€λ₯ λ°μμ μ¬μ©μ μ
λ ₯ κ°μ μ μ₯νλ κΈ°λ₯μ μ 곡νλ€.
μ¬κΈ°μ rejectedValue
κ° λ°λ‘ μ€λ₯ λ°μμ μ¬μ©μ μ
λ ₯ κ°μ μ μ₯νλ νλμ΄λ€. bindingFailure
μλ νμ
μ€λ₯ κ°μ λ°μΈλ©μ΄ μ€ν¨νλμ§μ λν μ¬λΆλ₯Ό μ μ΄μ€λ€.
νμ리νμ μ¬μ©μ μ
λ ₯ κ° μ μ§
th:field
μμ μ€λ₯κ° λ°μνλ©΄ FieldError
μμ 보κ΄ν κ°μ μ¬μ©ν΄ κ°μ μΆλ ₯νλ€.
μ€νλ§μ λ°μΈλ© μ€λ₯ μ²λ¦¬
νμ
μ€λ₯λ‘ λ°μΈλ©μ μ€ν¨νλ©΄ μ€νλ§μ FieldError
λ₯Ό μμ±νλ©° μ¬μ©μκ° μ
λ ₯ν κ°μ λ£μ΄λλ€. κ·Έλ¦¬κ³ ν΄λΉ μ€λ₯λ₯Ό BindingResult
μ λ΄μ 컨νΈλ‘€λ¬λ₯Ό νΈμΆνλ€.
κ·Έλμ νμ
μ€λ₯μ κ°μ λ°μΈλ© μ€ν¨μλ μ¬μ©μμ μ€λ₯ λ©μμ§λ₯Ό μ μ μΆλ ₯ν μ μλ κ²μ΄λ€.
λͺ©ν: μ€λ₯ λ©μμ§λ "μν μμΈ", "μν μμ "...μ²λΌ μΌκ΄μ μΌλ‘ κ΄λ¦¬νμ.
β‘οΈ κ°μ μμ μ²λΌ νκΈλ‘ νκ³ μΆμμΌλ νκΈ μΈμ½λ©μ΄ μλΌμ μμ΄λ‘ κ°κΉ γ
γ
λ°λ‘ μμμ μμλ³Έ FieldError
λ₯Ό μ¬μ©ν κ²
code
: (μμ μμλ) required.item.itemNameλ₯Ό μ¬μ©ν΄ λ©μμ§ μ½λλ₯Ό μ§μ . λ©μμ§ μ½λλ νλκ° μλλΌ λ°°μ΄λ‘ μ¬λ¬ κ°μ μ λ¬ ν μ μμ΄, μμλλ‘ λ§€μΉν΄ μ²μ 맀μΉλλ λ©μμ§κ° μ¬μ©λ¨.
arguments
: Object[]{1000, 1000000}λ₯Ό μ¬μ©ν΄ μ½λμ {0}, {1}λ‘ μΉνν κ°μ μ λ¬.
λͺ©ν: FieldError
, ObjectError
λ λ€λ£¨κΈ° λ²κ±°λ‘μ°λ―λ‘ λ μλνμν€μ.
μμ μ BindingResult
λ νλΌλ―Έν°μμ μμκ° μ€μνλ€κ³ νμλ€. BindingResult
λ κ²μ¦ν΄μΌ ν κ°μ²΄ targetλ°λ‘ λ€μμ μ¨λ€.
λ°λΌμ BindingResult
λ μ΄λ―Έ λ³ΈμΈμ΄ κ²μ¦ν΄μΌ ν κ°μ²΄μΈ targetμ μκ³ μλ€.
BindingResult
κ° μ 곡νλ rejectValue()
, reject()
λ₯Ό μ¬μ©νλ©΄ FieldError
, ObjectError
λ₯Ό μ§μ μμ±νμ§ μκ³ λ κΉλνκ² κ²μ¦ μ€λ₯λ₯Ό λ€λ£° μ μλ€.
π rejectValue()
field
: μ€λ₯ νλλͺ
errorCode
: μ€λ₯ μ½λ(λ©μμ§μ λ±λ‘λ μ½λ X, messageResolverλ₯Ό μν μ€λ₯ μ½λ O)errorArgs
: μ€λ₯ λ©μμ§μμ {0}λ₯Ό μΉννκΈ° μν κ°defaultMessage
: μ€λ₯ λ©μμ§λ₯Ό μ°Ύμ μ μμ λ μ¬μ©νλ κΈ°λ³Έ λ©μμ§π reject()
μ€λ₯ μ½λλ "μν μ΄λ¦μ νμμ λλ€."μ κ°μ΄ μμΈν μλ, "νμ κ° μ λλ€."μ κ°μ΄ λ¨μν μλ μλ€.
λ¨μνκ² λ§λ€λ©΄ λ²μ©μ±μ΄ μ’μ μ¬λ¬ κ³³μμ μ¬μ©ν μ μμ§λ§ μΈλ°ν μμ±νκΈ°μ μ΄λ ΅λ€. λ°λλ‘ λ무 μμΈνλ©΄ λ²μ©μ±μ΄ λ¨μ΄μ§λ€.
κ·Έλμ κ°μ₯ μ’μ λ°©λ²μ λ²μ©μ±μΌλ‘ μ¬μ©νλ€ νμν λλ§ μΈλ°ν λ΄μ©μ΄ μ μ©λλλ‘ λ§λ€λ©΄ λλ€.
(μ°μ κ°μ²΄λͺ κ³Ό νλλͺ μ μ‘°ν©ν λ©μμ§κ° μλμ§ νμΈνκ³ , μλ€λ©΄ μ’ λ λ²μ©μ μΈ λ©μμ§λ₯Ό μ ννλλ‘)
π MessageCodesResolver
:
κ²μ¦ μ€λ₯ μ½λλ‘ λ©μμ§ μ½λλ€μ μμ±
MessageCodesResolver
μΈν°νμ΄μ€, DefaultMessageCodesResolver
λ κΈ°λ³Έ ꡬν체
μ£Όλ‘ ObjectError
, FieldError
μ ν¨κ» μ¬μ©
π MessageCodesResolver
μ κΈ°λ³Έ λ©μμ§ μμ± κ·μΉ
ex. μ€λ₯ μ½λ: required
, object name: item
1. required.item
2. required
ex. μ€λ₯ μ½λ: typeMismatch
, object name "user"
, field "age"
, field type: int
1. "typeMismatch.user.age"
2. "typeMismatch.age"
3. "typeMismatch.int"
4. "typeMismatch"
λμ λ°©μ
rejectValue()
, reject()
λ λ΄λΆμμ MessageCodesResolver
(μ¬κΈ°μμ λ©μμ§ μ½λλ€ μμ±)λ₯Ό μ¬μ©νλ€. FieldError
, ObjectError
μ μμ±μλ₯Ό 보면 μ€λ₯ μ½λλ₯Ό μ¬λ¬κ° κ°μ§ μ μλ€. MessageCodesResolver
λ₯Ό ν΅ν΄ μμ±λ μμλλ‘ μ€λ₯ μ½λλ₯Ό 보κ΄νλ€.μ€λ₯ λ©μμ§ μΆλ ₯
νμ리ν νλ©΄μ λ λλ§ ν λ th:errors
κ° μ€νλκ³ μ΄λ μ€λ₯κ° μλ€λ©΄ μμ±λ μ€λ₯ λ©μμ§ μ½λλ₯Ό μμλλ‘ λμκ°λ©° λ©μμ§λ₯Ό μ°Ύκ³ μλ€λ©΄ λν΄νΈ λ©μμ§λ₯Ό μΆλ ₯νλ€.
ꡬ체μ μΈ κ²μμ β‘οΈ λ ꡬ체μ μΈ κ²μΌλ‘
MessageCodesResolver
λ required.item.itemName
μ²λΌ ꡬ체μ μΈ κ²μ λ¨Όμ , κ·Έλ¦¬κ³ required
μ²λΌ λ ꡬ체μ μΈ κ²μ κ°μ₯ λμ€μ λ§λ λ€.
ex. itemName
μ κ²½μ° required κ²μ¦ μ€λ₯λ©μμ§ λ°μμ λ€μ μμλλ‘ λ©μμ§κ° μμ±
1. required.item.itemName
2. required.itemName
3. required.java.lang.String
4. required
μ΄λ κ² μμ±λ λ©μμ§ μ½λλ₯Ό κΈ°λ°μΌλ‘ 1λ²λΆν° μμλλ‘ MessageSourceμμ λ©μμ§λ₯Ό μ°Ύλλ€.
π ValidationUtils
// κ²μ¦ λ‘μ§
if(!StringUtils.hasText(item.getItemName())) {
bindingResult.rejectValue("itemName", "required");
}
λ₯Ό μλμ κ°μ΄ ν μ€λ‘ λ체 κ°λ₯.
μ 곡νλ κΈ°λ₯ = Empty
, 곡백 κ°μ λ¨μν κΈ°λ₯λ§ μ 곡
ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "itemName", "required");
π
1. rejectValue()
νΈμΆ
2. MessageCodesResolver
λ₯Ό μ¬μ©ν΄ κ²μ¦ μ€λ₯ μ½λλ‘ λ©μμ§ μ½λλ€ μμ±
3. new FieldError()
λ₯Ό μμ±νλ©° λ©μμ§ μ½λλ€μ 보κ΄
4. th:errors
μμ λ©μμ§ μ½λλ€λ‘ λ©μμ§λ₯Ό μμλλ‘ λ©μμ§μμ μ°Ύκ³ λ
ΈμΆ
κ²μ¦ μ€λ₯ μ½λλ κ°λ°μκ° μ§μ μ€μ ν μ€λ₯ μ½λ (rejectValue()
μ§μ νΈμΆ)κ³Ό μ€νλ§μ΄ μ§μ κ²μ¦ μ€λ₯μ μΆκ°ν κ²½μ°(μ£Όλ‘ νμ
μ 보 λ§μ§ μμ)μΌλ‘ λλ μ μλ€.
νμ μ€λ₯μ κ²½μ° typeMismatchλΌλ μ€λ₯ μ½λλ₯Ό μ¬μ©νλλ° μ΄ μ€λ₯ μ½λλ μ€νλ§μ΄ μ 곡ν κ²
λͺ©ν: κ²μ¦ λ‘μ§ λΆλ¦¬νκΈ°
π κ²μ¦μ 체κ³μ μΌλ‘ μ 곡νκΈ° μν΄ μ€νλ§μ΄ μ 곡νλ μΈν°νμ΄μ€
public interface Validator {
boolean supports(Class<?> clazz);
void validate(Object target, Errors errors);
}
supports() {}
: ν΄λΉ κ²μ¦κΈ°λ₯Ό μ§μνλμ§ μ¬λΆ (λ°λ‘ λ€μ [16]μμ μ΄ν΄ν μ μμ)
validate(Object target, Errors errors)
: κ²μ¦ λμ κ°μ²΄μ BindingResult
WebDataBinder
: μ€νλ§μ νλΌλ―Έν° λ°μΈλ©μ μν μ ν΄μ£Όκ³ κ²μ¦ κΈ°λ₯λ λ΄λΆμ ν¬ν¨. μ¬κΈ°μ κ²μ¦κΈ°λ₯Ό μΆκ°νλ©΄ ν΄λΉ 컨νΈλ‘€λ¬μμ κ²μ¦κΈ°λ₯Ό μλμΌλ‘ μ μ©ν μ μμ.
@InitBinder
: ν΄λΉ 컨νΈλ‘€λ¬μλ§ μν₯μ μ€. κΈλ‘λ² μ€μ μ λ³λ νμ.
v6μμλ κ²μ¦ λμ μμ @Validated
λ₯Ό λΆμ¬ κ²μ¦κΈ°λ₯Ό μ§μ νΈμΆνλ λΆλΆμ μμ΄λ€.
@Validated
: "κ²μ¦κΈ°λ₯Ό μ€ννλΌ"
μ΄ μ λ
Έν
μ΄μ
μ΄ λΆμΌλ©΄ WebDataBinderμ λ±λ‘ν κ²μ¦κΈ°λ₯Ό μ°Ύμ μ€ννλ€. κ·Έλ°λ° κ²μ¦κΈ°κ° μ¬λ¬κ°μΌ κ²½μ° μ΄λ€ κ±Έ μ€νν΄μΌ ν μ§ λͺ°λΌ μ΄λ νμν κ²μ΄ μμ μκΈ°νλ supports()
μ΄λ€.
π
@Validated
=Valid
λμ
@Valid
λ₯Ό μ¬μ©νλ €λ©΄ build.gradle μμ‘΄κ΄κ³ μΆκ°κ° νμ.
μ΄λ μλ° νμ€ κ²μ¦ μ λ Έν μ΄μ μ΄κ³@Validated
λ μ€νλ§ μ μ© κ²μ¦ μ λ Έν μ΄μ
μ λ
μ΄λ² κ°μλ 머리μ μ μ λ¦¬κ° μλΌμ νλ€μλ μ±ν°
λμ€μ λ°λ‘ μ 리λ₯Ό ν΄λ¬μΌ ν κ² κ°λ€.