퀭한눈 달팽이 2023. 3. 5. 00:01

 

오늘까지 되게 고민이 많았던 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");
}

보기도 깔끔하고, 기존거 대비 의미없는 반복 수도 많이 줄인거 같아서 좋습니다.