Skip to content

Commit

Permalink
전체 게시글 목록 조회 기능 구현 (#93)
Browse files Browse the repository at this point in the history
* refactor: (#88) 게시글 작성 시, 클라이언트로부터 받는 데이터를 매핑하는 Dto 이름 개선

* refactor: (#88) 컨트롤러 통합 테스트 삭제

* refactor: (#88) 수월한 디버깅을 위해 member toString 추가

* feat: (#88) 조건에 따라 전체 게시글을 정렬해서 조회하는 기능 구현

* feat: (#88) 클라이언트에게 데이터 전달하기 위한 response 생성

* test: (#88) 테스트 없는 메서드 테스트 코드 추가

* refactor: (#88) 서비스 메서드 트랜잭션 어노테이션 붙이기

* refactor: (#88) 이미지 삭제

* refactor: (#88) 이미지 저장 경로 변경

* refactor: (#88) 게시글 작성 시, 필요없는 파라미터 개선

* refactor: (#88) PostOptions 생성하는 코드 개선

* refactor: (#88) dto에 데이터 정제 로직들을 도메인으로 옮김

* refactor: (#88) sql문을 더 보기 쉽게 하기 위해 개행 추가

* refactor: (#88) 원시 타입을 래퍼 클래스 타입으로 변경

* refactor: (#88) 개행 없어야 하는 부분 개행 지우기

* refactor: (#88) 전체 게시글 목록 조회 기능 테스트 메서드 명 더 명확하게 개선

* refactor: (#88) enum 상수들 개행

* refactor: (#88) EqualsAndHashCode의 supercall 속성 삭제

* refactor: (#88) PostOption의 EqualsAndHashCode 삭제

* refactor: (#88) 테스트용 yml 파일 필요없는 설정 삭제

* refactor: (#88) Member 파라미터에 final 붙이기

* refactor: (#88) swagger 관련 어노테이션 중 500 에러 관련 어노테이션 생략

* refactor: (#88) 페이지 넘버 파라미터 타입을 원시 타입으로 변경

* refactor: (#88) response 변수명 더 간결하게 개선

* refactor: (#88) 투표 결과를 볼 수 있는지 판단하는 메서드를 작성자인 경우에도 볼 수 있도록 수정

* refactor: (#88) Repository의 메서드 파라미터에 final 붙이기

* refactor: (#88) isWriter의 테스트 코드 수정

* refactor: (#88) 테스트 코드에서 final 키워드 삭제

* refactor: (#88) 클래스, 필드명을 더 명확하게 개선

* refactor: (#88) Dto클래스의 이름에서 불용어인 Info 삭제

* refactor: (#88) selectedOption 의 역할이 sequence가 아닌 id가 되도록 변경

* refactor: (#88) 파라미터인 Member의 위치를 맨 밑으로 수정

* refactor: (#88) 게시글 조회 반환 값인 response dto의 생성을 정적 팩토리 메서드가 하도록 개선

* refactor: (#88) 래퍼 클래스 타입을 원시 타입으로 변경

* refactor: (#88) 연관관계 편의 메서드에 양방향에 추가하는 로직을 몰아 넣기

* refactor: (#88) 스트림에서 하나만 빼낼 시, findFirst 대신 findAny로 찾는 것으로 변경
  • Loading branch information
tjdtls690 committed Sep 12, 2023
1 parent 2109c47 commit 1a7145b
Show file tree
Hide file tree
Showing 27 changed files with 755 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = {"id"})
@ToString
@Getter
@Entity
public class Member extends BaseEntity {
Expand Down Expand Up @@ -45,7 +49,7 @@ public class Member extends BaseEntity {
private String socialId;

@Column(nullable = false)
private Integer point;
private int point;

@Builder
private Member(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public Member findById(final Long memberId) {

@Transactional(readOnly = true)
public MemberInfoResponse findMemberInfo(final Member member) {
final int numberOfPosts = postRepository.countByMember(member);
final int numberOfPosts = postRepository.countByWriter(member);
final int numberOfVotes = voteRepository.countByMember(member);

return new MemberInfoResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.votogether.domain.post.controller;

import com.votogether.domain.member.entity.Gender;
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.member.entity.SocialType;
import com.votogether.domain.post.dto.request.PostCreateRequest;
import com.votogether.domain.post.dto.response.PostResponse;
import com.votogether.domain.post.dto.response.VoteOptionStatisticsResponse;
import com.votogether.domain.post.entity.PostClosingType;
import com.votogether.domain.post.entity.PostSortType;
import com.votogether.domain.post.service.PostService;
import com.votogether.global.jwt.Auth;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -35,57 +36,60 @@ public class PostController {
@Operation(summary = "게시글 작성", description = "게시글을 저장한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "게시물 생성되었습니다."),
@ApiResponse(responseCode = "400", description = "잘못된 입력입니다."),
@ApiResponse(responseCode = "500", description = "인터넷 서버 오류입니다.")
@ApiResponse(responseCode = "400", description = "잘못된 입력입니다.")
})
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> save(
@RequestPart final PostCreateRequest request,
@RequestPart final List<MultipartFile> images
@RequestPart final List<MultipartFile> images,
@Auth final Member loginMember
) {
// TODO : 일단 돌아가게 하기 위한 member 저장 (실제 어플에선 삭제될 코드)
final Member member = Member.builder()
.socialType(SocialType.KAKAO)
.socialId("tjdtls690")
.nickname("Abel")
.gender(Gender.MALE)
.birthday("0718")
.ageRange("10~14")
.socialType(SocialType.KAKAO)
.socialId("tjdtls690")
.point(100)
.ageRange("30~39")
.birthday("0101")
.build();

final Long postId = postService.save(request, member, images);
final long postId = postService.save(request, loginMember, images);
return ResponseEntity.created(URI.create("/posts/" + postId)).build();
}

@Operation(summary = "게시글 조회", description = "게시글을 조회한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "게시글을 조회했습니다."),
@ApiResponse(responseCode = "400", description = "잘못된 입력입니다.")
})
@GetMapping
public ResponseEntity<List<PostResponse>> getAllPost(
final int page,
final PostClosingType postClosingType,
final PostSortType postSortType,
@Auth final Member loginMember
) {
final List<PostResponse> responses =
postService.getAllPostBySortTypeAndClosingType(loginMember, page, postClosingType, postSortType);

return ResponseEntity.ok(responses);
}

@Operation(summary = "게시글 투표 통계 조회", description = "게시글 투표에 대한 전체 통계를 조회한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "게시글 투표 통계 조회 성공"),
@ApiResponse(responseCode = "404", description = "존재하지 않는 게시글")
})
@GetMapping("/{postId}/options")
public ResponseEntity<VoteOptionStatisticsResponse> getVoteStatistics(
@PathVariable final Long postId,
@PathVariable final long postId,
@Auth final Member member
) {
final VoteOptionStatisticsResponse response = postService.getVoteStatistics(postId, member);
return ResponseEntity.ok(response);
}

@Operation(summary = "게시글 투표 선택지 통계 조회", description = "게시글 특정 투표 선택지에 대한 통계를 조회한다.")
@ApiResponses({
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "게시글 투표 선택지 통계 조회 성공"),
@ApiResponse(responseCode = "400", description = "게시글 투표 옵션이 게시글에 속하지 않아 조회 실패"),
@ApiResponse(responseCode = "404", description = "존재하지 않는 게시글이거나 게시글 투표 옵션")
})
@GetMapping("/{postId}/options/{optionId}")
public ResponseEntity<VoteOptionStatisticsResponse> getVoteOptionStatistics(
@PathVariable final Long postId,
@PathVariable final Long optionId,
@PathVariable final long postId,
@PathVariable final long optionId,
@Auth final Member member
) {
final VoteOptionStatisticsResponse response = postService.getVoteOptionStatistics(postId, optionId, member);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.votogether.domain.post.dto.response;

import com.votogether.domain.category.entity.Category;

public record CategoryResponse(
long id,
String name
) {

public static CategoryResponse of(Category category) {
return new CategoryResponse(category.getId(), category.getName());
}

@Override
public String toString() {
return "CategoryResponse{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.votogether.domain.post.dto.response;

import com.votogether.domain.post.entity.PostOption;

public record PostOptionResponse(
long optionId,
String content,
int voteCount,
double votePercent
) {

public static PostOptionResponse of(
final PostOption postOption,
final boolean isVisibleVoteResult,
final Long totalVoteCount
) {
return new PostOptionResponse(
postOption.getId(),
postOption.getContent(),
postOption.getVoteCount(isVisibleVoteResult),
postOption.getVotePercent(totalVoteCount)
);
}

@Override
public String toString() {
return "OptionResponse{" +
"optionId=" + optionId +
", content='" + content + '\'' +
", voteCount=" + voteCount +
", votePercent=" + votePercent +
'}';
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.votogether.domain.post.dto.response;

import com.votogether.domain.member.entity.Member;
import com.votogether.domain.post.entity.Post;
import com.votogether.domain.post.entity.PostBody;
import com.votogether.domain.post.entity.PostCategory;
import java.time.LocalDateTime;
import java.util.List;

public record PostResponse(
Long postId,
WriterResponse writer,
String title,
String content,
List<CategoryResponse> categories,
LocalDateTime createdAt,
LocalDateTime deadline,
VoteResponse voteInfo
) {

public static PostResponse of(final Post post, final Member loginMember) {
final Member writer = post.getWriter();
final PostBody postBody = post.getPostBody();

return new PostResponse(
post.getId(),
WriterResponse.of(writer.getId(), writer.getNickname().getValue()),
postBody.getTitle(),
postBody.getContent(),
getCategories(post),
post.getCreatedAt(),
post.getDeadline(),
VoteResponse.of(
post.getPostOptions().getSelectedOptionId(loginMember),
post.getFinalTotalVoteCount(loginMember),
getOptions(post, loginMember)
)
);
}

private static List<CategoryResponse> getCategories(final Post post) {
return post.getPostCategories().getPostCategories().stream()
.map(PostCategory::getCategory)
.map(CategoryResponse::of)
.toList();
}

private static List<PostOptionResponse> getOptions(
final Post post,
final Member loginMember
) {
return post.getPostOptions().getPostOptions().stream()
.map(postOption ->
PostOptionResponse.of(
postOption,
post.isVisibleVoteResult(loginMember),
post.getFinalTotalVoteCount(loginMember)
)
)
.toList();
}

@Override
public String toString() {
return "PostResponse{" +
"postId=" + postId +
", writer=" + writer +
", title='" + title + '\'' +
", content='" + content + '\'' +
", categories=" + categories +
", createdAt=" + createdAt +
", deadline=" + deadline +
", voteInfo=" + voteInfo +
'}' + "\n\n";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.votogether.domain.post.dto.response;

import java.util.List;

public record VoteResponse(
long selectedOptionId,
long totalVoteCount,
List<PostOptionResponse> options
) {

public static VoteResponse of(
final long selectedOptionId,
final long finalTotalVoteCount,
final List<PostOptionResponse> options
) {
return new VoteResponse(selectedOptionId, finalTotalVoteCount, options);
}

@Override
public String toString() {
return "VoteInfoResponse{" +
"selectedOptionId=" + selectedOptionId +
", totalVoteCount=" + totalVoteCount +
", options=" + options +
'}';
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.votogether.domain.post.dto.response;

public record WriterResponse(
Long id,
String nickname
) {

public static WriterResponse of(final Long id, final String nickname) {
return new WriterResponse(id, nickname);
}

@Override
public String toString() {
return "WriterResponse{" +
"id=" + id +
", nickname='" + nickname + '\'' +
'}';
}

}
Loading

0 comments on commit 1a7145b

Please sign in to comment.