저번 시간에 Valid 어노테이션을 이용해서, json 입력에 대해서 검증하는 처리를 했어요. 예를 들자면, regLevel이 1 이상이여야 하고, itemName은 공백이면 안되는 조건을 걸면, itemName 필드가 공백인 것이 들어오면 400을 떨궈주게 됩니다. 이 글을 보시면 대략적으로 감이 오실 거 같아요.

 

 그런데 제 토이 프로젝트에서, validation 처리야 했다고 쳐도, 예외에 대해서 ResponseEntity를 controller에서 만들어 버렸어요. 최근에 리팩토링 한 부분이 이것을 ControllerAdvice로 뺀 것이였는데요. 그러면서 몇 개의 api에 대해서 에러 포맷도 custom 하게 처리하게 되었습니다. 이 부분은 프로젝트 변경 내역에서 확인하실 수 있습니다.

 

 


 

 이전에 했던 것을 생각해 보면, 그냥 status, error, path, timestamp 정도만 떨어졌어요. Valid가 실패하면요. 그런데, 이것을 어떤 필드가 Valid 조건을 만족하지 않는지, 그리고 어떤 에러가 나타났는지, 즉 Custom 한 ValidError 객체를 ResponseBody로 떨구고자 합니다. 문제 상황은 이해하셨으리라 생각합니다.

 

 

 validate 프로젝트에서 추가할 파일은 별 거 없습니다. exceptionController와 ErrorObject 모델 이 둘 뿐입니다.

 

 

 ErrorObject는 별 게 없습니다. 단지, fieldName하고 message만 있을 뿐입니다. exceptionController를 보겠습니다.

 

 

 ControllerAdvice를 적용했습니다. 그리고, 13번째 줄에 있는, MethodArgumentNotValidException이 떨어지면 14번째 줄에 있는 badRequestHandler 메서드로 오게 됩니다. 여기서 우리는 ResponseEntity를 custom하게 바꿔버릴 건데요. 해당 예외 객체를 디버그 해서 봅시다.

 

 

 그러면, e 밑에 bindingResult가 있고, bindingResult 밑에 errors가 있습니다.

 

 

 errors를 보면, ArrayList로 되어 있어요. 그러면 이것은 foreach문으로 읽어와야 함을 의미하는데요. 0이라고 써져 있는 것을 클릭해 보면 field와, defaultMessage가 있음을 알 수 있어요. 즉, 리스트를 순회하면서 field와 defaultMessage를 얻어오면 됩니다.

 

 

 for loop를 도는데요. e.getBindingResult().getFieldErrors()는 필드 에러들을 모아놓는 리스트를 의미합니다. 즉 Valid가 실패한 것들을 모아놓았습니다. 이 리스트들을 돌면서, Field와 Message를 얻어와서, 새로운 ErrorObject에 추가하면 됩니다. 다 추가하고 나서, ResponseEntity에는 errors를 body로 떨어트리면 됩니다.

 

 


 원하는 대로 잘 동작하는지 테스트를 해 보겠습니다.

 

 

 먼저, 요구 레벨이 0이고 item 이름이 냄비뚜껑인 아이템 하나를 저장한 리스트를 보냈어요. 이것은 valid에 걸립니다. 왜? regLevel이 1 이상이여야 한다는 조건을 위반했기 때문입니다. result에 필드 이름과, 해당 필드가 1 이상이여야 한다는 에러 메세지가 뜨네요.

 

 

 이번에는 itemName이 공백인 케이스를 보내 봅시다. regLevel은 0이고요. 그러면, regLevel이 0이니까 1 이상이여야 한다는 메세지가, 그리고 itemName이 공백이니 공백일 수 없다는 메세지가 뜨게 됩니다.

 

 

 itemList가 아무것도 없다면 어떻게 될까요? List의 크기가 1에서 2147483647 사이여야 한다는 메세지가 뜨게 됩니다.

 

 

 itemList에 객체 하나가 있어요. 그런데 객체에 값들이 없네요? 이런 경우에는 어떨까요? itemName와 regLevel이 둘 다 널이므로, 널이여서도 안되고 공백이여서도 안된다는 메세지가 떠야 합니다. 의도대로 잘 동작함을 확인하였습니다.