본문 바로가기
  • 오늘도 한걸음. 수고많았어요.^^
  • 조금씩 꾸준히 오래 가자.ㅎ
IT기술/spring

[Spring] BindingResult 검증도구

by 미노드 2024. 2. 20.

스프링이 제공하는 검증 오류를 보관하는 객체입니다.

컨트롤러에서 파라미터로 선언시키며, 검증 오류가 발생하면 여기에 보관하면 view로 전달 가능합니다.

BindingResult.addError(에러객체)

에러객체 : 에러라고 판단할 정보를 담은 객체이며
ObjectError , FieldError 가 사용됩니다.
사용자가 원하는 오류 코드와, 오류 메시지를 만들고 message.properties 또는 별도의 프로퍼티를 만들어 저장 한 뒤
특정한 상황이 되면 BindingResult 에서 에러를 불러와서 출력시키기 위해 사용합니다.

이는 특정 상황에서 어떤 오류가 발생했는지 표준화를 시키기 위해, 그리고 원하는 조건에 부합하지 않을 경우
즉, 검증되지 않은 특정한 상황에서, 커스텀 에러를 내고싶을 때 사용합니다.

bindingResult.addError(new FieldError("item", "itemName", item.getItemName(), false, new String[]{"required.item.itemName"}, null,null));

bindingResult.addError(new ObjectError("item", new String[] {"totalPriceMin"}, new Object[]{10000, resultPrice}, null));

ObjectError

경우 다음 순서로 2가지 생성 (MessageResolver가 만듭니다.)
1.: code + "." + object name
2.: code
예) code: "required", object name: item 
1.: required.item
2.: required

FieldError

필드 오류의 경우 다음 순서로 4가지 메시지 코드 생성 (MessageResolver가 만듭니다.)
1.: code + "." + object name + "." + field
2.: code + "." + field
3.: code + "." + field type
4.: code
예) code : "typeMismatch", object name : "user", field : "age", field type : int
1. "typeMismatch.user.age"
2. "typeMismatch.age"
3. "typeMismatch.int"
4. "typeMismatch"

typeMismatch 는 주어진 변수와 일치하지않는 변수가 들어오면 스프링이 자동으로 만들어주는 에러코드입니다.

여기서 순서가 중요한 부분인데, application code를 변경하지 않고
프로퍼티만 주석쳐가면서 상태변경으로, 에러코드 우선순위를 다르게 잡아서 각각 다른 메시지를 출력할 수 있는데,
그 기준이 1, 2, 3, 4 순서 입니다.
1번 순서에 해당하는 에러코드가 있으면 1번출력
1번없을땐 2번순서에 해당하는 에러코드 출력
2번없을땐 3번순서에 해당하는 에러코드 출력
3번없을땐 4번순서에 해당하는 에러코드 출력 입니다.
스프링에서 이 순서로 에러코드를 읽을테니 프로퍼티에 이 양식대로 에러코드를 만들어둬라! 이소립니다.

이 방식은 Controller같은 Application Code를 변경하지 않는 부분이 장점이라고 할 수 있습니다.

그러나 FieldError를 잡는데에 4가지 순위로 매번 프로퍼티에 할당시키는 것, 그리고 우선순위를 MessageResolver 가 제공하는 순서에 맞춰야하는 것이 과연 옳은 것인지는 잘 모르겠습니다.

에러코드의 우선순위는 로직으로 맞춰야지, 리졸버가 만들어주는 네이밍 형식에 맞추는게 무슨의미가 있고 어떤 장점이 있는지는 아직 이해되지 않습니다.
실제로 원하는 에러코드와 value가 나와야되는데, 다른 에러코드가 나오도록 변경하던지 하면 될텐데,
우선순위가 낮은 에러코드가 잡히도록 하는것이 맞는것인지도 잘 모르겠습니다.

다만 에러 우선순위로 에러코드를 지원하는 기능을 MessageResolver가 제공하고,
그 기능을 이용해서 에러를 출력하는 방식도 있다는 것을 정리해봅니다.

스프링이 제공하는 디폴트 메시지를 변경하는 방법은?

스프링이 에러코드를 자동으로 만들어주면서 에러메시지도 고정적으로 지원하는데,
이를 코드로 변경할 수는 없습니다.
스프링에서 박아놓은 것이며, 에러코드 또한 위의 순서대로 자동으로 잡히도록 선언해 뒀기 때문입니다.

그러나 스프링이 제공하는 디폴트 메시지를 그대로 출력하는 것은 문제가 있습니다.
사용자에게 아래처럼 영어로 에러메시지를 보여줄 수는 없기 때문입니다.
Failed to convert property value of type java.lang.String to required type java.lang.Integer for property price; For input string:

이를 대응하려면 위의 순서를 이해하고, 해당 오류코드가 무엇으로 잡히는지 분석한 뒤 프로퍼티에 넣어서 value를 원하는 것으로 치환해주면 됩니다.

실제로 로그를 찍어보면 Int로 받는곳에 문자가 들어오면 에러코드는 다음처럼 잡히는게 확인됩니다.

1순위. "typeMismatch.item.price"
2순위. "typeMismatch.price"
3순위. "typeMismatch.java.lang.Integer"
4순위. "typeMismatch"

에러코드는 타임리프에서 뱉어주는 로그를 확인했으며, 프로퍼티에 넣어서 value를 치환해줍시다.
기본적으로 message.properties를 사용하겠지만, 원한다면 다른 프로퍼티를 사용하도록 설정을 추가해줘도 됩니다.

이런식으로 프로퍼티에 자동으로 생성되는 에러코드와 해당하는 value를 지정해주면
스프링이 자동으로 만들어주는 에러 value가 아닌 커스텀 value를 출력시킵니다.