Spring

MessageCodesResolver

dev-rootable 2023. 7. 25. 21:37

📌 단순한 오류 메시지 vs 자세한 오류 메시지

 

🔎 단순한 오류 메시지

 

# 단순한 오류 메시지
required : 필수 값입니다.
range : 범위 오류입니다.

 

  • 범용성이 좋아 여러 곳에서 사용할 수 있다.
  • 메시지를 세밀하게 작성하기 어렵다.

 

🔎 자세한 오류 메시지

 

# 자세한 오류 메시지
required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.

 

  • 범용성이 떨어진다.
  • 메시지를 세밀하게 작성할 수 있다.

 

범용성을 사용하다가 필요한 경우에만 자세한 오류 메시지를 사용하도록 메시지 단계를 두자

 

자세한 메시지일수록 우선순위를 높게 준다.

 

스프링은 MessageCodesResolver라는 것으로 이러한 기능을 지원한다.

 

📌 MessageCodesResolverTest

 

Test 코드로 MessageCodesResolver를 사용해 보자

 

package hello.itemservice.validation;

...

public class MessageCodesResolverTest {

    MessageCodesResolver codesResolver = new DefaultMessageCodesResolver();

    @DisplayName("ObjectError의 메시지 코드 생성")
    @Test
    void messageCodesResolverObject() {
        String[] messageCodes = codesResolver.resolveMessageCodes("required", "item");
        for (String messageCode : messageCodes) {
            System.out.println("messageCode = " + messageCode);
        }
    }

    @DisplayName("FieldError의 메시지 코드 생성")
    @Test
    void messageCodesResolverField() {
        String[] messageCodes = codesResolver.resolveMessageCodes("required", "item", "itemName", String.class);
        for (String messageCode : messageCodes) {
            System.out.println("messageCode = " + messageCode);
        }
    }

}

 

ObjectError의 메시지 코드 생성

 

FieldError의 메시지 코드 생성

 

🔎 원리 및 동작

 

MessageCodesResolver 인터페이스의 구현체인 DefaultMessageCodesResolver는 기본 메시지 생성 규칙을 갖고 있다. 이 규칙과 검증 오류 코드를 바탕으로 자세한 메시지 코드부터 순서대로 생성하고, 탐색 또한 자세한 메시지 코드부터 찾아온다.

 

✔ DefaultMessageCodesResolver의 기본 메시지 생성 규칙

 

#FieldError의 메시지 코드 생성
code.object_name.field #Level 1
code.field #Level 2
code.field_type #Level 3
code #Level 4

 

#ObjectError의 메시지 코드 생성
code.object_name #Level 1
code #Level 2

 

#타입 오류에 대한 메시지 코드 생성
typeMismatch.object_name.field #Level 1
typeMismatch.field #Level 2
typeMismatch.field_type #Level 3
typeMismatch #Level 4

 

스프링은 FieldError 또는 ObjectError를 생성할 때 codes 매개 변수에 messageCodes라는 위와 같은 메시지 코드들을 String 배열로 보관한다.

 

타임리프의 "th:errors"는 타임리프 화면을 렌더링 할 때 실행되는데, 만약 오류가 있다면 생성된 오류 메시지 코드를 MessageSource를 통해서 순서대로 돌아가면서 errors.properties와 매칭하는 역할을 한다. 오류 메시지 코드가 없으면 스프링에서 정한 디폴트 메시지가 출력된다.

 

스프링에서 제공하는 DefaultMessage

 

📌 오류 코드 관리 전략

 

오류 메시지 생성 및 탐색 순서 ➡ 구체적인 것에서 덜 구체적인 것으로

 

오류 코드 관리 전략은 기본적으로 모든 오류 코드에 대해 메시지를 각각 다 정의하면 관리가 힘들어지기 때문에 사용한다. 또한, 구체적인 것을 먼저 만드는 이유는 메시지와 관련된 공통 관리 전략을 편리하게 도입할 수 있기 때문이라고 한다. 이를 필자는 구체적인 영역을 묶어 보다 범용적인 영역을 쉽게 정의하기 위한 전략이라고 이해했다.

 

📌 errors.properties에 도입

 

스프링에서 오류 메시지를 Level 1 ~ Level 4 우선순위로 찾게 된다.

 

#==ObjectError==
#Level1
totalPriceMin.item=상품의 가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}

#Level2 - 생략
totalPriceMin=전체 가격은 {0}원 이상이어야 합니다. 현재 값 = {1}

#==FieldError==
#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} 까지 허용합니다.

typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.

 

검증 결과 - FieldError

 

검증 결과 - ObjectError

 

검증 결과 - typeMismatch

 

📌 검증 오류 생성 동작

 

  • rejectValue() 또는 reject() 호출
  • MessageCodesResolver를 사용해서 검증 오류 코드로 메시지 코드들을 생성
  • new FieldError() 또는 new ObjectError()를 생성하면서 메시지 코드들 보관
  • th:errors에서 메시지 코드들로 메시지를 순서대로 매칭하여 찾고, 노출

 

Reference:

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com