-
[Spring Boot] List의 null값 처리하기2 - 일급컬렉션, @RequestBodyBackend/개발 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 = []
일급 컬렉션을 이용해서 유효성 검증을 좀 더 편리하게 할 수 있을 것 같다!
'Backend > 개발' 카테고리의 다른 글
[DB] 커버링 인덱스, 실행 계획 Using index (0) 2023.09.11 [Spring Boot] @Transactional Rollback 관련 트러블슈팅 (0) 2023.01.30 [Spring Boot] 카카오 로그인 - 1 (0) 2022.05.01 [Spring Boot] JPA Flush 특징, 문제 해결 (0) 2022.04.17 [Spring Boot] List의 null 값 처리하기1 - CustomConverter로 @RequestParam (0) 2022.04.07