Skip to content

Commit cadf580

Browse files
authored
Merge pull request #118 from prgrms-web-devcourse-final-project/feat/22-post
fix[post]:DB에러수정
2 parents d1a4e9e + aa9db4a commit cadf580

File tree

10 files changed

+79
-58
lines changed

10 files changed

+79
-58
lines changed

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

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
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;
12+
import com.ai.lawyer.global.response.ApiResponse;
1213
import io.swagger.v3.oas.annotations.Operation;
1314
import io.swagger.v3.oas.annotations.tags.Tag;
1415
import lombok.RequiredArgsConstructor;
@@ -32,52 +33,60 @@ public class PollController {
3233

3334
@Operation(summary = "투표 단일 조회")
3435
@GetMapping("/{pollId}")
35-
public PollDto getPoll(@PathVariable Long pollId) {
36-
return pollService.getPoll(pollId);
36+
public ResponseEntity<ApiResponse<PollDto>> getPoll(@PathVariable Long pollId) {
37+
PollDto poll = pollService.getPoll(pollId);
38+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 단일 조회 성공", poll));
3739
}
3840

3941
@Operation(summary = "투표 옵션 목록 조회")
4042
@GetMapping("/{pollId}/options")
41-
public List<PollOptions> getPollOptions(@PathVariable Long pollId) {
42-
return pollService.getPollOptions(pollId);
43+
public ResponseEntity<ApiResponse<List<PollOptions>>> getPollOptions(@PathVariable Long pollId) {
44+
List<PollOptions> options = pollService.getPollOptions(pollId);
45+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 옵션 목록 조회 성공", options));
4346
}
4447

4548
@Operation(summary = "투표하기")
4649
@PostMapping("/{pollId}/vote")
47-
public ResponseEntity<?> vote(@PathVariable Long pollId, @RequestParam Long pollItemsId) {
50+
public ResponseEntity<ApiResponse<PollVoteDto>> vote(@PathVariable Long pollId, @RequestParam Long pollItemsId) {
4851
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
4952
Long memberId = Long.parseLong(authentication.getName());
50-
return ResponseEntity.ok(pollService.vote(pollId, pollItemsId, memberId));
53+
PollVoteDto result = pollService.vote(pollId, pollItemsId, memberId);
54+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 성공적으로 완료되었습니다.", result));
5155
}
5256

5357
@Operation(summary = "투표 통계 조회")
5458
@GetMapping("/{pollId}/statics")
55-
public List<PollStatics> getPollStatics(@PathVariable Long pollId) {
56-
return pollService.getPollStatics(pollId);
59+
public ResponseEntity<ApiResponse<List<PollStatics>>> getPollStatics(@PathVariable Long pollId) {
60+
List<PollStatics> statics = pollService.getPollStatics(pollId);
61+
return ResponseEntity.ok(new ApiResponse<>(200, "투표 통계 조회 성공", statics));
5762
}
5863

5964
@Operation(summary = "투표 종료")
6065
@PutMapping("/{pollId}/close")
61-
public void closePoll(@PathVariable Long pollId) {
66+
public ResponseEntity<ApiResponse<Void>> closePoll(@PathVariable Long pollId) {
6267
pollService.closePoll(pollId);
68+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 종료되었습니다.", null));
6369
}
6470

6571
@Operation(summary = "투표 삭제")
6672
@DeleteMapping("/{pollId}")
67-
public void deletePoll(@PathVariable Long pollId) {
73+
public ResponseEntity<ApiResponse<Void>> deletePoll(@PathVariable Long pollId) {
6874
pollService.deletePoll(pollId);
75+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 삭제되었습니다.", null));
6976
}
7077

7178
@Operation(summary = "진행중인 투표 Top 1 조회")
7279
@GetMapping("/top/ongoing")
73-
public PollDto getTopOngoingPoll() {
74-
return pollService.getTopPollByStatus(PollDto.PollStatus.ONGOING);
80+
public ResponseEntity<ApiResponse<PollDto>> getTopOngoingPoll() {
81+
PollDto poll = pollService.getTopPollByStatus(PollDto.PollStatus.ONGOING);
82+
return ResponseEntity.ok(new ApiResponse<>(200, "진행중인 투표 Top 1 조회 성공", poll));
7583
}
7684

7785
@Operation(summary = "종료된 투표 Top 1 조회")
7886
@GetMapping("/top/closed")
79-
public PollDto getTopClosedPoll() {
80-
return pollService.getTopPollByStatus(PollDto.PollStatus.CLOSED);
87+
public ResponseEntity<ApiResponse<PollDto>> getTopClosedPoll() {
88+
PollDto poll = pollService.getTopPollByStatus(PollDto.PollStatus.CLOSED);
89+
return ResponseEntity.ok(new ApiResponse<>(200, "종료된 투표 Top 1 조회 성공", poll));
8190
}
8291

8392
// @Operation(summary = "진행중인 투표 상세 조회")
@@ -96,63 +105,68 @@ public PollDto getTopClosedPoll() {
96105

97106
@Operation(summary = "투표 생성")
98107
@PostMapping("")
99-
public ResponseEntity<?> createPoll(@RequestBody PollCreateDto pollCreateDto) {
108+
public ResponseEntity<ApiResponse<PollDto>> createPoll(@RequestBody PollCreateDto pollCreateDto) {
100109
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
101110
Long memberId = Long.parseLong(authentication.getName());
102-
return ResponseEntity.ok(pollService.createPoll(pollCreateDto, memberId));
111+
PollDto created = pollService.createPoll(pollCreateDto, memberId);
112+
return ResponseEntity.ok(new ApiResponse<>(201, "투표가 생성되었습니다.", created));
103113
}
104114

105115
@Operation(summary = "투표 수정")
106116
@PutMapping("/{pollId}")
107-
public PollDto updatePoll(@PathVariable Long pollId, @RequestBody com.ai.lawyer.domain.poll.dto.PollUpdateDto pollUpdateDto) {
108-
return pollService.updatePoll(pollId, pollUpdateDto);
117+
public ResponseEntity<ApiResponse<PollDto>> updatePoll(@PathVariable Long pollId, @RequestBody com.ai.lawyer.domain.poll.dto.PollUpdateDto pollUpdateDto) {
118+
PollDto updated = pollService.updatePoll(pollId, pollUpdateDto);
119+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 수정되었습니다.", updated));
109120
}
110121

111122
@Operation(summary = "진행중인 투표 전체 목록 조회")
112123
@GetMapping("/ongoing")
113-
public List<PollDto> getOngoingPolls() {
114-
return pollService.getPollsByStatus(PollDto.PollStatus.ONGOING);
124+
public ResponseEntity<ApiResponse<List<PollDto>>> getOngoingPolls() {
125+
List<PollDto> polls = pollService.getPollsByStatus(PollDto.PollStatus.ONGOING);
126+
return ResponseEntity.ok(new ApiResponse<>(200, "진행중인 투표 전체 목록 조회 성공", polls));
115127
}
116128

117129
@Operation(summary = "종료된 투표 전체 목록 조회")
118130
@GetMapping("/closed")
119-
public List<PollDto> getClosedPolls() {
120-
return pollService.getPollsByStatus(PollDto.PollStatus.CLOSED);
131+
public ResponseEntity<ApiResponse<List<PollDto>>> getClosedPolls() {
132+
List<PollDto> polls = pollService.getPollsByStatus(PollDto.PollStatus.CLOSED);
133+
return ResponseEntity.ok(new ApiResponse<>(200, "종료된 투표 전체 목록 조회 성공", polls));
121134
}
122135

123136
@Operation(summary = "종료된 투표 Top N 조회")
124137
@GetMapping("/top/closed-list") //검색조건 : pi/polls/top/closed-list?size=3
125-
public List<PollDto> getTopClosedPolls(@RequestParam(defaultValue = "3") int size) {
126-
return pollService.getTopNPollsByStatus(PollDto.PollStatus.CLOSED, size);
138+
public ResponseEntity<ApiResponse<List<PollDto>>> getTopClosedPolls(@RequestParam(defaultValue = "3") int size) {
139+
List<PollDto> polls = pollService.getTopNPollsByStatus(PollDto.PollStatus.CLOSED, size);
140+
String message = String.format("종료된 투표 Top %d 조회 성공", size);
141+
return ResponseEntity.ok(new ApiResponse<>(200, message, polls));
127142
}
128143

129144
@Operation(summary = "진행중인 투표 Top N 조회")
130145
@GetMapping("/top/ongoing-list") //검색조건 : api/polls/top/ongoing-list?size=3
131-
public List<PollDto> getTopOngoingPolls(@RequestParam(defaultValue = "3") int size) {
132-
return pollService.getTopNPollsByStatus(PollDto.PollStatus.ONGOING, size);
146+
public ResponseEntity<ApiResponse<List<PollDto>>> getTopOngoingPolls(@RequestParam(defaultValue = "3") int size) {
147+
List<PollDto> polls = pollService.getTopNPollsByStatus(PollDto.PollStatus.ONGOING, size);
148+
String message = String.format("진행중인 투표 Top %d 조회 성공", size);
149+
return ResponseEntity.ok(new ApiResponse<>(200, message, polls));
133150
}
134151

135152
@Operation(summary = "index(순번)로 투표하기 - Swagger 편의용")
136153
@PostMapping("/{pollId}/vote-by-index")
137-
public ResponseEntity<?> voteByIndex(@PathVariable Long pollId, @RequestParam int index) {
154+
public ResponseEntity<ApiResponse<PollVoteDto>> voteByIndex(@PathVariable Long pollId, @RequestParam int index) {
138155
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
139156
Long memberId = Long.parseLong(authentication.getName());
140-
141157
List<PollOptions> options = pollService.getPollOptions(pollId);
142158
if (index < 1 || index > options.size()) {
143159
throw new ResponseStatusException(org.springframework.http.HttpStatus.BAD_REQUEST, "index가 옵션 범위를 벗어났습니다.");
144160
}
145161
Long pollItemsId = options.get(index - 1).getPollItemsId();
146-
return ResponseEntity.ok(pollService.vote(pollId, pollItemsId, memberId));
162+
PollVoteDto result = pollService.vote(pollId, pollItemsId, memberId);
163+
return ResponseEntity.ok(new ApiResponse<>(200, "투표가 성공적으로 완료되었습니다.", result));
147164
}
148165

149166
@ExceptionHandler(ResponseStatusException.class)
150-
public ResponseEntity<Object> handleResponseStatusException(ResponseStatusException ex) {
167+
public ResponseEntity<ApiResponse<Void>> handleResponseStatusException(ResponseStatusException ex) {
151168
int code = ex.getStatusCode().value();
152169
String message = ex.getReason();
153-
return ResponseEntity.status(code).body(new java.util.HashMap<String, Object>() {{
154-
put("code", code);
155-
put("message", message);
156-
}});
170+
return ResponseEntity.status(code).body(new ApiResponse<>(code, message, null));
157171
}
158172
}

backend/src/main/java/com/ai/lawyer/domain/poll/entity/Poll.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ public class Poll {
1919
@Column(name = "poll_id")
2020
private Long pollId;
2121

22-
@OneToOne(fetch = FetchType.LAZY)
23-
@JoinColumn(name = "post_id", nullable = true)
22+
@OneToOne(mappedBy = "poll", fetch = FetchType.LAZY)
2423
private Post post;
2524

2625
@Column(length = 100, nullable = false, name = "vote_title")

backend/src/main/java/com/ai/lawyer/domain/poll/entity/PollOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public class PollOptions {
1717
private Long pollItemsId;
1818

1919
@ManyToOne(fetch = FetchType.LAZY)
20-
@JoinColumn(name = "poll_id", nullable = false)
20+
@JoinColumn(name = "poll_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLOPTIONS_POLL"))
2121
private Poll poll;
2222

23-
@Column(length = 100, nullable = false, name = "option")
23+
@Column(length = 100, nullable = false, name = "option_text")
2424
private String option;
2525

2626
@Column(name = "count")

backend/src/main/java/com/ai/lawyer/domain/poll/entity/PollStatics.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ public class PollStatics {
1717
private Long statId;
1818

1919
@ManyToOne(fetch = FetchType.LAZY)
20-
@JoinColumn(name = "poll_id", nullable = false)
20+
@JoinColumn(name = "poll_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLSTATICS_POLL"))
2121
private Poll poll;
2222

2323
@ManyToOne(fetch = FetchType.LAZY)
24-
@JoinColumn(name = "poll_items_id", nullable = false)
24+
@JoinColumn(name = "poll_items_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLSTATICS_POLLOPTIONS"))
2525
private PollOptions pollOptions;
2626

2727
@Column(length = 10, name = "gender")

backend/src/main/java/com/ai/lawyer/domain/poll/entity/PollVote.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ public class PollVote {
1818
private Long pollVoteId;
1919

2020
@ManyToOne(fetch = FetchType.LAZY)
21-
@JoinColumn(name = "poll_id", nullable = false)
21+
@JoinColumn(name = "poll_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLVOTE_POLL"))
2222
private Poll poll;
2323

2424
@ManyToOne(fetch = FetchType.LAZY)
25-
@JoinColumn(name = "member_id", nullable = false)
25+
@JoinColumn(name = "member_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLVOTE_MEMBER"))
2626
private Member member;
2727

2828
@ManyToOne(fetch = FetchType.LAZY)
29-
@JoinColumn(name = "poll_items_id", nullable = false)
29+
@JoinColumn(name = "poll_items_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POLLVOTE_POLLOPTIONS"))
3030
private PollOptions pollOptions;
3131
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ public PollDto createPoll(PollCreateDto request, Long memberId) {
9393
pollOptionsRepository.save(option);
9494
}
9595
return convertToDto(savedPoll);
96+
} catch (ResponseStatusException e) {
97+
throw e;
9698
} catch (Exception e) {
9799
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "투표 생성 중 오류가 발생했습니다.");
98100
}

backend/src/main/java/com/ai/lawyer/domain/post/controller/PostController.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.ai.lawyer.domain.member.entity.Member;
99
import com.ai.lawyer.domain.member.repositories.MemberRepository;
1010
import com.ai.lawyer.global.jwt.TokenProvider;
11+
import com.ai.lawyer.global.response.ApiResponse;
1112
import io.swagger.v3.oas.annotations.Operation;
1213
import io.swagger.v3.oas.annotations.tags.Tag;
1314
import jakarta.servlet.http.HttpServletRequest;
@@ -147,12 +148,4 @@ public ResponseEntity<ApiResponse<List<PostDto>>> getMyPosts() {
147148
List<PostDto> posts = postService.getMyPosts(memberId);
148149
return ResponseEntity.ok(new ApiResponse<>(200, "본인 게시글 전체 조회 성공", posts));
149150
}
150-
151-
@Data
152-
@AllArgsConstructor
153-
public static class ApiResponse<T> {
154-
private int code;
155-
private String message;
156-
private T result;
157-
}
158151
}

backend/src/main/java/com/ai/lawyer/domain/post/entity/Post.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class Post {
2222
private Long postId;
2323

2424
@ManyToOne(fetch = FetchType.LAZY)
25-
@JoinColumn(name = "member_id", nullable = false)
25+
@JoinColumn(name = "member_id", nullable = false, foreignKey = @ForeignKey(name = "FK_POST_MEMBER"))
2626
private Member member;
2727

2828
@Column(name = "post_name", length = 100, nullable = false)
@@ -37,7 +37,7 @@ public class Post {
3737
@Column(name = "created_at")
3838
private LocalDateTime createdAt;
3939

40-
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) // 포스트 삭제 시 연관된 투표도 삭제
41-
@JoinColumn(name = "poll_id")
40+
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
41+
@JoinColumn(name = "poll_id", foreignKey = @ForeignKey(name = "FK_POST_POLL"))
4242
private Poll poll;
4343
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.ai.lawyer.global.response;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
6+
@Data
7+
@AllArgsConstructor
8+
public class ApiResponse<T> {
9+
private int code;
10+
private String message;
11+
private T result;
12+
}
13+

backend/src/test/java/com/ai/lawyer/domain/poll/controller/PollControllerTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ void t10() throws Exception {
148148
Mockito.when(pollService.getPoll(Mockito.anyLong())).thenReturn(responseDto);
149149
mockMvc.perform(get("/api/polls/1"))
150150
.andExpect(status().isOk())
151-
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.pollId").value(1L))
152-
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.voteTitle").value("테스트 투표"));
151+
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.result.pollId").value(1L))
152+
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.result.voteTitle").value("테스트 투표"));
153153
}
154154

155155
@Test
@@ -162,7 +162,7 @@ void t11() throws Exception {
162162
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post("/api/polls/1/vote")
163163
.param("pollItemsId", "1")
164164
).andExpect(status().isOk())
165-
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.pollId").value(1L))
166-
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.memberId").value(1L));
165+
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.result.pollId").value(1L))
166+
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath("$.result.memberId").value(1L));
167167
}
168168
}

0 commit comments

Comments
 (0)