Skip to content

Commit 04182b8

Browse files
authored
Merge pull request #160 from prgrms-web-devcourse-final-project/feat/22-post
Feat[poll]:투표 항목별 통계 기능 추가
2 parents 5a5510d + 30110d8 commit 04182b8

File tree

17 files changed

+386
-71
lines changed

17 files changed

+386
-71
lines changed

backend/src/main/java/com/ai/lawyer/domain/poll/controller/PollController.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import com.ai.lawyer.domain.poll.dto.PollCreateDto;
44
import com.ai.lawyer.domain.poll.dto.PollDto;
5+
import com.ai.lawyer.domain.poll.dto.PollStaticsResponseDto;
56
import com.ai.lawyer.domain.poll.dto.PollVoteDto;
67
import com.ai.lawyer.domain.poll.entity.PollVote;
78
import com.ai.lawyer.domain.poll.entity.PollOptions;
8-
import com.ai.lawyer.domain.poll.entity.PollStatics;
99
import com.ai.lawyer.domain.poll.service.PollService;
1010
import com.ai.lawyer.domain.post.dto.PostDetailDto;
1111
import com.ai.lawyer.domain.post.service.PostService;
@@ -54,10 +54,10 @@ public ResponseEntity<ApiResponse<PollVoteDto>> vote(@PathVariable Long pollId,
5454
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 성공적으로 완료되었습니다.", result));
5555
}
5656

57-
@Operation(summary = "투표 통계 조회")
57+
@Operation(summary = "투표 통계 조회 (항목별 나이/성별 카운트)")
5858
@GetMapping("/{pollId}/statics")
59-
public ResponseEntity<ApiResponse<List<PollStatics>>> getPollStatics(@PathVariable Long pollId) {
60-
List<PollStatics> statics = pollService.getPollStatics(pollId);
59+
public ResponseEntity<ApiResponse<PollStaticsResponseDto>> getPollStatics(@PathVariable Long pollId) {
60+
PollStaticsResponseDto statics = pollService.getPollStatics(pollId);
6161
return ResponseEntity.ok(new ApiResponse<>(200, "투표 통계 조회 성공", statics));
6262
}
6363

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
import lombok.*;
3+
4+
@Data
5+
@AllArgsConstructor
6+
@NoArgsConstructor
7+
@Builder
8+
public class PollAgeStaticsDto {
9+
private Long pollItemsId;
10+
private Integer pollOptionIndex;
11+
private java.util.List<AgeGroupCountDto> ageGroupCounts;
12+
13+
@Data
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
@Builder
17+
public static class AgeGroupCountDto {
18+
private String option;
19+
private String ageGroup;
20+
private Long voteCount;
21+
}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import java.util.List;
9+
import java.time.LocalDateTime;
10+
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Builder
15+
public class PollForPostDto {
16+
@Schema(description = "투표 제목", example = "당신의 선택은?")
17+
private String voteTitle;
18+
@Schema(description = "투표 항목(2개 필수)", example = "[{\"content\": \"항목1 내용\"}, {\"content\": \"항목2 내용\"}]")
19+
private List<PollOptionCreateDto> pollOptions;
20+
private LocalDateTime reservedCloseAt;
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
import lombok.*;
3+
4+
@Data
5+
@AllArgsConstructor
6+
@NoArgsConstructor
7+
@Builder
8+
public class PollGenderStaticsDto {
9+
private Long pollItemsId;
10+
private Integer pollOptionIndex;
11+
private java.util.List<GenderCountDto> genderCounts;
12+
13+
@Data
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
@Builder
17+
public static class GenderCountDto {
18+
private String option;
19+
private String gender;
20+
private Long voteCount;
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.ai.lawyer.domain.poll.dto;
2+
3+
import lombok.*;
4+
import java.util.List;
5+
6+
@Data
7+
@AllArgsConstructor
8+
@NoArgsConstructor
9+
@Builder
10+
public class PollStaticsResponseDto {
11+
private Long postId;
12+
private Long pollId;
13+
private List<PollAgeStaticsDto> optionAgeStatics;
14+
private List<PollGenderStaticsDto> optionGenderStatics;
15+
}

backend/src/main/java/com/ai/lawyer/domain/poll/dto/PollWithPostDto.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollStaticsRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
public interface PollStaticsRepository extends JpaRepository<PollStatics, Long> {
99
List<PollStatics> findByPoll_PollId(Long pollId);
1010
}
11+

backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,29 @@ public interface PollVoteRepository extends JpaRepository<PollVote, Long> {
2525
java.util.List<Object[]> countStaticsByPollOptionIds(@Param("pollOptionIds") java.util.List<Long> pollOptionIds);
2626

2727
boolean existsByPoll_PollIdAndMember_MemberId(Long pollId, Long memberId);
28+
29+
@Query(value = "SELECT po.option, m.gender, COUNT(*) FROM poll_vote pv JOIN poll_options po ON pv.poll_items_id = po.poll_items_id JOIN member m ON pv.member_id = m.member_id WHERE po.poll_id = :pollId GROUP BY po.option, m.gender", nativeQuery = true)
30+
List<Object[]> getGenderOptionStatics(@Param("pollId") Long pollId);
31+
32+
@Query(value = "SELECT CASE WHEN m.age < 20 THEN '10대' WHEN m.age < 30 THEN '20대' " +
33+
"WHEN m.age < 40 THEN '30대' WHEN m.age < 50 THEN '40대' WHEN m.age < 60 THEN '50대' " +
34+
"WHEN m.age < 70 THEN '60대' WHEN m.age < 80 THEN '70대' ELSE '80대 이상' " +
35+
"END AS ageGroup, m.gender, COUNT(*) FROM poll_vote pv JOIN member m ON pv.member_id = m.member_id JOIN poll_options po ON pv.poll_items_id = po.poll_items_id WHERE po.poll_id = :pollId GROUP BY ageGroup, m.gender", nativeQuery = true)
36+
List<Object[]> getAgeGenderStatics(@Param("pollId") Long pollId);
37+
38+
@Query("SELECT o.option, " +
39+
"CASE WHEN m.age < 20 THEN '10대' WHEN m.age < 30 THEN '20대' " +
40+
"WHEN m.age < 40 THEN '30대' WHEN m.age < 50 THEN '40대' WHEN m.age < 60 THEN '50대' " +
41+
"WHEN m.age < 70 THEN '60대' WHEN m.age < 80 THEN '70대' ELSE '80대 이상' END, " +
42+
"COUNT(v) " +
43+
"FROM PollVote v JOIN v.pollOptions o JOIN v.member m " +
44+
"WHERE o.poll.pollId = :pollId " +
45+
"GROUP BY o.option, " +
46+
"CASE WHEN m.age < 20 THEN '10대' WHEN m.age < 30 THEN '20대' " +
47+
"WHEN m.age < 40 THEN '30대' WHEN m.age < 50 THEN '40대' WHEN m.age < 60 THEN '50대' " +
48+
"WHEN m.age < 70 THEN '60대' WHEN m.age < 80 THEN '70대' ELSE '80대 이상' END")
49+
List<Object[]> getOptionAgeStatics(@Param("pollId") Long pollId);
50+
51+
@Query("SELECT o.option, m.gender, COUNT(v) FROM PollVote v JOIN v.pollOptions o JOIN v.member m WHERE o.poll.pollId = :pollId GROUP BY o.option, m.gender")
52+
List<Object[]> getOptionGenderStatics(@Param("pollId") Long pollId);
2853
}

backend/src/main/java/com/ai/lawyer/domain/poll/service/PollService.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,36 @@
77
import com.ai.lawyer.domain.poll.entity.PollVote;
88
import com.ai.lawyer.domain.poll.entity.PollStatics;
99
import com.ai.lawyer.domain.poll.entity.PollOptions;
10+
import com.ai.lawyer.domain.poll.dto.PollForPostDto;
11+
import com.ai.lawyer.domain.poll.dto.PollStaticsResponseDto;
1012

1113
import java.util.List;
1214

1315
public interface PollService {
16+
// ===== 조회 관련 =====
1417
PollDto getPoll(Long pollId);
18+
PollDto getPollWithStatistics(Long pollId);
1519
List<PollOptions> getPollOptions(Long pollId);
16-
PollVoteDto vote(Long pollId, Long pollItemsId, Long memberId);
17-
List<PollStatics> getPollStatics(Long pollId);
18-
void closePoll(Long pollId);
19-
void deletePoll(Long pollId);
20+
List<PollDto> getPollsByStatus(PollDto.PollStatus status);
2021
PollDto getTopPollByStatus(PollDto.PollStatus status);
22+
List<PollDto> getTopNPollsByStatus(PollDto.PollStatus status, int n);
23+
24+
// ===== 통계 관련 =====
25+
PollStaticsResponseDto getPollStatics(Long pollId);
2126
Long getVoteCountByPollId(Long pollId);
2227
Long getVoteCountByPostId(Long postId);
23-
PollDto updatePoll(Long pollId, PollUpdateDto pollUpdateDto);
24-
PollDto getPollWithStatistics(Long pollId);
28+
29+
// ===== 투표 관련 =====
30+
PollVoteDto vote(Long pollId, Long pollItemsId, Long memberId);
31+
32+
// ===== 생성/수정/삭제 관련 =====
2533
PollDto createPoll(PollCreateDto request, Long memberId);
34+
PollDto updatePoll(Long pollId, PollUpdateDto pollUpdateDto);
2635
void patchUpdatePoll(Long pollId, PollUpdateDto pollUpdateDto);
27-
List<PollDto> getPollsByStatus(PollDto.PollStatus status);
28-
List<PollDto> getTopNPollsByStatus(PollDto.PollStatus status, int n);
36+
void closePoll(Long pollId);
37+
void deletePoll(Long pollId);
38+
39+
// ===== 검증 관련 =====
40+
void validatePollCreate(PollCreateDto dto);
41+
void validatePollCreate(PollForPostDto dto);
2942
}

0 commit comments

Comments
 (0)