내일배움캠프
87 TIL
퀭한눈 달팽이
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");
}
보기도 깔끔하고, 기존거 대비 의미없는 반복 수도 많이 줄인거 같아서 좋습니다.