스프링/4. 스프링 MVC-2

33. 오류메시지 3

sdafdq 2023. 9. 2. 14:45

사실 그동안 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