-
오늘까지 되게 고민이 많았던 NoShow 에 대해서 설명하겠습니다.
최종 프로잭트 주제가 모임, 만남 이다보니 노쇼에 관해서 깊게 고민했습니다.
기술적 한계로 구현이 어려울것 같아서 파티작성 및 파티 참여를 1회로 제한하고
설계했는데 주제가 퇴색되는것 같아 제약을 다풀었습니다.
처음엔 노쇼 신고를 받으면 해당 유저의 카운트가 올라가게 끔 하려 했는데
너무 가볍게 처리하는거 같아서 노쇼 객체는 아래와 같고
public NoShow(User reporter, User reported, PartyPost partyPost) { this.reporter = reporter; this.reported = reported; this.partyPost = partyPost; }
여러 제한 사항을 통과 했을 때 DB 에 저장됩니다
public ApiResponse reportNoShow(User user, NoShowRequest request) { isMySelf(user, request.getUserId()); int checkByUser = 0; int checkByMe = 0; //신고할 유저 User reported = findByUser(request.getUserId()); PartyPost partyPost = getPartyPost(request.getPartyPostId()); if (!partyPost.getStatus().equals(Status.NO_SHOW_REPORTING)) { throw new BadRequestException("노쇼 신고 기간이 만료되었습니다"); } // >>>>>>>>>>>>>>>>>>>>>> 수정할 코드 <<<<<<<<<<<<<<<<<<<<<< // 파티에 참여한 유저와 신고할 유저, 로그인한 유저를 비교함 List<Application> applicationList = partyPost.getApplications(); for (Application application : applicationList) { if (application.getUser().equals(reported)) { checkByUser++; } if (application.getUser().equals(user)) { checkByMe++; } } if (checkByUser == 0 || checkByMe == 0) { throw new BadRequestException("파티 구성원이 아닙니다"); } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // 이미 신고한 이력이 있는지 체크 if (noShowRepository.existsByReporterIdAndReportedIdAndPartyPostId(user.getId(), reported.getId(), partyPost.getId())) { throw new BadRequestException("이미 신고한 유저입니다"); } NoShow noShow = new NoShow(user, reported, partyPost); noShowRepository.save(noShow); return ApiResponse.ok("노쇼 신고 완료"); }
저장된 값들을 모아서 어떻게 비교할 수 있을까 라는 의문에 막혔는데
Map 을 이용해서 key 값으로 그룹화 시켜서 비교하면 되겠다고 판단했고 Map 기능을 잘 몰라서 좀 해맸습니다.
public void checkingNoShow(List<PartyPost> posts) { for (PartyPost partyPost : posts) { // postId = 1 partyPost.ChangeStatusEnd(); int joinUserSize = partyPost.getApplications().size(); List<NoShow> noShowList = noShowRepository.findAllByPartyPostId(partyPost.getId()); // reportId 별로 NoShow 개체를 그룹화합니다. Map<Long, List<NoShow>> reportedNoShowMap = new HashMap<>(); for (NoShow noShow : noShowList) { Long reportedId = noShow.getReported().getId(); //key 값이 없으면 해당 key 값의 리스트를 만들고 noShow 추가 reportedNoShowMap.computeIfAbsent(reportedId, k -> new ArrayList<>()).add(noShow); } //Map.Entry : 한번의 조작으로 key, value 를 둘다 가져올 수 있음 for (Map.Entry<Long, List<NoShow>> entry : reportedNoShowMap.entrySet()) { Long reportedId = entry.getKey(); List<NoShow> reportedNoShowList = entry.getValue(); int noShowReportCnt = reportedNoShowList.size(); if (noShowReportCnt >= Math.round(joinUserSize / 2.0)) { User reported = findByUser(reportedId); reported.getProfile().plusNoShowCnt(); } } } }
위 처럼 처리하니까 잘 돌아가네요. reportNoShow 에서 for 문과 count 가 너무 원시적인 방법이면서
보기도 안좋아서 어떻게 해야되나 찾아보니 stream 에 noneMatch 가 있더라고요.
이 친구를 이용해서 람다식으로 바꿧습니다
allMatch() : 모든 요소들이 매개값(Predicate)으로 주어진 조건을 만족하는지 조사
anyMatch() : 최소 한개 이상이 조건을 만족하는지 조사
noneMatch() : 모든 요소들이 주어진 조건을 만족하지 않는지 조사if (applicationList.stream().noneMatch(a -> a.getUser().equals(reported)) || applicationList.stream().noneMatch(a -> a.getUser().equals(user))) { throw new BadRequestException("Not a party member"); }
보기도 깔끔하고, 기존거 대비 의미없는 반복 수도 많이 줄인거 같아서 좋습니다.