사실 그동안 resolve에 대해 익히 학습하였기 때문에 이 개념까지 자세히 파야 할 이유가 있나 싶긴 하다.
우리가 과거
bindingResult.rejectValue("itemName", "required");
이렇게 하면 required라는 이름으로 템플릿이 렌더링 될 때 th:errors를 수행할 때 errors.properties에서 저 required 코드를 찾아 넣는다.
이 때, 우선순위가 있다. 더 자세한 순이다.
저 rejectValue를 해 놓으면,
new FieldError("item", "itemName", item.getItemName(), false, new String[]{"required.item.itemName"}, null, null)
자동으로 이걸 생성해 주는거다.
근데 rejectValue 내부적으로 MessageCodesResolver라는 걸 쓰는데, 이름 그대로이다.
.properties의 메시지코드에 대한 resolve를 해준다.
위에 필드에러 생성할 때 메시지 코드를 배열로 여러개 줄 수 있는데,
얘가
public class MessageCodesResolverTest {
MessageCodesResolver codesResolver = new DefaultMessageCodesResolver();
@Test
void messageCodesResolverObject(){
String[] messagesCodes = codesResolver.resolveMessageCodes("required", "item");
assertThat(messagesCodes).containsExactly("required.item","required");
}
@Test
void messageCodesResolverField(){
String[] messages = codesResolver.resolveMessageCodes("required", "item", "itemName",String.class);
for (String message : messages) {
System.out.println("message = " + message);
}
assertThat(messages).containsExactly("required.item.itemName", "required.itemName", "required.java.lang.String", "required");
}
}
rejectValue 내부적으로 저렇게 문자열의 배열을 생성해서 저 부분에 넣어주는거다.
bindingResult.rejectValue("itemName", "required");
이 경우 bindingResult가 object name을 알고 있으므로,
String[] messagesCodes = codesResolver.resolveMessageCodes("required", "item","itemName", String.class);
해서 넣어주는거랑 똑같다.
그럼
required.item.itemName
required.item
required
이렇게 나오고,
resolveMessageCodes("코드", "오브젝트이름", "필드이름", 타입)인데,
아마 타입의 필드까지 쓰는 건 타입오류는 뭔가 default일 정도로 빈번하니 필드이름을 쓰면 꼭 넣어줘야 하는 듯 하다.
그래서
required.java.lang.String
이렇게 타입까지 조합된 코드가 나오고, 이 것들을 저 메시지 코드의 배열에 넣어주는 것이나 마찬가지이다.
그 후 가장 자세한 걸로 선택된다. th:errors에서.
참고로 required.java.lang.String 이거는 . 이 많지만 required.[java.lang.String] 이렇게 묶어서 봐야 하는 듯 하다.
참고로 containsExactly는 정확히, 순서도 정확해야 한다.
그래서 properties에서 에러코드를 짤 때
구체적인 것 -> 덜 구체적인 것으로 만들면 좋다.. 고 했는데
그냥 전체적인 것 먼저 짜 놓고 구체적인거 집어넣는 식으로 해도 되지 않나? 라고 생각한다.
뭐 예를 들어
require 답을입력하셔야 합니다.
type 제대로 된 타입을 입력하세요
type.java.lang.String 문자만 입력하셔야 합니다.
등등 ..
중요한 메시지는 자세히, 덜 중요한 메시지는 범용의 것을 이용하여.
#Object Error
#level1
totalPriceMin.item=상품의 가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}
#level2
totalPriceMin=가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}
#level1
required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
#level2 - 생략
#level3
required.java.lang.String = 필수 문자입니다.
required.java.lang.Integer = 필수 숫자입니다.
min.java.lang.String = {0} 이상의 문자를 입력하세요.
min.java.lang.Integer = {0} 이상의 숫자를 입력하세요.
range.java.lang.String = {0} ~ {1} 까지의 문자를 입력하세요.
range.java.lang.Integer = {0} ~ {1} 까지의 숫자를 입력하세요.
max.java.lang.String = {0} 까지의 문자를 허용합니다.
max.java.lang.Integer = {0} 까지의 숫자를 허용합니다.
#level4
required = 필수 값 입니다.
min = {0} 이상이어야 합니다.
range = {0} ~ {1} 범위를 허용합니다.
max = {0} 까지 허용합니다.
이렇게 처리.
#은 주석인데, level3까지 주석처리 해 보면 level4만 나옴.
참고로
if(!StringUtils.hasText(item.getItemName())){
bindingResult.rejectValue("itemName", "required");
}
이거를
ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "itemName", "required");
이렇게 한 줄로 가능
검증유틸.거부한다비어있거나공백일시(bindingResult,"필드명","에러코드")
이게 위랑 똑같음. 로직이 같음.
'스프링 > 4. 스프링 MVC-2' 카테고리의 다른 글
35. 검증로직 분리 (0) | 2023.09.02 |
---|---|
34. 오류메시지 4 (0) | 2023.09.02 |
32. 오류 메시지 2 (0) | 2023.09.02 |
31. 오류 메시지 처리 (0) | 2023.09.02 |
30. FieldError, ObjectError (0) | 2023.08.29 |