ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] List의 null값 처리하기2 - 일급컬렉션, @RequestBody
    Backend/개발 2022. 5. 15. 16:04
    반응형

    컨트롤러에서 List로 된 요청을 받아오는 과정에서, null이나 empty List가 왔을 때 처리하는 방법에 대한 글이다.

    이전에 올렸던 [Spring Boot]List의 null 값 처리하기1 - CustomConverter로 @RequestParam 에서 좀 애매한 부분이 있었는데, 다른 해결 방안이 될 수 있을 것 같아서 적어본다.

    이전 글은 param, List <String>이고 이번 글은 body, List <DtoObject>라 조금 다를 수도 있지만 일단 기록용 ㅎㅎ;;

     

    요청으로 받을 DTO를 json파일로 받아와 게임을 등록하는 API가 있었는데, 이 json파일을 리스트로 한번에 받아올 수 있게 하려고 한다.

        public ResponseEntity<RiotReplayDtos> saveGameRecords(
                @RequestBody List<RiotReplayDto> riotReplayDtos) throws IOException {
            if (riotReplayDtos.isEmpty()) throw new MayoException(ErrorCode.INVALID_INPUT_VALUE, "no replays");
    		GameRecordDto gameRecordDto = gameRecordV2Service.registerGameRecord(riotReplayDto, mayoId);
            return ResponseEntity.ok(riotReplayDtos);
        }

    원래는 이렇게 riotReplayDtos.isEmpty() 또는 riotReplayDtos == null  을 검증해줘야 한다.

     

    최근에 컬렉션으로 된 필드 하나만 가지고 포장하는 일급컬렉션을 사용한 리팩터링을 진행해보았어서, 이렇게 컨트롤러에서 받아올 때도 일급 컬렉션을 사용할 수 있을까 싶어 적용해보았다.

        public ResponseEntity<RiotReplayDtos> saveGameRecords(
                @RequestBody @Valid RiotReplayDtos riotReplayDtos) throws IOException {
    		GameRecordDto gameRecordDto = gameRecordV2Service.registerGameRecord(riotReplayDto, mayoId);
            return ResponseEntity.ok(riotReplayDtos);
        }
    @JsonIgnoreProperties(ignoreUnknown = true)
    @Getter
    @ToString
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public class RiotReplayDtos {
    
        @ApiModelProperty(value = "리플레이 json파일을 입력해주세요.")
        @NotEmpty(message = "리플레이 json파일을 입력해주세요.")
        private List<RiotReplayDto> riotReplayDtos;
    
        public RiotReplayDtos(List<RiotReplayDto> riotReplayDtos) {
            this.riotReplayDtos = riotReplayDtos;
        }
    
        public boolean isEmpty() {
            return riotReplayDtos.isEmpty();
        }
    }

     

     

    일급 컬렉션을 final로 생성해보려고 했는데 그건 잘 안돼서 일단은 불변성은 처리하지 못했지만, @NotEmpty 조건을 걸어주고 @Valid로 설정해서 테스트를 해보았다.

     

    성공 테스트

        @Test
        @DisplayName("게임 등록 -  여러게임 한번에 등록 ")
        void saveGameRecorsTest() throws Exception {
            ObjectMapper mapper = new ObjectMapper();
            RiotReplayDto riotReplayDto = RiotReplayDto.builder()
                    .gameId(12L)
                    .gameType(GameTypeCode.REGULAR)
                    .gameCreationTime(123L)
                    .gameLength(123L)
                    .statsJson(null)
                    .build();
            Map<String, Object> map = new HashMap<>();
            map.put("riotReplayDtos", Lists.newArrayList(riotReplayDto, riotReplayDto));
            MvcResult mvcResult = mvc.perform(post("/api/game/records")
                    .contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(mapper.writeValueAsString(map)))
                    .andDo(print())
                    .andExpect(status().isOk())
                    .andReturn();
        }
    MockHttpServletResponse:
               Status = 200
        Error message = null
              Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"]
         Content type = application/json;charset=UTF-8
                 Body = {"riotReplayDtos":[{"gameId":12,"gameCreationTime":123,"gameType":"REGULAR","gameLength":123,"statsJson":null},{"gameId":12,"gameCreationTime":123,"gameType":"REGULAR","gameLength":123,"statsJson":null}],"empty":false}
        Forwarded URL = null
       Redirected URL = null
              Cookies = []

    실패 테스트

    @Test
        @DisplayName("게임 등록 - null일 경우 여러게임 한번에 등록 실패 ")
        void saveGameRecorsNullTest() throws Exception {
            ObjectMapper mapper = new ObjectMapper();
           Map<String, Object> map = new HashMap<>();
            map.put("riotReplayDtos", null);
            MvcResult mvcResult = mvc.perform(post("/api/game/records")
                    .contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(mapper.writeValueAsString(map)))
                    .andDo(print())
                    .andExpect(status().isBadRequest())
                    .andReturn();
        }
    
        @Test
        @DisplayName("게임 등록 - empty일 경우 여러게임 한번에 등록 실패 ")
        void saveGameRecorsEmptyTest() throws Exception {
            ObjectMapper mapper = new ObjectMapper();
           Map<String, Object> map = new HashMap<>();
            map.put("riotReplayDtos", Lists.newArrayList());
            MvcResult mvcResult = mvc.perform(post("/api/game/records")
                    .contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(mapper.writeValueAsString(map)))
                    .andDo(print())
                    .andExpect(status().isBadRequest())
                    .andReturn();
        }
    MockHttpServletResponse:
               Status = 400
        Error message = null
              Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"]
         Content type = application/json;charset=UTF-8
                 Body = {"status":400,"code":"C001","message":"Invalid input value","errors":[{"field":"riotReplayDtos","value":"null","message":"리플레이 json파일을 입력해주세요."}]}
        Forwarded URL = null
       Redirected URL = null
              Cookies = []

     

     

    일급 컬렉션을 이용해서 유효성 검증을 좀 더 편리하게 할 수 있을 것 같다!

    댓글

Designed by Tistory.