[Spring MVC] [2] 4. 검증1 - Validation

윀경·2021λ…„ 9μ›” 18일
0

Spring MVC

λͺ©λ‘ 보기
18/26
post-thumbnail

[1] 검증 μš”κ΅¬μ‚¬ν•­

βž• μΆ”κ°€λœ μš”κ΅¬μ‚¬ν•­

νƒ€μž… 검증: 가격, μˆ˜λŸ‰μ— λ¬Έμžκ°€ λ“€μ–΄κ°€λ©΄ 검증 였λ₯˜ 처리
ν•„λ“œ 검증: μƒν’ˆλͺ… ν•„μˆ˜, 가격 λ²”μœ„ μ„€μ •, μˆ˜λŸ‰ ν•œκ³„
νŠΉμ • ν•„λ“œμ˜ λ²”μœ„λ₯Ό λ„˜μ–΄μ„œλŠ” 검증: 가격 * μˆ˜λŸ‰μ˜ 합은 10,000원 이상

컨트둀러의 μ€‘μš”ν•œ μ—­ν•  쀑 ν•˜λ‚˜λŠ” HTTP μš”μ²­μ΄ 정상인지 κ²€μ¦ν•˜λŠ” 것

πŸ“Œ
- ν΄λΌμ΄μ–ΈνŠΈ 검증은 μ‘°μž‘ν•  수 μžˆμœΌλ―€λ‘œ λ³΄μ•ˆμ— μ·¨μ•½(ν¬μŠ€νŠΈλ§¨μ„ 생각해봐라)
- μ„œλ²„λ§ŒμœΌλ‘œ κ²€μ¦ν•˜λ©΄, 즉각적인 고객 μ‚¬μš©μ„± λΆ€μ‘±
- λ‘˜μ„ 적절히 μ„žμ–΄ μ‚¬μš©ν•˜λ˜, μ΅œμ’…μ μœΌλ‘œ μ„œλ²„ 검증은 ν•„μˆ˜
- API 방식을 μ‚¬μš©ν•˜λ©΄ API μŠ€νŽ™μ„ 잘 μ •μ˜ν•΄ 검증 였λ₯˜λ₯Ό API 응닡 결과에 잘 남겨주어야 함


[2] ν”„λ‘œμ νŠΈ μ„€μ • V1

validation ν”„λ‘œμ νŠΈ


[3] 검증 직접 처리 - μ†Œκ°œ


[4] 검증 직접 처리 - 개발

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의 문제점

  • λ·° ν…œν”Œλ¦Ώμ—μ„œ 쀑볡 μ²˜λ¦¬κ°€ λ§Žλ‹€.
  • νƒ€μž… 였λ₯˜ μ²˜λ¦¬κ°€ μ•ˆλœλ‹€.
  • νƒ€μž… 였λ₯˜κ°€ λ°œμƒν–ˆμ„ λ•Œ 고객이 μ–΄λ–€ λ‚΄μš© λ•Œλ¬Έμ— 였λ₯˜κ°€ λ°œμƒν–ˆλŠ”μ§€ 이해할 수 μ—†λ‹€.
  • κ²°κ΅­ 고객이 μž…λ ₯ν•œ 값도 μ–΄λ”˜κ°€ λ³„λ„λ‘œ 관리가 λ˜μ–΄μ•Ό ν•œλ‹€.

[5] ν”„λ‘œμ νŠΈ μ€€λΉ„ V2

πŸ“Œ mac κΈ°μ€€ command+R을 μ΄μš©ν•΄μ„œ λ³΅μ‚¬ν•œ v1 파일 이름을 v2둜 ν•œ λ²ˆμ— λ°”κΏ€ 수 있음

ν΄λ”μ˜ λͺ¨λ“  v1을 v2둜 λ°”κΎΈκΈ° μœ„ν•΄μ„œλŠ” ν•΄λ‹Ή 폴더에 command+shift+R


[6] BindingResult1

⭐️핡심 BindingResult

πŸ“Œ @ModelAttribute와 BindingResult νŒŒλΌλ―Έν„° μˆœμ„œλ₯Ό μ£Όμ˜ν•˜μž.
(BindingResultλŠ” 검증할 λŒ€μƒ λ°”λ‘œ λ‹€μŒμ— 와야 ν•œλ‹€.)
(BindingResultλŠ” Model에 μžλ™ 포함)

νƒ€μž„λ¦¬ν”„λŠ” μŠ€ν”„λ§μ˜ BindingResultλ₯Ό ν™œμš©ν•΄ νŽΈλ¦¬ν•˜κ²Œ 검증 였λ₯˜λ₯Ό ν‘œν˜„ν•˜λŠ” κΈ°λŠ₯을 제곡

  • @fields: 이걸둜 BindingResultκ°€ μ œκ³΅ν•˜λŠ” 검증 였λ₯˜μ— μ ‘κ·Ό
  • th:errors: ν•΄λ‹Ή ν•„λ“œμ— 였λ₯˜κ°€ μžˆλŠ” 경우 νƒœκ·Έλ₯Ό 좜λ ₯. th:if의 편의 버전
  • th:errorclass: th:fieldμ—μ„œ μ§€μ •ν•œ ν•„λ“œμ— 였λ₯˜κ°€ 있으면 class 정보λ₯Ό μΆ”κ°€

[7] BindingResult2

BindingResultκ°€ 있으면 @ModelAttribute에 데이터 바인딩 μ‹œ 였λ₯˜κ°€ λ°œμƒν•΄λ„ μ»¨νŠΈλ‘€λŸ¬κ°€ ν˜ΈμΆœλœλ‹€.

  • BindingResultκ°€ μ—†λ‹€λ©΄ 400 였λ₯˜κ°€ λ°œμƒν•˜λ©° 컨트둀러 호좜 ❌, 였λ₯˜νŽ˜μ΄μ§€λ‘œ 이동 (즉, μ‚¬μš©μžκ°€ 보기엔 μ–΄λ–€ 였λ₯˜κ°€ λ°œμƒν–ˆλŠ”μ§€ μ•Œ 수 μ—†μŒ)
  • BindingResultκ°€ μžˆλ‹€λ©΄ 였λ₯˜ 정보(FieldError)λ₯Ό BindingResult에 λ‹΄μ•„ 컨트둀러λ₯Ό 정상 호좜

πŸ“Œ BindingResult에 검증 였λ₯˜λ₯Ό μ μš©ν•˜λŠ” μ„Έ 가지 방법
1. @ModelAttribute의 객체에 νƒ€μž… 였λ₯˜ λ“±μœΌλ‘œ 바인딩이 μ‹€νŒ¨ν•˜λŠ” 경우 μŠ€ν”„λ§μ΄ FieldErrorλ₯Ό μƒμ„±ν•΄μ„œ BindingResult에 λ„£μ–΄μ€€λ‹€.

  1. κ°œλ°œμžκ°€ 직접 λ„£μ–΄μ€€λ‹€.

  2. Validator μ‚¬μš©

BindingResultλŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ©° Errors μΈν„°νŽ˜μ΄μŠ€λ₯Ό 상속받고 μžˆλ‹€.
μ‹€μ œλ‘œ λ„˜μ–΄μ˜€λŠ” κ΅¬ν˜„μ²΄λŠ” BeanPropertyBindingResultλΌλŠ” 것인데 두 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ³  μžˆμœΌλ―€λ‘œ BindingResult와 Errors λ‘˜ 쀑에 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
Errors μΈν„°νŽ˜μ΄μŠ€λŠ” λ‹¨μˆœν•œ 였λ₯˜ μ €μž₯κ³Ό 쑰회 κΈ°λŠ₯을 μ œκ³΅ν•˜μ§€λ§Œ BindingResultλŠ” 여기에 κΈ°λŠ₯을 μΆ”κ°€μ μœΌλ‘œ μ œκ³΅ν•œλ‹€.
addError()도 BindingResultκ°€ μ œκ³΅ν•˜λ―€λ‘œ μ—¬κΈ°μ„œλŠ” BindingResultλ₯Ό μ‚¬μš©ν•˜λ©° κ΄€λ‘€μƒμœΌλ‘œλ„ BindingResultλ₯Ό 많이 μ‚¬μš©ν•œλ‹€.

아직 고객이 쑰건에 λ§žμ§€ μ•Šκ²Œ μž…λ ₯ν•΄ μ œμΆœν•˜λ©΄ 고객이 μž…λ ₯ν–ˆλ˜ λ‚΄μš©λ“€μ΄ 사라진닀.


[8] FieldError, ObjectError

πŸ“Œ FieldError μƒμ„±μž

πŸ“Œ FieldError νŒŒλΌλ―Έν„° λͺ©λ‘

  • objectName: 였λ₯˜κ°€ λ°œμƒν•œ 객체 이름
  • field: 였λ₯˜ ν•„λ“œ
  • rejectedValue: μ‚¬μš©μžκ°€ μž…λ ₯ν•œ κ°’ (거절된 κ°’)
  • bindingFailure: νƒ€μž… 였λ₯˜ 같은 바인딩 μ‹€νŒ¨μΈμ§€, 검증 μ‹€νŒ¨μΈμ§€ ꡬ뢄 κ°’
  • codes: λ©”μ‹œμ§€ μ½”λ“œ
  • arguments: λ©”μ‹œμ§€μ—μ„œ μ‚¬μš©ν•˜λŠ” 인자
  • defaultMessage: κΈ°λ³Έ 였λ₯˜ λ©”μ‹œμ§€

μ‚¬μš©μžμ˜ μž…λ ₯ 데이터가 컨트둀러의 @ModelAttribute에 λ°”μΈλ”©λ˜λŠ” μ‹œμ μ— 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ λͺ¨λΈ 객체에 μ‚¬μš©μž μž…λ ₯ 값을 μœ μ§€ν•˜κΈ° μ–΄λ ΅λ‹€.
➑️ FieldErrorλŠ” 였λ₯˜ λ°œμƒμ‹œ μ‚¬μš©μž μž…λ ₯ 값을 μ €μž₯ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€.

μ—¬κΈ°μ„œ rejectedValueκ°€ λ°”λ‘œ 였λ₯˜ λ°œμƒμ‹œ μ‚¬μš©μž μž…λ ₯ 값을 μ €μž₯ν•˜λŠ” ν•„λ“œμ΄λ‹€. bindingFailureμ—λŠ” νƒ€μž… 였λ₯˜ 같은 바인딩이 μ‹€νŒ¨ν–ˆλŠ”μ§€μ— λŒ€ν•œ μ—¬λΆ€λ₯Ό 적어쀀닀.

νƒ€μž„λ¦¬ν”„μ˜ μ‚¬μš©μž μž…λ ₯ κ°’ μœ μ§€
th:fieldμ—μ„œ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ FieldErrorμ—μ„œ λ³΄κ΄€ν•œ 값을 μ‚¬μš©ν•΄ 값을 좜λ ₯ν•œλ‹€.

μŠ€ν”„λ§μ˜ 바인딩 였λ₯˜ 처리
νƒ€μž… 였λ₯˜λ‘œ 바인딩에 μ‹€νŒ¨ν•˜λ©΄ μŠ€ν”„λ§μ€ FieldErrorλ₯Ό μƒμ„±ν•˜λ©° μ‚¬μš©μžκ°€ μž…λ ₯ν•œ 값을 λ„£μ–΄λ‘”λ‹€. 그리고 ν•΄λ‹Ή 였λ₯˜λ₯Ό BindingResult에 λ‹΄μ•„ 컨트둀러λ₯Ό ν˜ΈμΆœν•œλ‹€.
κ·Έλž˜μ„œ νƒ€μž… 였λ₯˜μ™€ 같은 바인딩 μ‹€νŒ¨μ—λ„ μ‚¬μš©μžμ˜ 였λ₯˜ λ©”μ‹œμ§€λ₯Ό 정상 좜λ ₯ν•  수 μžˆλŠ” 것이닀.


[9] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리1

λͺ©ν‘œ: 였λ₯˜ λ©”μ‹œμ§€λ„ "μƒν’ˆ 상세", "μƒν’ˆ μˆ˜μ •"...처럼 μΌκ΄€μ μœΌλ‘œ κ΄€λ¦¬ν•˜μž.
➑️ κ°•μ˜ 예제처럼 ν•œκΈ€λ‘œ ν•˜κ³  μ‹Άμ—ˆμœΌλ‚˜ ν•œκΈ€ 인코딩이 μ•ˆλΌμ„œ μ˜μ–΄λ‘œ κ°ˆκΉ€ γ… γ… 

λ°”λ‘œ μœ„μ—μ„œ μ•Œμ•„λ³Έ FieldErrorλ₯Ό μ‚¬μš©ν•  것

code: (μ˜ˆμ œμ—μ„œλŠ”) required.item.itemNameλ₯Ό μ‚¬μš©ν•΄ λ©”μ‹œμ§€ μ½”λ“œλ₯Ό 지정. λ©”μ‹œμ§€ μ½”λ“œλŠ” ν•˜λ‚˜κ°€ μ•„λ‹ˆλΌ λ°°μ—΄λ‘œ μ—¬λŸ¬ 값을 전달 ν•  수 μžˆμ–΄, μˆœμ„œλŒ€λ‘œ 맀칭해 처음 λ§€μΉ­λ˜λŠ” λ©”μ‹œμ§€κ°€ μ‚¬μš©λ¨.
arguments: Object[]{1000, 1000000}λ₯Ό μ‚¬μš©ν•΄ μ½”λ“œμ˜ {0}, {1}둜 μΉ˜ν™˜ν•  값을 전달.


[10] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리2

λͺ©ν‘œ: FieldError, ObjectErrorλŠ” 닀루기 λ²ˆκ±°λ‘œμš°λ―€λ‘œ 더 μžλ™ν™”μ‹œν‚€μž.

μ˜ˆμ „μ— BindingResultλŠ” νŒŒλΌλ―Έν„°μ—μ„œ μˆœμ„œκ°€ μ€‘μš”ν•˜λ‹€κ³  ν–ˆμ—ˆλ‹€. BindingResultλŠ” 검증해야 ν•  객체 targetλ°”λ‘œ λ‹€μŒμ— μ˜¨λ‹€.
λ”°λΌμ„œ BindingResultλŠ” 이미 본인이 검증해야 ν•  객체인 target을 μ•Œκ³  μžˆλ‹€.

BindingResultκ°€ μ œκ³΅ν•˜λŠ” rejectValue(), reject()λ₯Ό μ‚¬μš©ν•˜λ©΄ FieldError, ObjectErrorλ₯Ό 직접 μƒμ„±ν•˜μ§€ μ•Šκ³ λ„ κΉ”λ”ν•˜κ²Œ 검증 였λ₯˜λ₯Ό λ‹€λ£° 수 μžˆλ‹€.

πŸ“Œ rejectValue()

  • field: 였λ₯˜ ν•„λ“œλͺ…
  • errorCode: 였λ₯˜ μ½”λ“œ(λ©”μ‹œμ§€μ— λ“±λ‘λœ μ½”λ“œ X, messageResolverλ₯Ό μœ„ν•œ 였λ₯˜ μ½”λ“œ O)
    단지 μ§€κΈˆμ€ "μ—λŸ¬ μ½”λ“œ ν•˜λ‚˜λ§Œ λ„£μœΌλ©΄ 였브젝트, ν•„λ“œλ₯Ό μ°Έκ³ ν•΄ μ½”λ“œλ₯Ό λ§Œλ“€μ–΄μ£Όλ‚˜λ³΄λ‹€"라고만 μ΄ν•΄ν•˜κ³  있자.
  • errorArgs: 였λ₯˜ λ©”μ‹œμ§€μ—μ„œ {0}λ₯Ό μΉ˜ν™˜ν•˜κΈ° μœ„ν•œ κ°’
  • defaultMessage: 였λ₯˜ λ©”μ‹œμ§€λ₯Ό 찾을 수 없을 λ•Œ μ‚¬μš©ν•˜λŠ” κΈ°λ³Έ λ©”μ‹œμ§€

πŸ“Œ reject()


[11] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리3

였λ₯˜ μ½”λ“œλŠ” "μƒν’ˆ 이름은 ν•„μˆ˜μž…λ‹ˆλ‹€."와 같이 μžμ„Έν•  μˆ˜λ„, "ν•„μˆ˜ κ°’ μž…λ‹ˆλ‹€."와 같이 λ‹¨μˆœν•  μˆ˜λ„ μžˆλ‹€.

λ‹¨μˆœν•˜κ²Œ λ§Œλ“€λ©΄ λ²”μš©μ„±μ΄ μ’‹μ•„ μ—¬λŸ¬ κ³³μ—μ„œ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ μ„Έλ°€νžˆ μž‘μ„±ν•˜κΈ°μ—” μ–΄λ ΅λ‹€. λ°˜λŒ€λ‘œ λ„ˆλ¬΄ μžμ„Έν•˜λ©΄ λ²”μš©μ„±μ΄ 떨어진닀.
κ·Έλž˜μ„œ κ°€μž₯ 쒋은 방법은 λ²”μš©μ„±μœΌλ‘œ μ‚¬μš©ν•˜λ‹€ ν•„μš”ν•  λ•Œλ§Œ μ„Έλ°€ν•œ λ‚΄μš©μ΄ μ μš©λ˜λ„λ‘ λ§Œλ“€λ©΄ λœλ‹€.

(μš°μ„  객체λͺ…κ³Ό ν•„λ“œλͺ…을 μ‘°ν•©ν•œ λ©”μ‹œμ§€κ°€ μžˆλŠ”μ§€ ν™•μΈν•˜κ³ , μ—†λ‹€λ©΄ μ’€ 더 λ²”μš©μ μΈ λ©”μ‹œμ§€λ₯Ό μ„ νƒν•˜λ„λ‘)


[12] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리4

πŸ“Œ MessageCodesResolver:
검증 였λ₯˜ μ½”λ“œλ‘œ λ©”μ‹œμ§€ μ½”λ“œλ“€μ„ 생성
MessageCodesResolver μΈν„°νŽ˜μ΄μŠ€, DefaultMessageCodesResolverλŠ” κΈ°λ³Έ κ΅¬ν˜„μ²΄
주둜 ObjectError, FieldError와 ν•¨κ»˜ μ‚¬μš©

πŸ“Œ MessageCodesResolver의 κΈ°λ³Έ λ©”μ‹œμ§€ 생성 κ·œμΉ™

  • 객체 였λ₯˜μ˜ 경우 λ‹€μŒ μˆœμ„œλ‘œ 2가지 생성
  1. error code + "." + object name
  2. error code

ex. 였λ₯˜ μ½”λ“œ: required, object name: item
1. required.item
2. required

  • ν•„λ“œ 였λ₯˜μ˜ 경우 λ‹€μŒ μˆœμ„œλ‘œ 4가지 λ©”μ‹œμ§€ μ½”λ“œ 생성
  1. error code + "." + object name + "." + field
  2. error code + "." + field
  3. error code + "." + field type
  4. error code

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κ°€ μ‹€ν–‰λ˜κ³  μ΄λ•Œ 였λ₯˜κ°€ μžˆλ‹€λ©΄ μƒμ„±λœ 였λ₯˜ λ©”μ‹œμ§€ μ½”λ“œλ₯Ό μˆœμ„œλŒ€λ‘œ λŒμ•„κ°€λ©° λ©”μ‹œμ§€λ₯Ό μ°Ύκ³  μ—†λ‹€λ©΄ λ””ν΄νŠΈ λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•œλ‹€.


[13] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리5

ꡬ체적인 κ²ƒμ—μ„œ ➑️ 덜 ꡬ체적인 κ²ƒμœΌλ‘œ

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μ—μ„œ λ©”μ‹œμ§€ μ½”λ“œλ“€λ‘œ λ©”μ‹œμ§€λ₯Ό μˆœμ„œλŒ€λ‘œ λ©”μ‹œμ§€μ—μ„œ μ°Ύκ³  λ…ΈμΆœ


[14] 였λ₯˜ μ½”λ“œμ™€ λ©”μ‹œμ§€ 처리6

검증 였λ₯˜ μ½”λ“œλŠ” κ°œλ°œμžκ°€ 직접 μ„€μ •ν•œ 였λ₯˜ μ½”λ“œ (rejectValue() 직접 호좜)κ³Ό μŠ€ν”„λ§μ΄ 직접 검증 였λ₯˜μ— μΆ”κ°€ν•œ 경우(주둜 νƒ€μž… 정보 λ§žμ§€ μ•ŠμŒ)으둜 λ‚˜λˆŒ 수 μžˆλ‹€.

νƒ€μž… 였λ₯˜μ˜ 경우 typeMismatchλΌλŠ” 였λ₯˜ μ½”λ“œλ₯Ό μ‚¬μš©ν•˜λŠ”λ° 이 였λ₯˜ μ½”λ“œλŠ” μŠ€ν”„λ§μ΄ μ œκ³΅ν•œ 것


[15] Validator 뢄리1

λͺ©ν‘œ: 검증 둜직 λΆ„λ¦¬ν•˜κΈ°

πŸ“Œ 검증을 μ²΄κ³„μ μœΌλ‘œ μ œκ³΅ν•˜κΈ° μœ„ν•΄ μŠ€ν”„λ§μ΄ μ œκ³΅ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€

public interface Validator {
    boolean supports(Class<?> clazz);
    void validate(Object target, Errors errors);
}

supports() {}: ν•΄λ‹Ή 검증기λ₯Ό μ§€μ›ν•˜λŠ”μ§€ μ—¬λΆ€ (λ°”λ‘œ λ‹€μŒ [16]μ—μ„œ 이해할 수 있음)
validate(Object target, Errors errors): 검증 λŒ€μƒ 객체와 BindingResult


[16] Validator 뢄리2

WebDataBinder: μŠ€ν”„λ§μ˜ νŒŒλΌλ―Έν„° λ°”μΈλ”©μ˜ 역할을 ν•΄μ£Όκ³  검증 κΈ°λŠ₯도 내뢀에 포함. 여기에 검증기λ₯Ό μΆ”κ°€ν•˜λ©΄ ν•΄λ‹Ή μ»¨νŠΈλ‘€λŸ¬μ—μ„œ 검증기λ₯Ό μžλ™μœΌλ‘œ μ μš©ν•  수 있음.
@InitBinder: ν•΄λ‹Ή μ»¨νŠΈλ‘€λŸ¬μ—λ§Œ 영ν–₯을 쀌. κΈ€λ‘œλ²Œ 섀정은 별도 ν•„μš”.

v6μ—μ„œλŠ” 검증 λŒ€μƒ μ•žμ— @Validatedλ₯Ό λΆ™μ—¬ 검증기λ₯Ό 직접 ν˜ΈμΆœν•˜λŠ” 뢀뢄을 μ—†μ•΄λ‹€.
@Validated: "검증기λ₯Ό μ‹€ν–‰ν•˜λΌ"
이 μ• λ…Έν…Œμ΄μ…˜μ΄ λΆ™μœΌλ©΄ WebDataBinder에 λ“±λ‘ν•œ 검증기λ₯Ό μ°Ύμ•„ μ‹€ν–‰ν•œλ‹€. 그런데 검증기가 μ—¬λŸ¬κ°œμΌ 경우 μ–΄λ–€ κ±Έ μ‹€ν–‰ν•΄μ•Ό 할지 λͺ°λΌ μ΄λ•Œ ν•„μš”ν•œ 것이 μ•žμ„œ μ–˜κΈ°ν–ˆλ˜ supports()이닀.

πŸ“Œ
@Validated = Valid

λŒ€μ‹  @Validλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ build.gradle μ˜μ‘΄κ΄€κ³„ μΆ”κ°€κ°€ ν•„μš”.
μ΄λŠ” μžλ°” ν‘œμ€€ 검증 μ• λ…Έν…Œμ΄μ…˜μ΄κ³  @ValidatedλŠ” μŠ€ν”„λ§ μ „μš© 검증 μ• λ…Έν…Œμ΄μ…˜



μœ λ… 이번 κ°•μ˜λŠ” 머리에 잘 정리가 μ•ˆλΌμ„œ νž˜λ“€μ—ˆλ˜ 챕터
λ‚˜μ€‘μ— λ”°λ‘œ 정리λ₯Ό 해둬야 ν•  것 κ°™λ‹€.

profile
개발 바보 이사 쀑

0개의 λŒ“κΈ€