에러메세지 - BindingResult

jiaLEE·2022년 8월 25일
0

에러가 발생하게 되면 다음 화면을 부르는 Controller를 호출하지 못하고 바로 에러가 뜨면서 아래와 같은 화면으로 전환이 되는데, 실제 사용자가 화면을 이용하게 된다면 이와 같은 화면전환이 아닌 에러메세지가 뜨게 하는 것이 필요하다.

이런 상황에서 요긴하게 쓰이는 것이 **BindingResult** 이다.

BindingResult 를 사용하게 되면 오류가 날 때, 아래와 같이 에러메세지가 보여지게 도와준다.


사용방법

먼저 에러메세지를 담는 bindingResult는 Object 바로 뒤에서 선언되어야 한다. (-> 자동적으로 객체를 알게 해주기 위해)

 public String addItem(
 			@ModelAttribute Item item, 
 			BindingResult bindingResult, 
 			RedirectAttributes redirectAttributes, 
 			Model model) {
 			... 
 	
 	}
 

BindingResult에 에러메세지를 담아준다.

FieldError와 ObjectError 2가지의 형태가 있으며 아래와 같이 파라미터를 받는다.

//FiledError(객체명, 필드명, 메세지)
bindingResult.addError(new FieldError("item", "itemName", "상품이름은 필수입니다."));

//ObjectError(객체명, 메세지)
bindingResult.addError(new ObjectError("item", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재값 =  " + resultPrice));

위와 같이 메세지를 담게 되면 리다이렉트로 에러메세지를 담은 화면이 내려졌을때, 사용자가 기입했던 값들이 리셋이 되게 된다. 이런 경우를 방지하기 위해 rejectValue 라는 파라미터를 추가한다.

그리고 에러메세지들은 위와 같이 생성할때마다 메세지를 넣어주기 보다는 아예 errors.properties에서 메세지들을 한번에 관리하는 게 개발자에게 용이하다.

RejectValue 와 메세지 코드를 추가한다.

//FiledError
bindingResult.addError(
          new FieldError(
              "item", 				//객체명
              "quantity", 			//필드명
              item.getQuantity(), 	//RejectValue
              false, 				//객체명
              new String[]{"max.item.quantity"}, //메세지 코드
              new Object[]{9999}, 	//메세지의 {} 값
              null					//디폴트 메세지의 여부
         ));

//ObjectError
bindingResult.addError(
			new ObjectError(
            "item", 				//객체명
            new String[]{"totalPriceMin"},	// 메세지 코드
            new Object[]{10000, resultPrice}, //메세지의 {} 값
            null					//디폴트 메세지의 여부
            ));

여기서 메세지 코드를 [] 배열로 받는 이유는 값이 각 단어가 배열로 들어가기 때문이다.
위의 메세지 코드를 아래의 errors.properties에서 찾아서 에러메세지를 내려준다.

//errors.properties
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
totalPriceMin=가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}

에러 메세지에 단계를 나눠서 한꺼번에 관리한다.

에러메세지를 내려줄 때 중요한 것은 상황에 따라 간단한 에러메세지 혹은 자세한 에러메세지를 내보내 줘야한다는 것이다. 메세지에 단계를 두어서 기본적으로 범용성이 좋은 에러메세지를 사용하되, 특정 부분에서는 자세한 에러 내용이 적용되도록 하는 게 좋다.

이때, MessageCodesResolver를 사용하게 되면 알아서 메세지 코드를 생성해주는데, 우리는 이 코드를 기반으로 errors.properties에 메세지들을 넣어두게 되면, 코드를 수정하지 않고도 메세지를 관리할 수 있다.

//리졸버 생성
MessageCodesResolver codesResolver = new DefaultMessageCodesResolver();

@Test //(에러코드, 객체명)
    void messageCodesResolverObject() {
        String[] messageCodes = codesResolver.resolveMessageCodes("required", "item");
        //생성되는 에러코드들
        //messageCode = required.item
		//messageCode = required
    }
    
@Test //(에러코드, 객체명, 필드명, 타입)
    String[] messageCodes = codesResolver.resolveMessageCodes("required", "item", "itemName", String.class);
        //생성되는 에러코드들
        //messageCode = required.item.itemName
        //messageCode = required.itemName
        //messageCode = required.java.lang.String
        //messageCode = required

리졸버에 파라미터를 몇 개 넣어주느냐에 따라 생성되는 에러코드의 개수가 달라진다.
아래와 같은 순으로 중요도가 높고 메세지가 상세하다.

  1. 에러코드.객체명.필드명 //제일 자세한 에러 메세지, 중요도 제일 높음
  2. 에러코드.필드명
  3. 에러코드.타입
  4. 에러코드.

리졸브를 통해 위와 같이 에러코드들이 생성되고 내가 원하는 코드를 선택해 메세지를 errors.properties에 정의한다.

이때 Controller에서는 아래와 같이 rejectValue/reject 메소드를 통해 파라미터를 넣으면 알아서 errors.properties에 있는 에러 코드의 메세지 들 중 가장 중요한(상세한) 메세지를 가져와서 내려준다.

//FiledError(필드명, 에러코드)
bindingResult.rejectValue("itemName", "required");
//FiledError(필드명, 에러코드, 메세지에 들어가는 값, 디폴트 메세지)
bindingResult.rejectValue("quantity", "max", new Object[]{9999}, null);
 
//ObjectError(에러코드, 메세지에 들어가는 값, 디폴트 메세지)
bindingResult.reject("totalPriceMin" , new Object[]{1000, resultPrice}, null);

결국 MessageCodesResolver와 BindingResult를 통해 코드를 변경하지 않고 에러메세지만을 변경, 관리 할 수 있다.

출처ㅣ 인프런 스프링 MVC 2편 (김영한 강사님)

0개의 댓글