diff --git a/src/main/java/com/server/capple/domain/answer/controller/AnswerController.java b/src/main/java/com/server/capple/domain/answer/controller/AnswerController.java index 2f529bb1..67691145 100644 --- a/src/main/java/com/server/capple/domain/answer/controller/AnswerController.java +++ b/src/main/java/com/server/capple/domain/answer/controller/AnswerController.java @@ -3,18 +3,19 @@ import com.server.capple.config.security.AuthMember; import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse; +import com.server.capple.domain.answer.dto.AnswerResponse.AnswerInfo; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.service.AnswerService; import com.server.capple.domain.member.entity.Member; import com.server.capple.global.common.BaseResponse; +import com.server.capple.global.common.SliceResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; +import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; @Tag(name = "답변 API", description = "답변 API입니다.") @@ -26,7 +27,7 @@ public class AnswerController { private final AnswerService answerService; @Operation(summary = "답변 생성 API", description = " 답변 생성 API 입니다." + - "pathvariable 으로 questionId를 주세요.") + "pathvariable 으로 questionId를 주세요.") @PostMapping("/question/{questionId}") public BaseResponse createAnswer(@AuthMember Member member, @PathVariable(value = "questionId") Long questionId, @RequestBody @Valid AnswerRequest request) { @@ -34,25 +35,21 @@ public BaseResponse createAnswer(@AuthMember Member mem } @Operation(summary = "질문에 대한 답변 조회 API", description = "특정 질문에 대한 답변리스트를 조회하는 API입니다." - + "pathVariable으로 questionId를 주세요." - + "조회할 질문의 개수를 param으로 입력해주세요.") - @Parameters(value = { - @Parameter(name = "keyword", description = "검색"), - @Parameter(name = "size", description = "조회할 질문의 개수를 입력하세요."), - }) + + "pathVariable으로 questionId를 주세요.") @GetMapping("/question/{questionId}") - public BaseResponse getAnswerList( - @AuthMember Member member, - @PathVariable(value = "questionId") Long questionId, - @RequestParam(name = "keyword", required = false) String keyword, - @PageableDefault - @Parameter(hidden = true) Pageable pageable) { - Pageable tempPageable = PageRequest.of(pageable.getPageNumber(), 250); - return BaseResponse.onSuccess(answerService.getAnswerList(member.getId(), questionId, keyword, tempPageable)); + public BaseResponse> getAnswerList( + @AuthMember Member member, + @Parameter(description = "질문 식별자") + @PathVariable(value = "questionId") Long questionId, + @Parameter(description = "조회할 페이지 번호
0부터 시작") + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, + @Parameter(description = "조회할 페이지 크기") + @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(answerService.getAnswerList(member.getId(), questionId, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } @Operation(summary = "답변 수정 API", description = " 답변 수정 API 입니다." + - "pathvariable 으로 answerId를 주세요.") + "pathvariable 으로 answerId를 주세요.") @PatchMapping("/{answerId}") public BaseResponse updateAnswer(@AuthMember Member member, @PathVariable(value = "answerId") Long answerId, @RequestBody @Valid AnswerRequest request) { @@ -60,14 +57,14 @@ public BaseResponse updateAnswer(@AuthMember Member mem } @Operation(summary = "답변 삭제 API", description = " 답변 삭제 API 입니다." + - "pathvariable 으로 answerId를 주세요.") + "pathvariable 으로 answerId를 주세요.") @DeleteMapping("/{answerId}") public BaseResponse deleteAnswer(@AuthMember Member member, @PathVariable(value = "answerId") Long answerId) { return BaseResponse.onSuccess(answerService.deleteAnswer(member, answerId)); } @Operation(summary = "답변 좋아요/취소 API", description = " 답변 좋아요/취소 API 입니다." + - "pathvariable 으로 answerId를 주세요.") + "pathvariable 으로 answerId를 주세요.") @PostMapping("/{answerId}/heart") public BaseResponse toggleAnswerHeart(@AuthMember Member member, @PathVariable(value = "answerId") Long answerId) { return BaseResponse.onSuccess(answerService.toggleAnswerHeart(member, answerId)); @@ -75,13 +72,23 @@ public BaseResponse toggleAnswerHeart(@AuthMember Mem @Operation(summary = "작성한 답변 조회 API", description = " 작성한 답변 조회 API 입니다.") @GetMapping - public BaseResponse getMemberAnswer(@AuthMember Member member) { - return BaseResponse.onSuccess(answerService.getMemberAnswer(member)); + public BaseResponse> getMemberAnswer( + @AuthMember Member member, + @Parameter(description = "조회할 페이지 번호
0부터 시작") + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, + @Parameter(description = "조회할 페이지 크기") + @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(answerService.getMemberAnswer(member, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } @Operation(summary = "좋아한 답변 조회 API", description = " 좋아한 답변 조회 API 입니다.") @GetMapping("/heart") - public BaseResponse getMemberHeartAnswer(@AuthMember Member member) { - return BaseResponse.onSuccess(answerService.getMemberHeartAnswer(member)); + public BaseResponse> getMemberHeartAnswer( + @AuthMember Member member, + @Parameter(description = "조회할 페이지 번호
0부터 시작") + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, + @Parameter(description = "조회할 페이지 크기") + @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(answerService.getMemberHeartAnswer(member, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } } diff --git a/src/main/java/com/server/capple/domain/answer/dao/AnswerRDBDao.java b/src/main/java/com/server/capple/domain/answer/dao/AnswerRDBDao.java new file mode 100644 index 00000000..f3e55c83 --- /dev/null +++ b/src/main/java/com/server/capple/domain/answer/dao/AnswerRDBDao.java @@ -0,0 +1,10 @@ +package com.server.capple.domain.answer.dao; + +import com.server.capple.domain.answer.entity.Answer; + +public class AnswerRDBDao { + public interface AnswerInfoInterface { + public Answer getAnswer(); + public Boolean getIsReported(); + } +} diff --git a/src/main/java/com/server/capple/domain/answer/dto/AnswerResponse.java b/src/main/java/com/server/capple/domain/answer/dto/AnswerResponse.java index 7f35b5d3..d431a9ea 100644 --- a/src/main/java/com/server/capple/domain/answer/dto/AnswerResponse.java +++ b/src/main/java/com/server/capple/domain/answer/dto/AnswerResponse.java @@ -1,7 +1,5 @@ package com.server.capple.domain.answer.dto; -import java.util.List; - import lombok.*; public class AnswerResponse { @@ -26,14 +24,6 @@ public static class AnswerInfo { private String writeAt; } - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class AnswerList { - private List answerInfos; - } - @Getter @AllArgsConstructor public static class AnswerLike { @@ -55,10 +45,4 @@ public static class MemberAnswerInfo { private String writeAt; private Boolean isLiked; } - - @Getter - @AllArgsConstructor - public static class MemberAnswerList { - private List memberAnswerInfos; - } } diff --git a/src/main/java/com/server/capple/domain/answer/mapper/AnswerMapper.java b/src/main/java/com/server/capple/domain/answer/mapper/AnswerMapper.java index 4900087b..95c70918 100644 --- a/src/main/java/com/server/capple/domain/answer/mapper/AnswerMapper.java +++ b/src/main/java/com/server/capple/domain/answer/mapper/AnswerMapper.java @@ -2,9 +2,7 @@ import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse.AnswerInfo; -import com.server.capple.domain.answer.dto.AnswerResponse.AnswerList; import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.entity.Question; @@ -22,12 +20,6 @@ public Answer toAnswerEntity(AnswerRequest request, Member member, Question ques .build(); } - public AnswerList toAnswerList(List answerInfoList) { - return AnswerList.builder() - .answerInfos(answerInfoList) - .build(); - } - public AnswerInfo toAnswerInfo(Answer answer, Long memberId, Boolean isReported, Boolean isLiked, Boolean isMine) { return AnswerInfo.builder() .answerId(answer.getId()) @@ -55,9 +47,4 @@ public MemberAnswerInfo toMemberAnswerInfo(Answer answer, int heartCount, Boolea .isLiked(isLiked) .build(); } - - public MemberAnswerList toMemberAnswerList(List memberAnswerInfos) { - return new MemberAnswerList(memberAnswerInfos); - } - } diff --git a/src/main/java/com/server/capple/domain/answer/repository/AnswerRepository.java b/src/main/java/com/server/capple/domain/answer/repository/AnswerRepository.java index b3628363..088f3054 100644 --- a/src/main/java/com/server/capple/domain/answer/repository/AnswerRepository.java +++ b/src/main/java/com/server/capple/domain/answer/repository/AnswerRepository.java @@ -1,32 +1,34 @@ package com.server.capple.domain.answer.repository; +import com.server.capple.domain.answer.dao.AnswerRDBDao.AnswerInfoInterface; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.entity.Question; import io.lettuce.core.dynamic.annotation.Param; -import java.util.List; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.Optional; +import java.util.Set; public interface AnswerRepository extends JpaRepository { Optional findById(Long answerId); - boolean existsByQuestionAndMember(Question question, Member member); + Slice findByIdIn(Set answerIds, Pageable pageable); - @Query("SELECT a FROM Answer a WHERE a.question.id = :questionId ORDER BY a.createdAt DESC") - Optional> findByQuestion( - @Param("questionId") Long questionId, - Pageable pageable); + boolean existsByQuestionAndMember(Question question, Member member); - @Query("SELECT a FROM Answer a WHERE a.question.id = :questionId AND a.content LIKE %:keyword%") - Optional> findByQuestionAndKeyword( - @Param("questionId") Long questionId, - @Param("keyword") String keyword, - Pageable pageable); + @Query("SELECT a AS answer, (r IS NOT NULL) AS isReported " + + "FROM Answer a " + + "LEFT JOIN " + + "Report r ON r.answer = a " + + "WHERE a.question.id = :questionId") + Slice findByQuestion( + @Param("questionId") Long questionId, + Pageable pageable); - @Query("SELECT a FROM Answer a WHERE a.member = :member and a.deletedAt is null ORDER BY a.createdAt DESC") - Optional> findByMember(@Param("member") Member member); + @Query("SELECT a FROM Answer a WHERE a.member = :member and a.deletedAt is null") + Slice findByMember(@Param("member") Member member, Pageable pageable); } diff --git a/src/main/java/com/server/capple/domain/answer/service/AnswerService.java b/src/main/java/com/server/capple/domain/answer/service/AnswerService.java index 8dbd09da..6f71f373 100644 --- a/src/main/java/com/server/capple/domain/answer/service/AnswerService.java +++ b/src/main/java/com/server/capple/domain/answer/service/AnswerService.java @@ -2,10 +2,11 @@ import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse; -import com.server.capple.domain.answer.dto.AnswerResponse.AnswerList; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; +import com.server.capple.domain.answer.dto.AnswerResponse.AnswerInfo; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.member.entity.Member; +import com.server.capple.global.common.SliceResponse; import org.springframework.data.domain.Pageable; @@ -20,9 +21,9 @@ public interface AnswerService { AnswerResponse.AnswerLike toggleAnswerHeart(Member loginMember, Long answerId); - AnswerList getAnswerList(Long memberId, Long questionId, String keyword, Pageable pageable); + SliceResponse getAnswerList(Long memberId, Long questionId, Pageable pageable); - MemberAnswerList getMemberAnswer(Member member); + SliceResponse getMemberAnswer(Member member, Pageable pageable); - MemberAnswerList getMemberHeartAnswer(Member member); + SliceResponse getMemberHeartAnswer(Member member, Pageable pageable); } diff --git a/src/main/java/com/server/capple/domain/answer/service/AnswerServiceImpl.java b/src/main/java/com/server/capple/domain/answer/service/AnswerServiceImpl.java index 1dad6dd0..5efc4eec 100644 --- a/src/main/java/com/server/capple/domain/answer/service/AnswerServiceImpl.java +++ b/src/main/java/com/server/capple/domain/answer/service/AnswerServiceImpl.java @@ -1,10 +1,11 @@ package com.server.capple.domain.answer.service; +import com.server.capple.domain.answer.dao.AnswerRDBDao.AnswerInfoInterface; import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse; +import com.server.capple.domain.answer.dto.AnswerResponse.AnswerInfo; import com.server.capple.domain.answer.dto.AnswerResponse.AnswerLike; -import com.server.capple.domain.answer.dto.AnswerResponse.AnswerList; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.answer.mapper.AnswerMapper; import com.server.capple.domain.answer.repository.AnswerHeartRedisRepository; @@ -14,15 +15,15 @@ import com.server.capple.domain.question.entity.Question; import com.server.capple.domain.question.service.QuestionService; import com.server.capple.domain.report.repository.ReportRepository; +import com.server.capple.global.common.SliceResponse; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.AnswerErrorCode; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -91,45 +92,43 @@ public AnswerLike toggleAnswerHeart(Member loginMember, Long answerId) { } @Override - public AnswerList getAnswerList(Long memberId, Long questionId, String keyword, Pageable pageable) { - - if (keyword == null) { - return answerMapper.toAnswerList( - answerRepository.findByQuestion(questionId, pageable).orElseThrow(() - -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND)) - .stream() - .map(answer -> answerMapper.toAnswerInfo(answer, memberId, reportRepository.existsReportByAnswer(answer), answerHeartRedisRepository.isMemberLikedAnswer(memberId, answer.getId()), answer.getMember().getId().equals(memberId))) - .toList()); - } else { - return answerMapper.toAnswerList( - answerRepository.findByQuestionAndKeyword(questionId, keyword, pageable).orElseThrow(() - -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND)) - .stream() - .map(answer -> answerMapper.toAnswerInfo(answer, memberId, reportRepository.existsReportByAnswer(answer), answerHeartRedisRepository.isMemberLikedAnswer(memberId, answer.getId()), answer.getMember().getId().equals(memberId))) - .toList()); - } - + public SliceResponse getAnswerList(Long memberId, Long questionId, Pageable pageable) { + Slice answerInfoSliceInterface = answerRepository.findByQuestion(questionId, pageable); + return SliceResponse.toSliceResponse(answerInfoSliceInterface, answerInfoSliceInterface.getContent().stream().map( + answerInfoDto -> answerMapper.toAnswerInfo( + answerInfoDto.getAnswer(), + memberId, + answerInfoDto.getIsReported(), + answerHeartRedisRepository.isMemberLikedAnswer(memberId, answerInfoDto.getAnswer().getId()), + answerInfoDto.getAnswer().getMember().getId().equals(memberId) + ) + ).toList()); } // 유저가 작성한 답변 조회 @Override - public MemberAnswerList getMemberAnswer(Member member) { - List answers = answerRepository.findByMember(member).orElse(null); - return answerMapper.toMemberAnswerList( - answers.stream() - .map(answer -> answerMapper.toMemberAnswerInfo(answer, answerHeartRedisRepository.getAnswerHeartsCount(answer.getId()), answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answer.getId()))) - .toList() + public SliceResponse getMemberAnswer(Member member, Pageable pageable) { + Slice answerSlice = answerRepository.findByMember(member, pageable); + return SliceResponse.toSliceResponse( + answerSlice, answerSlice.getContent().stream() + .map(answer -> answerMapper.toMemberAnswerInfo( + answer, + answerHeartRedisRepository.getAnswerHeartsCount(answer.getId()), + answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answer.getId()) + )).toList() ); } // 유저가 좋아한 답변 조회 @Override - public MemberAnswerList getMemberHeartAnswer(Member member) { - return answerMapper.toMemberAnswerList( - answerHeartRedisRepository.getMemberHeartsAnswer(member.getId()) - .stream() - .map(answerId -> answerMapper.toMemberAnswerInfo(findAnswer((answerId)), answerHeartRedisRepository.getAnswerHeartsCount(answerId), answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answerId))) - .toList() + public SliceResponse getMemberHeartAnswer(Member member, Pageable pageable) { + Slice answerSlice = answerRepository.findByIdIn(answerHeartRedisRepository.getMemberHeartsAnswer(member.getId()), pageable); + return SliceResponse.toSliceResponse(answerSlice, answerSlice.getContent().stream() + .map(answer -> answerMapper.toMemberAnswerInfo( + answer, + answerHeartRedisRepository.getAnswerHeartsCount(answer.getId()), + answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answer.getId()) + )).toList() ); } @@ -144,7 +143,7 @@ private void checkPermission(Member loginMember, Answer answer) { @Override public Answer findAnswer(Long answerId) { return answerRepository.findById(answerId).orElseThrow( - () -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND) + () -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND) ); } } diff --git a/src/main/java/com/server/capple/domain/board/controller/BoardController.java b/src/main/java/com/server/capple/domain/board/controller/BoardController.java index 1639085f..101fcdc0 100644 --- a/src/main/java/com/server/capple/domain/board/controller/BoardController.java +++ b/src/main/java/com/server/capple/domain/board/controller/BoardController.java @@ -3,18 +3,21 @@ import com.server.capple.config.security.AuthMember; import com.server.capple.domain.board.dto.BoardRequest; import com.server.capple.domain.board.dto.BoardResponse.BoardId; -import com.server.capple.domain.board.dto.BoardResponse.BoardsGetBoardInfos; +import com.server.capple.domain.board.dto.BoardResponse.BoardInfo; import com.server.capple.domain.board.dto.BoardResponse.ToggleBoardHeart; import com.server.capple.domain.board.entity.BoardType; import com.server.capple.domain.board.service.BoardService; import com.server.capple.domain.member.entity.Member; import com.server.capple.global.common.BaseResponse; +import com.server.capple.global.common.SliceResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; @Tag(name = "게시판 API", description = "게시판 관련 API") @@ -40,13 +43,12 @@ private BaseResponse createBoard(@AuthMember Member member, @ApiResponse(responseCode = "COMMON200", description = "성공"), }) @GetMapping("/redis") - private BaseResponse getBoardsByBoardTypeWithRedis( + private BaseResponse> getBoardsByBoardTypeWithRedis( @AuthMember Member member, - @RequestParam(name = "boardType", required = false) BoardType boardType - // TODO: 페이징 프론트 이슈로 추후 구현 -// @PageableDefault(sort = "created_at", direction = Sort.Direction.DESC) @Parameter(hidden = true) Pageable pageable - ) { - return BaseResponse.onSuccess(boardService.getBoardsByBoardTypeWithRedis(member, boardType)); + @RequestParam(name = "boardType", required = false) BoardType boardType, + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, @RequestParam(defaultValue = "1000", required = false) Integer pageSize + ) { + return BaseResponse.onSuccess(boardService.getBoardsByBoardTypeWithRedis(member, boardType, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } @Operation(summary = "카테고리별 게시글 조회", description = "카테고리별 게시글을 조회합니다.") @@ -54,13 +56,12 @@ private BaseResponse getBoardsByBoardTypeWithRedis( @ApiResponse(responseCode = "COMMON200", description = "성공"), }) @GetMapping() - private BaseResponse getBoardsByBoardType( + private BaseResponse> getBoardsByBoardType( @AuthMember Member member, - @RequestParam(name = "boardType", required = false) BoardType boardType - // TODO: 페이징 프론트 이슈로 추후 구현 -// @PageableDefault(sort = "created_at", direction = Sort.Direction.DESC) @Parameter(hidden = true) Pageable pageable + @RequestParam(name = "boardType", required = false) BoardType boardType, + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, @RequestParam(defaultValue = "1000", required = false) Integer pageSize ) { - return BaseResponse.onSuccess(boardService.getBoardsByBoardType(member, boardType)); + return BaseResponse.onSuccess(boardService.getBoardsByBoardType(member, boardType, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } @Operation(summary = "게시글 검색 API", description = "게시글을 검색합니다. 자유게시판에서만 검색이 가능합니다.") @@ -68,9 +69,11 @@ private BaseResponse getBoardsByBoardType( @ApiResponse(responseCode = "COMMON200", description = "성공"), }) @GetMapping("/search") - private BaseResponse searchBoardsByKeyword(@AuthMember Member member, - @RequestParam(name = "keyword") String keyword) { - return BaseResponse.onSuccess(boardService.searchBoardsByKeyword(member, keyword)); + private BaseResponse> searchBoardsByKeyword( + @AuthMember Member member, @RequestParam(name = "keyword") String keyword, + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, + @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(boardService.searchBoardsByKeyword(member, keyword, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } diff --git a/src/main/java/com/server/capple/domain/board/dto/BoardResponse.java b/src/main/java/com/server/capple/domain/board/dto/BoardResponse.java index 52b78959..dc3f38c5 100644 --- a/src/main/java/com/server/capple/domain/board/dto/BoardResponse.java +++ b/src/main/java/com/server/capple/domain/board/dto/BoardResponse.java @@ -6,7 +6,6 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; -import java.util.List; public class BoardResponse { @@ -15,20 +14,11 @@ public class BoardResponse { public static class BoardId { private Long boardId; } - - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class BoardsGetBoardInfos { - private List boards; - } - @Getter @Builder @AllArgsConstructor @NoArgsConstructor - public static class BoardsGetBoardInfo { + public static class BoardInfo { private Long boardId; private Long writerId; private String content; diff --git a/src/main/java/com/server/capple/domain/board/mapper/BoardMapper.java b/src/main/java/com/server/capple/domain/board/mapper/BoardMapper.java index 1233a419..7ee43ce8 100644 --- a/src/main/java/com/server/capple/domain/board/mapper/BoardMapper.java +++ b/src/main/java/com/server/capple/domain/board/mapper/BoardMapper.java @@ -1,6 +1,6 @@ package com.server.capple.domain.board.mapper; -import com.server.capple.domain.board.dto.BoardResponse.BoardsGetBoardInfo; +import com.server.capple.domain.board.dto.BoardResponse.BoardInfo; import com.server.capple.domain.board.entity.Board; import com.server.capple.domain.board.entity.BoardType; import com.server.capple.domain.member.entity.Member; @@ -21,8 +21,8 @@ public Board toBoard(Member member, BoardType boardType, String content) { } //redis - public BoardsGetBoardInfo toBoardsGetBoardInfo(Board board, Integer boardHeartsCount, Boolean isLiked, Boolean isMine) { - return BoardsGetBoardInfo.builder() + public BoardInfo toBoardInfo(Board board, Integer boardHeartsCount, Boolean isLiked, Boolean isMine) { + return BoardInfo.builder() .boardId(board.getId()) .writerId(board.getWriter().getId()) .content(board.getContent()) @@ -36,8 +36,8 @@ public BoardsGetBoardInfo toBoardsGetBoardInfo(Board board, Integer boardHeartsC } //rdb - public BoardsGetBoardInfo toBoardsGetBoardInfo(Board board, Boolean isLiked, Boolean isMine) { - return BoardsGetBoardInfo.builder() + public BoardInfo toBoardInfo(Board board, Boolean isLiked, Boolean isMine) { + return BoardInfo.builder() .boardId(board.getId()) .writerId(board.getWriter().getId()) .content(board.getContent()) @@ -50,3 +50,4 @@ public BoardsGetBoardInfo toBoardsGetBoardInfo(Board board, Boolean isLiked, Boo .build(); } } + diff --git a/src/main/java/com/server/capple/domain/board/repository/BoardRepository.java b/src/main/java/com/server/capple/domain/board/repository/BoardRepository.java index 7cfe694c..2605eea6 100644 --- a/src/main/java/com/server/capple/domain/board/repository/BoardRepository.java +++ b/src/main/java/com/server/capple/domain/board/repository/BoardRepository.java @@ -4,6 +4,8 @@ import com.server.capple.domain.board.entity.Board; import com.server.capple.domain.board.entity.BoardType; import com.server.capple.domain.member.entity.Member; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -11,21 +13,28 @@ public interface BoardRepository extends JpaRepository { - @Query("SELECT b AS board, " + - "(CASE WHEN bh.member = :member AND bh.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + + @Query("SELECT DISTINCT b AS board, " + + "(CASE WHEN bh.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + "(CASE WHEN b.writer = :member THEN TRUE ELSE FALSE END) AS isMine " + "FROM Board b " + - "LEFT JOIN BoardHeart bh ON b = bh.board " + - "WHERE :boardType IS NULL OR b.boardType = :boardType ORDER BY b.createdAt DESC") - List findBoardInfosByMemberAndBoardType(Member member, BoardType boardType); + "LEFT JOIN BoardHeart bh ON b = bh.board AND bh.member = :member " + + "WHERE :boardType IS NULL OR b.boardType = :boardType") + Slice findBoardInfosByMemberAndBoardType(Member member, BoardType boardType, Pageable pageable); - @Query("SELECT b AS board, " + - "(CASE WHEN bh.member = :member AND bh.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + + @Query("SELECT DISTINCT b AS board, " + + "(CASE WHEN bh.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + "(CASE WHEN b.writer = :member THEN TRUE ELSE FALSE END) AS isMine " + "FROM Board b " + - "LEFT JOIN BoardHeart bh ON b = bh.board " + + "LEFT JOIN BoardHeart bh ON b = bh.board AND bh.member = :member " + "WHERE b.content LIKE %:keyword% AND b.boardType = 0 ORDER BY b.createdAt DESC") //FREETYPE = 0 - List findBoardInfosByMemberAndKeyword(Member member, String keyword); + Slice findBoardInfosByMemberAndKeyword(Member member, String keyword, Pageable pageable); + + + //redis 성능 테스트용 + @Query("SELECT DISTINCT b AS board, " + + "(CASE WHEN b.writer = :member THEN TRUE ELSE FALSE END) AS isMine " + + "FROM Board b " + + "WHERE :boardType IS NULL OR b.boardType = :boardType ORDER BY b.createdAt DESC") + Slice findBoardInfosForRedis(Member member, BoardType boardType, Pageable pageable); - List findBoardsByBoardType(BoardType boardType); } diff --git a/src/main/java/com/server/capple/domain/board/service/BoardService.java b/src/main/java/com/server/capple/domain/board/service/BoardService.java index d4690216..efd5bbeb 100644 --- a/src/main/java/com/server/capple/domain/board/service/BoardService.java +++ b/src/main/java/com/server/capple/domain/board/service/BoardService.java @@ -1,22 +1,25 @@ package com.server.capple.domain.board.service; import com.server.capple.domain.board.dto.BoardResponse.BoardId; -import com.server.capple.domain.board.dto.BoardResponse.BoardsGetBoardInfos; +import com.server.capple.domain.board.dto.BoardResponse.BoardInfo; import com.server.capple.domain.board.dto.BoardResponse.ToggleBoardHeart; import com.server.capple.domain.board.entity.Board; import com.server.capple.domain.board.entity.BoardType; import com.server.capple.domain.member.entity.Member; +import com.server.capple.global.common.SliceResponse; +import org.springframework.data.domain.Pageable; + public interface BoardService { BoardId createBoard(Member member, BoardType boardType, String content); - BoardsGetBoardInfos getBoardsByBoardTypeWithRedis(Member member, BoardType boardType); + SliceResponse getBoardsByBoardTypeWithRedis(Member member, BoardType boardType, Pageable pageable); - BoardsGetBoardInfos getBoardsByBoardType(Member member, BoardType boardType); + SliceResponse getBoardsByBoardType(Member member, BoardType boardType, Pageable pageable); - BoardId deleteBoard(Member member, Long boardId); + SliceResponse searchBoardsByKeyword(Member member, String keyword, Pageable pageable); - BoardsGetBoardInfos searchBoardsByKeyword(Member member, String keyword); + BoardId deleteBoard(Member member, Long boardId); ToggleBoardHeart toggleBoardHeart(Member member, Long boardId); diff --git a/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java b/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java index 9079247d..d63942b5 100644 --- a/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java +++ b/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java @@ -2,7 +2,6 @@ import com.server.capple.domain.board.dao.BoardInfoInterface; import com.server.capple.domain.board.dto.BoardResponse.BoardId; -import com.server.capple.domain.board.dto.BoardResponse.BoardsGetBoardInfos; import com.server.capple.domain.board.dto.BoardResponse.ToggleBoardHeart; import com.server.capple.domain.board.entity.Board; import com.server.capple.domain.board.entity.BoardHeart; @@ -15,13 +14,16 @@ import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.notifiaction.service.NotificationService; +import com.server.capple.global.common.SliceResponse; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.BoardErrorCode; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; +import static com.server.capple.domain.board.dto.BoardResponse.BoardInfo; @Service @RequiredArgsConstructor @@ -29,11 +31,11 @@ public class BoardServiceImpl implements BoardService { private final BoardRepository boardRepository; - private final BoardHeartRedisRepository boardHeartRedisRepository; private final BoardMapper boardMapper; private final BoardHeartRepository boardHeartRepository; private final BoardHeartMapper boardHeartMapper; private final NotificationService notificationService; + private final BoardHeartRedisRepository boardHeartRedisRepository; private final BoardSubscribeMemberService boardSubscribeMemberService; @Override @@ -46,46 +48,48 @@ public BoardId createBoard(Member member, BoardType boardType, String content) { } @Override - public BoardsGetBoardInfos getBoardsByBoardType(Member member, BoardType boardType) { - List boardInfos = boardRepository.findBoardInfosByMemberAndBoardType(member, boardType); - - return new BoardsGetBoardInfos(boardInfos.stream() - .map(boardInfo -> boardMapper.toBoardsGetBoardInfo(boardInfo.getBoard(), boardInfo.getIsLike(), boardInfo.getIsMine())) + public SliceResponse getBoardsByBoardType(Member member, BoardType boardType, Pageable pageable) { + Slice sliceBoardInfos = boardRepository.findBoardInfosByMemberAndBoardType(member, boardType, pageable); + + return SliceResponse.toSliceResponse(sliceBoardInfos, sliceBoardInfos.getContent().stream().map(sliceBoardInfo -> + boardMapper.toBoardInfo( + sliceBoardInfo.getBoard(), + sliceBoardInfo.getIsLike(), + sliceBoardInfo.getIsMine())) .toList() ); } - /* - redis 성능 테스트 용 - */ @Override - public BoardsGetBoardInfos getBoardsByBoardTypeWithRedis(Member member, BoardType boardType) { - List boards; - if (boardType == null) { - boards = boardRepository.findAll(); - } else { - boards = boardRepository.findBoardsByBoardType(boardType); - } - - return new BoardsGetBoardInfos(boards.stream() - .map(board -> { - int heartCount = boardHeartRedisRepository.getBoardHeartsCount(board.getId()); - boolean isLiked = boardHeartRedisRepository.isMemberLikedBoard(member.getId(), board.getId()); - boolean isMine = board.getWriter().getId().equals(member.getId()); - return boardMapper.toBoardsGetBoardInfo(board, heartCount, isLiked, isMine); - }) + public SliceResponse searchBoardsByKeyword(Member member, String keyword, Pageable pageable) { + Slice sliceBoardInfos = boardRepository.findBoardInfosByMemberAndKeyword(member, keyword, pageable); + + return SliceResponse.toSliceResponse(sliceBoardInfos, sliceBoardInfos.getContent().stream().map(sliceBoardInfo -> + boardMapper.toBoardInfo( + sliceBoardInfo.getBoard(), + sliceBoardInfo.getIsLike(), + sliceBoardInfo.getIsMine())) .toList() ); } + /* + redis 성능 테스트 용 + */ @Override - public BoardsGetBoardInfos searchBoardsByKeyword(Member member, String keyword) { - List boardInfos = boardRepository.findBoardInfosByMemberAndKeyword(member, keyword); - - return new BoardsGetBoardInfos(boardInfos.stream() - .map(boardInfo -> boardMapper.toBoardsGetBoardInfo(boardInfo.getBoard(), boardInfo.getIsLike(), boardInfo.getIsMine())) - .toList() - ); + public SliceResponse getBoardsByBoardTypeWithRedis(Member member, BoardType boardType, Pageable pageable) { + Slice sliceBoardInfos = boardRepository.findBoardInfosForRedis(member, boardType, pageable); + + return SliceResponse.toSliceResponse(sliceBoardInfos, sliceBoardInfos.getContent().stream().map(sliceBoardInfo -> { + int heartCount = boardHeartRedisRepository.getBoardHeartsCount(sliceBoardInfo.getBoard().getId()); + boolean isLiked = boardHeartRedisRepository.isMemberLikedBoard(member.getId(), sliceBoardInfo.getBoard().getId()); + return boardMapper.toBoardInfo( + sliceBoardInfo.getBoard(), + heartCount, + isLiked, + sliceBoardInfo.getIsMine()); + }) + .toList()); } @Override diff --git a/src/main/java/com/server/capple/domain/boardComment/controller/BoardCommentController.java b/src/main/java/com/server/capple/domain/boardComment/controller/BoardCommentController.java index d6712dad..134a5f21 100644 --- a/src/main/java/com/server/capple/domain/boardComment/controller/BoardCommentController.java +++ b/src/main/java/com/server/capple/domain/boardComment/controller/BoardCommentController.java @@ -3,16 +3,19 @@ import com.server.capple.config.security.AuthMember; import com.server.capple.domain.boardComment.dto.BoardCommentRequest; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentId; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfos; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfo; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.service.BoardCommentService; import com.server.capple.domain.member.entity.Member; import com.server.capple.global.common.BaseResponse; +import com.server.capple.global.common.SliceResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; @Tag(name = "게시글 댓글 API", description = "게시글 댓글 API입니다.") @@ -52,8 +55,10 @@ public BaseResponse heartBoardComment(@AuthMember Membe @Operation(summary = "게시글 댓글 리스트 조회 API", description = " 게시글 댓글 리스트 조회 API 입니다. pathVariable 으로 boardId를 주세요.") @GetMapping("/{boardId}") - public BaseResponse getBoardCommentInfos(@AuthMember Member member, @PathVariable(value = "boardId") Long boardId) { - return BaseResponse.onSuccess(boardCommentService.getBoardCommentInfos(member,boardId)); + public BaseResponse> getBoardCommentInfos(@AuthMember Member member, @PathVariable(value = "boardId") Long boardId, + @RequestParam(defaultValue = "0", required = false) Integer pageNumber, + @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(boardCommentService.getBoardCommentInfos(member,boardId, PageRequest.of(pageNumber,pageSize, Sort.by(Sort.Direction.DESC, "createdAt")))); } } diff --git a/src/main/java/com/server/capple/domain/boardComment/dto/BoardCommentResponse.java b/src/main/java/com/server/capple/domain/boardComment/dto/BoardCommentResponse.java index 80204e55..94b9c3fb 100644 --- a/src/main/java/com/server/capple/domain/boardComment/dto/BoardCommentResponse.java +++ b/src/main/java/com/server/capple/domain/boardComment/dto/BoardCommentResponse.java @@ -34,10 +34,4 @@ public static class BoardCommentInfo { private Boolean isReport; private LocalDateTime createdAt; } - - @Getter - @AllArgsConstructor - public static class BoardCommentInfos { - private List boardCommentInfos; - } } diff --git a/src/main/java/com/server/capple/domain/boardComment/mapper/BoardCommentMapper.java b/src/main/java/com/server/capple/domain/boardComment/mapper/BoardCommentMapper.java index 51b1e062..76ac9246 100644 --- a/src/main/java/com/server/capple/domain/boardComment/mapper/BoardCommentMapper.java +++ b/src/main/java/com/server/capple/domain/boardComment/mapper/BoardCommentMapper.java @@ -17,7 +17,6 @@ public BoardComment toBoardComment(Member member, Board board, String comment) { .build(); } - //rdb public BoardCommentInfo toBoardCommentInfo(BoardComment comment, Boolean isLiked, Boolean isMine) { return BoardCommentInfo.builder() .boardCommentId(comment.getId()) diff --git a/src/main/java/com/server/capple/domain/boardComment/repository/BoardCommentRepository.java b/src/main/java/com/server/capple/domain/boardComment/repository/BoardCommentRepository.java index cbe3fa13..eeaac7e0 100644 --- a/src/main/java/com/server/capple/domain/boardComment/repository/BoardCommentRepository.java +++ b/src/main/java/com/server/capple/domain/boardComment/repository/BoardCommentRepository.java @@ -3,6 +3,8 @@ import com.server.capple.domain.boardComment.dao.BoardCommentInfoInterface; import com.server.capple.domain.boardComment.entity.BoardComment; import com.server.capple.domain.member.entity.Member; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -10,10 +12,10 @@ public interface BoardCommentRepository extends JpaRepository { @Query("SELECT bc AS boardComment, " + - "(CASE WHEN bch.member = :member AND bch.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + + "(CASE WHEN bch.isLiked = TRUE THEN TRUE ELSE FALSE END) AS isLike, " + "(CASE WHEN bc.writer = :member THEN TRUE ELSE FALSE END) AS isMine " + "FROM BoardComment bc " + - "LEFT JOIN BoardCommentHeart bch ON bc = bch.boardComment " + + "LEFT JOIN BoardCommentHeart bch ON bc = bch.boardComment AND bch.member = :member " + "WHERE bc.board.id = :boardId ORDER BY bc.createdAt DESC") - List findBoardCommentInfosByMemberAndBoardId(Member member, Long boardId); + Slice findBoardCommentInfosByMemberAndBoardId(Member member, Long boardId, Pageable pageable); } diff --git a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentService.java b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentService.java index 09001247..28b21c39 100644 --- a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentService.java +++ b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentService.java @@ -1,17 +1,19 @@ package com.server.capple.domain.boardComment.service; import com.server.capple.domain.boardComment.dto.BoardCommentRequest; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentId; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfos; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfo; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.entity.BoardComment; import com.server.capple.domain.member.entity.Member; +import com.server.capple.global.common.SliceResponse; +import org.springframework.data.domain.Pageable; public interface BoardCommentService { BoardCommentId createBoardComment(Member member, Long boardId, BoardCommentRequest request); BoardCommentId updateBoardComment(Member member, Long commentId,BoardCommentRequest request); BoardCommentId deleteBoardComment(Member member, Long commentId); ToggleBoardCommentHeart toggleBoardCommentHeart(Member member, Long commentId); - BoardCommentInfos getBoardCommentInfos(Member member, Long boardId); + SliceResponse getBoardCommentInfos(Member member, Long boardId, Pageable pageable); BoardComment findBoardComment(Long commentId); } diff --git a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java index 383ef691..8619c39d 100644 --- a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java +++ b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java @@ -5,7 +5,7 @@ import com.server.capple.domain.boardComment.dao.BoardCommentInfoInterface; import com.server.capple.domain.boardComment.dto.BoardCommentRequest; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentId; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfos; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfo; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.entity.BoardComment; import com.server.capple.domain.boardComment.entity.BoardCommentHeart; @@ -16,16 +16,16 @@ import com.server.capple.domain.boardComment.repository.BoardCommentRepository; import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService; import com.server.capple.domain.member.entity.Member; -import com.server.capple.domain.member.service.MemberService; import com.server.capple.domain.notifiaction.service.NotificationService; +import com.server.capple.global.common.SliceResponse; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.CommentErrorCode; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -97,11 +97,15 @@ public ToggleBoardCommentHeart toggleBoardCommentHeart(Member member, Long board @Override - public BoardCommentInfos getBoardCommentInfos(Member member, Long boardId) { - List commentInfos = boardCommentRepository.findBoardCommentInfosByMemberAndBoardId(member, boardId); - - return new BoardCommentInfos(commentInfos.stream().map(commentInfo -> - boardCommentMapper.toBoardCommentInfo(commentInfo.getBoardComment(), commentInfo.getIsLike(), commentInfo.getIsMine())).toList()); + public SliceResponse getBoardCommentInfos(Member member, Long boardId, Pageable pageable) { + Slice sliceBoardCommentInfos = boardCommentRepository.findBoardCommentInfosByMemberAndBoardId(member, boardId, pageable); + return SliceResponse.toSliceResponse(sliceBoardCommentInfos, sliceBoardCommentInfos.getContent().stream().map(sliceBoardCommentInfo -> + boardCommentMapper.toBoardCommentInfo( + sliceBoardCommentInfo.getBoardComment(), + sliceBoardCommentInfo.getIsLike(), + sliceBoardCommentInfo.getIsMine())) + .toList() + ); } private void checkPermission(Member member, BoardComment boardComment) { diff --git a/src/main/java/com/server/capple/domain/question/controller/QuestionController.java b/src/main/java/com/server/capple/domain/question/controller/QuestionController.java index 097ddcda..f4beb9bb 100644 --- a/src/main/java/com/server/capple/domain/question/controller/QuestionController.java +++ b/src/main/java/com/server/capple/domain/question/controller/QuestionController.java @@ -3,15 +3,18 @@ import com.server.capple.config.security.AuthMember; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.dto.response.QuestionResponse; -import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfos; +import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfo; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionSummary; import com.server.capple.domain.question.service.QuestionService; import com.server.capple.global.common.BaseResponse; +import com.server.capple.global.common.SliceResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; @Tag(name = "질문 API", description = "질문 관련 API") @@ -24,7 +27,7 @@ public class QuestionController { @Operation(summary = "메인 질문 조회 API", description = "메인 질문을 조회합니다.") @ApiResponses(value = { - @ApiResponse(responseCode = "COMMON200", description = "성공"), + @ApiResponse(responseCode = "COMMON200", description = "성공"), }) @GetMapping("/main") private BaseResponse getMainQuestion(@AuthMember Member member) { @@ -33,15 +36,15 @@ private BaseResponse getMainQuestion(@AuthMember Member member) @Operation(summary = "모든 질문 조회 API", description = "모든 질문을 조회합니다.") @ApiResponses(value = { - @ApiResponse(responseCode = "COMMON200", description = "성공"), + @ApiResponse(responseCode = "COMMON200", description = "성공"), }) @GetMapping - private BaseResponse getQuestions(@AuthMember Member member) { - return BaseResponse.onSuccess(questionService.getQuestions(member)); + private BaseResponse> getQuestions(@AuthMember Member member, @RequestParam(defaultValue = "0", required = false) Integer pageNumber, @RequestParam(defaultValue = "1000", required = false) Integer pageSize) { + return BaseResponse.onSuccess(questionService.getQuestions(member, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "livedAt")))); } @Operation(summary = "질문 좋아요/취소 API", description = " 질문 좋아요/취소 API 입니다." + - "pathvariable 으로 questionId를 주세요.") + "pathvariable 으로 questionId를 주세요.") @PostMapping("/{questionId}/heart") public BaseResponse toggleBoardHeart(@AuthMember Member member, @PathVariable(value = "questionId") Long questionId) { return BaseResponse.onSuccess(questionService.toggleQuestionHeart(member, questionId)); diff --git a/src/main/java/com/server/capple/domain/question/dto/response/QuestionResponse.java b/src/main/java/com/server/capple/domain/question/dto/response/QuestionResponse.java index d792f632..9d1c342f 100644 --- a/src/main/java/com/server/capple/domain/question/dto/response/QuestionResponse.java +++ b/src/main/java/com/server/capple/domain/question/dto/response/QuestionResponse.java @@ -8,7 +8,6 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; -import java.util.List; public class QuestionResponse { @@ -46,13 +45,6 @@ public static class QuestionId { private Long questionId; } - @Getter - @AllArgsConstructor - @Builder - public static class QuestionInfos { - private List questionInfos; - } - @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/server/capple/domain/question/mapper/QuestionMapper.java b/src/main/java/com/server/capple/domain/question/mapper/QuestionMapper.java index ee9e4360..6b2090d6 100644 --- a/src/main/java/com/server/capple/domain/question/mapper/QuestionMapper.java +++ b/src/main/java/com/server/capple/domain/question/mapper/QuestionMapper.java @@ -2,51 +2,42 @@ import com.server.capple.domain.question.dto.request.QuestionRequest.QuestionCreate; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfo; -import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfos; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionSummary; import com.server.capple.domain.question.entity.Question; import org.springframework.stereotype.Component; -import java.util.List; - @Component public class QuestionMapper { public Question toQuestion(QuestionCreate request) { return Question.builder() - .questionStatus(request.getQuestionStatus()) - .content(request.getContent()) + .questionStatus(request.getQuestionStatus()) + .content(request.getContent()) // .commentCount(0) - .build(); + .build(); } public QuestionSummary toQuestionSummary(Question question, boolean isAnswered/*, Integer likeCount*/) { return QuestionSummary.builder() - .questionId(question.getId()) - .questionStatus(question.getQuestionStatus()) - .content(question.getContent()) - .isAnswered(isAnswered) + .questionId(question.getId()) + .questionStatus(question.getQuestionStatus()) + .content(question.getContent()) + .isAnswered(isAnswered) // .likeCount(likeCount) // .commentCount(question.getCommentCount()) - .build(); + .build(); } public QuestionInfo toQuestionInfo(Question question, boolean isAnswered/*, Integer likeCount*/) { return QuestionInfo.builder() - .questionId(question.getId()) - .questionStatus(question.getQuestionStatus()) - .livedAt(question.getLivedAt()) - .content(question.getContent()) + .questionId(question.getId()) + .questionStatus(question.getQuestionStatus()) + .livedAt(question.getLivedAt()) + .content(question.getContent()) // .likeCount(likeCount) // .commentCount(question.getCommentCount()) - .isAnswered(isAnswered) - .build(); - } - - public QuestionInfos toQuestionInfos(List questionInfoList) { - return QuestionInfos.builder() - .questionInfos(questionInfoList) - .build(); + .isAnswered(isAnswered) + .build(); } } diff --git a/src/main/java/com/server/capple/domain/question/repository/QuestionRepository.java b/src/main/java/com/server/capple/domain/question/repository/QuestionRepository.java index ffe97da0..419e7d7f 100644 --- a/src/main/java/com/server/capple/domain/question/repository/QuestionRepository.java +++ b/src/main/java/com/server/capple/domain/question/repository/QuestionRepository.java @@ -3,17 +3,12 @@ import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.dao.QuestionInfoInterface; import com.server.capple.domain.question.entity.Question; -import com.server.capple.domain.question.entity.QuestionStatus; import io.lettuce.core.dynamic.annotation.Param; - -import java.util.List; - -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import java.util.Objects; import java.util.Optional; public interface QuestionRepository extends JpaRepository { @@ -27,10 +22,9 @@ public interface QuestionRepository extends JpaRepository { @Query("SELECT q AS question, (a IS NOT NULL) AS isAnsweredByMember " + - "FROM Question q LEFT JOIN Answer a ON q = a.question AND a.deletedAt is NULL AND a.member = :member " + - "WHERE q.questionStatus = 'OLD' OR q.questionStatus = 'LIVE' " + - "ORDER BY q.livedAt DESC") - List findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(@Param("member") Member member); + "FROM Question q LEFT JOIN Answer a ON q = a.question AND a.deletedAt is NULL AND a.member = :member " + + "WHERE q.questionStatus = 'OLD' OR q.questionStatus = 'LIVE'") + Slice findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(@Param("member") Member member, Pageable pageable); } diff --git a/src/main/java/com/server/capple/domain/question/service/QuestionService.java b/src/main/java/com/server/capple/domain/question/service/QuestionService.java index eaa8580c..98ae0de8 100644 --- a/src/main/java/com/server/capple/domain/question/service/QuestionService.java +++ b/src/main/java/com/server/capple/domain/question/service/QuestionService.java @@ -2,15 +2,17 @@ import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.dto.response.QuestionResponse; -import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfos; +import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfo; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionSummary; import com.server.capple.domain.question.entity.Question; +import com.server.capple.global.common.SliceResponse; +import org.springframework.data.domain.Pageable; public interface QuestionService { Question findQuestion(Long questionId); QuestionSummary getMainQuestion(Member member); - QuestionInfos getQuestions(Member member); + SliceResponse getQuestions(Member member, Pageable pageable); QuestionResponse.QuestionToggleHeart toggleQuestionHeart(Member member, Long questionId); } diff --git a/src/main/java/com/server/capple/domain/question/service/QuestionServiceImpl.java b/src/main/java/com/server/capple/domain/question/service/QuestionServiceImpl.java index 3a027e4e..8d680b73 100644 --- a/src/main/java/com/server/capple/domain/question/service/QuestionServiceImpl.java +++ b/src/main/java/com/server/capple/domain/question/service/QuestionServiceImpl.java @@ -1,24 +1,24 @@ package com.server.capple.domain.question.service; import com.server.capple.domain.answer.repository.AnswerRepository; -import com.server.capple.domain.answerComment.repository.AnswerCommentHeartRedisRepository; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.question.dao.QuestionInfoInterface; import com.server.capple.domain.question.dto.response.QuestionResponse; -import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfos; +import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionInfo; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionSummary; import com.server.capple.domain.question.entity.Question; import com.server.capple.domain.question.mapper.QuestionMapper; import com.server.capple.domain.question.repository.QuestionHeartRedisRepository; import com.server.capple.domain.question.repository.QuestionRepository; +import com.server.capple.global.common.SliceResponse; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.QuestionErrorCode; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -27,34 +27,29 @@ public class QuestionServiceImpl implements QuestionService { private final AnswerRepository answerRepository; private final QuestionMapper questionMapper; private final QuestionHeartRedisRepository questionHeartRepository; - private final AnswerCommentHeartRedisRepository answerCommentHeartRepository; @Override public Question findQuestion(Long questionId) { return questionRepository.findById(questionId).orElseThrow(() - -> new RestApiException(QuestionErrorCode.QUESTION_NOT_FOUND)); + -> new RestApiException(QuestionErrorCode.QUESTION_NOT_FOUND)); } @Override public QuestionSummary getMainQuestion(Member member) { Question mainQuestion = questionRepository.findByQuestionStatusIsLiveAndOldOrderByLivedAt() - .orElseThrow(() -> new RestApiException(QuestionErrorCode.QUESTION_NOT_FOUND)); + .orElseThrow(() -> new RestApiException(QuestionErrorCode.QUESTION_NOT_FOUND)); boolean isAnswered = answerRepository.existsByQuestionAndMember(mainQuestion, member); - return questionMapper.toQuestionSummary(mainQuestion, isAnswered/*, questionHeartRepository.getQuestionHeartsCount(mainQuestion.getId())*/); + return questionMapper.toQuestionSummary(mainQuestion, isAnswered); } @Override - public QuestionInfos getQuestions(Member member) { - List questions = questionRepository.findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(member); - - return questionMapper.toQuestionInfos(questions.stream() - .map(questionInfo -> - questionMapper.toQuestionInfo(questionInfo.getQuestion(), - questionInfo.getIsAnsweredByMember()/*, - questionHeartRepository.getQuestionHeartsCount(questionInfo.getQuestion().getId())*/) - ).toList()); + public SliceResponse getQuestions(Member member, Pageable pageable) { + Slice questionSlice = questionRepository.findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(member, pageable); + return SliceResponse.toSliceResponse(questionSlice, questionSlice.getContent().stream() + .map(questionInfoInterface -> questionMapper.toQuestionInfo(questionInfoInterface.getQuestion(), questionInfoInterface.getIsAnsweredByMember()) + ).toList()); } @Override diff --git a/src/main/java/com/server/capple/global/common/SliceResponse.java b/src/main/java/com/server/capple/global/common/SliceResponse.java index 9c92aef4..979851cf 100644 --- a/src/main/java/com/server/capple/global/common/SliceResponse.java +++ b/src/main/java/com/server/capple/global/common/SliceResponse.java @@ -1,5 +1,6 @@ package com.server.capple.global.common; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.domain.Slice; @@ -15,6 +16,7 @@ public class SliceResponse { int numberOfElements; boolean hasPrevious; boolean hasNext; + public SliceResponse(Slice sliceObject) { number = sliceObject.getNumber(); size = sliceObject.getSize(); @@ -23,4 +25,29 @@ public SliceResponse(Slice sliceObject) { hasPrevious = sliceObject.hasPrevious(); hasNext = sliceObject.hasNext(); } + + @Builder + public SliceResponse(int number, int size, List content, int numberOfElements, boolean hasPrevious, boolean hasNext) { + this.number = number; + this.size = size; + this.content = content; + this.numberOfElements = numberOfElements; + this.hasPrevious = hasPrevious; + this.hasNext = hasNext; + } + + /** + * P : 데이터베이스에서 반환 받은 데이터 타입
+ * R : 사용자게에 반환할 데이터 타입 + */ + public static SliceResponse toSliceResponse(Slice

sliceObject, List content) { + return SliceResponse.builder() + .number(sliceObject.getNumber()) + .size(sliceObject.getSize()) + .content(content) + .numberOfElements(sliceObject.getNumberOfElements()) + .hasPrevious(sliceObject.hasPrevious()) + .hasNext(sliceObject.hasNext()) + .build(); + } } diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..c975b048 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + INFO + ACCEPT + DENY + + + utf8 + ${INFO_LOG_PATTERN} + + + + + ERROR + ACCEPT + DENY + + + utf8 + ${ERROR_LOG_PATTERN} + + + + + WARN + ACCEPT + DENY + + + utf8 + ${WARN_LOG_PATTERN} + + + + + DEBUG + ACCEPT + DENY + + + utf8 + ${DEBUG_LOG_PATTERN} + + + + + TRACE + ACCEPT + DENY + + + utf8 + ${TRACE_LOG_PATTERN} + + + + + ./logs/qapple-info.log + + INFO + ACCEPT + DENY + + + utf8 + ${INFO_LOG_PATTERN} + + + ${INFO_LOG_FILE_NAME_PATTERN} + ${MAX_HISTORY} + ${MAX_FILE_SIZE} + ${TOTAL_SIZE} + + + + ./logs/qapple-error.log + + ERROR + ACCEPT + DENY + + + utf8 + ${ERROR_LOG_PATTERN} + + + ${ERROR_LOG_FILE_NAME_PATTERN} + ${MAX_HISTORY} + ${MAX_FILE_SIZE} + ${TOTAL_SIZE} + + + + ./logs/qapple-warn.log + + WARN + ACCEPT + DENY + + + utf8 + ${WARN_LOG_PATTERN} + + + ${WARN_LOG_FILE_NAME_PATTERN} + ${MAX_HISTORY} + ${MAX_FILE_SIZE} + ${TOTAL_SIZE} + + + + ./logs/qapple-debug.log + + DEBUG + ACCEPT + DENY + + + utf8 + ${DEBUG_LOG_PATTERN} + + + ${DEBUG_LOG_FILE_NAME_PATTERN} + ${MAX_HISTORY} + ${MAX_FILE_SIZE} + ${TOTAL_SIZE} + + + + ./logs/qapple-trace.log + + TRACE + ACCEPT + DENY + + + utf8 + ${TRACE_LOG_PATTERN} + + + ${TRACE_LOG_FILE_NAME_PATTERN} + ${MAX_HISTORY} + ${MAX_FILE_SIZE} + ${TOTAL_SIZE} + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/server/capple/domain/answer/controller/AnswerControllerTest.java b/src/test/java/com/server/capple/domain/answer/controller/AnswerControllerTest.java index 347f2f74..2124b163 100644 --- a/src/test/java/com/server/capple/domain/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/server/capple/domain/answer/controller/AnswerControllerTest.java @@ -2,14 +2,17 @@ import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.service.AnswerService; import com.server.capple.domain.member.entity.Member; +import com.server.capple.global.common.SliceResponse; import com.server.capple.support.ControllerTestConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageRequest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.ResultActions; @@ -135,8 +138,8 @@ public void toggleAnswerHeartTest() throws Exception { public void getMyPageMemberAnswerTest() throws Exception { //given final String url = "/answers"; - AnswerResponse.MemberAnswerList response = getMemberAnswerList(); - given(answerService.getMemberAnswer(any(Member.class))).willReturn(response); + SliceResponse response = getSliceMemberAnswerInfos(); + given(answerService.getMemberAnswer(any(Member.class), any(PageRequest.class))).willReturn(response); //when ResultActions resultActions = mockMvc.perform(get(url).accept(MediaType.APPLICATION_JSON) @@ -150,7 +153,7 @@ public void getMyPageMemberAnswerTest() throws Exception { .andExpect(jsonPath("$.code").value("COMMON200")) .andExpect(jsonPath("$.message").value("요청에 성공하였습니다.")) // .andExpect(jsonPath("$.result.memberAnswerInfos[0].nickname").value("루시")) - .andExpect(jsonPath("$.result.memberAnswerInfos[0].content").value("나는 무자비한 사람이 좋아")); + .andExpect(jsonPath("$.result.content[0].content").value("나는 무자비한 사람이 좋아")); } @Test @@ -158,8 +161,8 @@ public void getMyPageMemberAnswerTest() throws Exception { public void getMyPageMemberHeartAnswerTest() throws Exception { //given final String url = "/answers/heart"; - AnswerResponse.MemberAnswerList response = getMemberAnswerList(); - given(answerService.getMemberHeartAnswer(any(Member.class))).willReturn(response); + SliceResponse response = getSliceMemberAnswerInfos(); + given(answerService.getMemberHeartAnswer(any(Member.class), any(PageRequest.class))).willReturn(response); //when ResultActions resultActions = mockMvc.perform(get(url).accept(MediaType.APPLICATION_JSON) @@ -172,7 +175,7 @@ public void getMyPageMemberHeartAnswerTest() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value("COMMON200")) .andExpect(jsonPath("$.message").value("요청에 성공하였습니다.")) - .andExpect(jsonPath("$.result.memberAnswerInfos[0].heartCount").value(1)) - .andExpect(jsonPath("$.result.memberAnswerInfos[0].answerId").value(1)); + .andExpect(jsonPath("$.result.content[0].heartCount").value(1)) + .andExpect(jsonPath("$.result.content[0].answerId").value(1)); } } \ No newline at end of file diff --git a/src/test/java/com/server/capple/domain/answer/service/AnswerServiceTest.java b/src/test/java/com/server/capple/domain/answer/service/AnswerServiceTest.java index 564c01d5..5ee3dc60 100644 --- a/src/test/java/com/server/capple/domain/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/server/capple/domain/answer/service/AnswerServiceTest.java @@ -2,14 +2,18 @@ import com.server.capple.domain.answer.dto.AnswerRequest; import com.server.capple.domain.answer.dto.AnswerResponse; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.tag.service.TagService; +import com.server.capple.global.common.SliceResponse; import com.server.capple.global.exception.RestApiException; import com.server.capple.support.ServiceTestConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -121,9 +125,9 @@ public void toggleAnswerHeartTest() { @Transactional public void getMemberAnswerTest() { //when - AnswerResponse.MemberAnswerList memberAnswer = answerService.getMemberAnswer(member); + SliceResponse memberAnswer = answerService.getMemberAnswer(member, PageRequest.of(0, 1000, Sort.by(Sort.Direction.DESC, "createdAt"))); //then - assertEquals(memberAnswer.getMemberAnswerInfos().get(0).getContent(), "나는 무자비한 사람이 좋아"); + assertEquals(memberAnswer.getContent().get(0).getContent(), "나는 무자비한 사람이 좋아"); } @Test @@ -134,9 +138,9 @@ public void getMemberHeartAnswerTest() { answerService.toggleAnswerHeart(member, answer.getId()); //when - AnswerResponse.MemberAnswerList memberHeartAnswer = answerService.getMemberHeartAnswer(member); + SliceResponse memberHeartAnswer = answerService.getMemberHeartAnswer(member, PageRequest.of(0, 1000, Sort.by(Sort.Direction.DESC, "createdAt"))); //then - assertEquals(memberHeartAnswer.getMemberAnswerInfos().get(0).getHeartCount(), 1); + assertEquals(memberHeartAnswer.getContent().get(0).getHeartCount(), 1); } } diff --git a/src/test/java/com/server/capple/domain/boardComment/controller/BoardCommentControllerTest.java b/src/test/java/com/server/capple/domain/boardComment/controller/BoardCommentControllerTest.java index 715b527c..e7226701 100644 --- a/src/test/java/com/server/capple/domain/boardComment/controller/BoardCommentControllerTest.java +++ b/src/test/java/com/server/capple/domain/boardComment/controller/BoardCommentControllerTest.java @@ -3,12 +3,15 @@ import com.server.capple.domain.boardComment.dto.BoardCommentRequest; import com.server.capple.domain.boardComment.service.BoardCommentService; import com.server.capple.domain.member.entity.Member; +import com.server.capple.global.common.SliceResponse; import com.server.capple.support.ControllerTestConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.test.web.servlet.ResultActions; import static com.server.capple.domain.boardComment.dto.BoardCommentResponse.*; @@ -34,7 +37,6 @@ public class BoardCommentControllerTest extends ControllerTestConfig { public void createBoardCommentTest() throws Exception { //given final String url = "/board-comments/board/{boardId}"; - BoardCommentRequest request = getBoardCommentRequest(); BoardCommentId response = new BoardCommentId(1L); @@ -60,7 +62,6 @@ public void createBoardCommentTest() throws Exception { public void updateBoardCommentTest() throws Exception { //given final String url = "/board-comments/{commentId}"; - BoardCommentRequest request = getBoardCommentRequest(); BoardCommentId response = new BoardCommentId(1L); @@ -133,9 +134,9 @@ public void heartBoardCommentTest() throws Exception { public void getBoardCommentInfosTest() throws Exception { //given final String url = "/board-comments/{boardId}"; - BoardCommentInfos response = getBoardCommentInfos(); + SliceResponse response = getSliceBoardCommentInfos(); - doReturn(response).when(boardCommentService).getBoardCommentInfos(any(Member.class), any(Long.class)); + doReturn(response).when(boardCommentService).getBoardCommentInfos(any(Member.class), any(Long.class), any(PageRequest.class)); //when ResultActions resultActions = this.mockMvc.perform(get(url, 1L) @@ -148,10 +149,12 @@ public void getBoardCommentInfosTest() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value("COMMON200")) .andExpect(jsonPath("$.message").value("요청에 성공하였습니다.")) - .andExpect(jsonPath("$.result.boardCommentInfos[0].boardCommentId").value(1L)) -// .andExpect(jsonPath("$.result.boardCommentInfos[0].writer").value("루시")) - .andExpect(jsonPath("$.result.boardCommentInfos[0].content").value("댓글")) - .andExpect(jsonPath("$.result.boardCommentInfos[0].heartCount").value(2L)) - .andExpect(jsonPath("$.result.boardCommentInfos[0].isLiked").value(true)); + .andExpect(jsonPath("$.result.number").value(0)) + .andExpect(jsonPath("$.result.size").value(10)) + .andExpect(jsonPath("$.result.numberOfElements").value(1)) + .andExpect(jsonPath("$.result.content[0].boardCommentId").value(1L)) + .andExpect(jsonPath("$.result.content[0].content").value("댓글")) + .andExpect(jsonPath("$.result.content[0].heartCount").value(2L)) + .andExpect(jsonPath("$.result.content[0].isLiked").value(true)); } } diff --git a/src/test/java/com/server/capple/domain/boardComment/service/BoardCommentServiceTest.java b/src/test/java/com/server/capple/domain/boardComment/service/BoardCommentServiceTest.java index 51638d54..99944885 100644 --- a/src/test/java/com/server/capple/domain/boardComment/service/BoardCommentServiceTest.java +++ b/src/test/java/com/server/capple/domain/boardComment/service/BoardCommentServiceTest.java @@ -1,14 +1,19 @@ package com.server.capple.domain.boardComment.service; +import com.server.capple.domain.board.dto.BoardResponse; import com.server.capple.domain.boardComment.dto.BoardCommentRequest; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfos; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse; +import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfo; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.ToggleBoardCommentHeart; import com.server.capple.domain.boardComment.entity.BoardComment; +import com.server.capple.global.common.SliceResponse; import com.server.capple.support.ServiceTestConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -107,14 +112,19 @@ public void heartBoardCommentTest() { @DisplayName("게시판 댓글 리스트 조회 테스트") @Transactional public void getBoardCommentsTest() { + //given + PageRequest pageRequest = PageRequest.of(0,10, Sort.by(Sort.Direction.DESC,"createdAt")); //when - BoardCommentInfos response = boardCommentService.getBoardCommentInfos(member, board.getId()); + SliceResponse response = boardCommentService.getBoardCommentInfos(member, board.getId(), pageRequest); //then - assertEquals(member.getId(), response.getBoardCommentInfos().get(0).getWriterId()); - assertEquals("게시글 댓글", response.getBoardCommentInfos().get(0).getContent()); - assertEquals(0, response.getBoardCommentInfos().get(0).getHeartCount()); - assertEquals(false, response.getBoardCommentInfos().get(0).getIsLiked()); - assertEquals(true, response.getBoardCommentInfos().get(0).getIsMine()); + assertEquals(member.getId(), response.getContent().get(0).getWriterId()); + assertEquals("게시글 댓글", response.getContent().get(0).getContent()); + assertEquals(0, response.getContent().get(0).getHeartCount()); + assertEquals(false, response.getContent().get(0).getIsLiked()); + assertEquals(true, response.getContent().get(0).getIsMine()); + assertEquals(0, response.getNumber()); + assertEquals(10, response.getSize()); + assertEquals(1, response.getNumberOfElements()); } } \ No newline at end of file diff --git a/src/test/java/com/server/capple/domain/question/service/QuestionServiceTest.java b/src/test/java/com/server/capple/domain/question/service/QuestionServiceTest.java index 03bcbcc3..f995b583 100644 --- a/src/test/java/com/server/capple/domain/question/service/QuestionServiceTest.java +++ b/src/test/java/com/server/capple/domain/question/service/QuestionServiceTest.java @@ -8,6 +8,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -54,7 +56,7 @@ public void closeLiveQuestionTest() { @Transactional public void getQuestionsTest() { //given & when - List questionInfos = questionService.getQuestions(member).getQuestionInfos(); + List questionInfos = questionService.getQuestions(member, PageRequest.of(0, 1000, Sort.by(Sort.Direction.DESC, "livedAt"))).getContent(); //then assertEquals(questionInfos.size(), 2); diff --git a/src/test/java/com/server/capple/support/ControllerTestConfig.java b/src/test/java/com/server/capple/support/ControllerTestConfig.java index d7945268..d230d1c4 100644 --- a/src/test/java/com/server/capple/support/ControllerTestConfig.java +++ b/src/test/java/com/server/capple/support/ControllerTestConfig.java @@ -5,18 +5,18 @@ import com.server.capple.config.security.auth.service.JpaUserDetailService; import com.server.capple.config.security.jwt.service.JwtService; import com.server.capple.domain.answer.dto.AnswerRequest; -import com.server.capple.domain.answer.dto.AnswerResponse; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; +import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerInfo; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.answerComment.dto.AnswerCommentRequest; -import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.*; +import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.AnswerCommentInfo; +import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.AnswerCommentInfos; import com.server.capple.domain.boardComment.dto.BoardCommentRequest; import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfo; -import com.server.capple.domain.boardComment.dto.BoardCommentResponse.BoardCommentInfos; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.member.entity.Role; import com.server.capple.domain.question.entity.Question; import com.server.capple.domain.question.entity.QuestionStatus; +import com.server.capple.global.common.SliceResponse; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -60,14 +60,14 @@ public void setUp() { protected Member createMember() { return Member.builder() - .id(1L) - .role(Role.ROLE_ACADEMIER) - .sub("2384973284") - .email("tnals2384@gmail.com") - .profileImage("https://owori.s3.ap-northeast-2.amazonaws.com/story/capple_default_image_10635d7a-5f8c-4af2-b062-9a9420634eb3.png") - .email("ksm@naver.com") - .nickname("루시") - .build(); + .id(1L) + .role(Role.ROLE_ACADEMIER) + .sub("2384973284") + .email("tnals2384@gmail.com") + .profileImage("https://owori.s3.ap-northeast-2.amazonaws.com/story/capple_default_image_10635d7a-5f8c-4af2-b062-9a9420634eb3.png") + .email("ksm@naver.com") + .nickname("루시") + .build(); } protected String createJwt(Member member) { @@ -76,75 +76,89 @@ protected String createJwt(Member member) { protected Question createQuestion() { return Question.builder() - .id(1L) - .content("아카데미 러너 중 가장 마음에 드는 유형이 있나요?") - .questionStatus(QuestionStatus.LIVE) - .build(); + .id(1L) + .content("아카데미 러너 중 가장 마음에 드는 유형이 있나요?") + .questionStatus(QuestionStatus.LIVE) + .build(); } protected Answer createAnswer() { return Answer.builder() - .id(1L) - .content("나는 무자비한 사람이 좋아") - .question(question) - .member(member) - .build(); + .id(1L) + .content("나는 무자비한 사람이 좋아") + .question(question) + .member(member) + .build(); } protected AnswerRequest getAnswerRequest() { return AnswerRequest.builder() - .answer("나는 와플을 좋아하는 사람이 좋아") - .build(); + .answer("나는 와플을 좋아하는 사람이 좋아") + .build(); } - protected MemberAnswerList getMemberAnswerList () { - List memberAnswerInfos = List.of(AnswerResponse.MemberAnswerInfo.builder() - .questionId(answer.getQuestion().getId()) - .answerId(answer.getId()) - .writerId(member.getId()) - .profileImage(answer.getMember().getProfileImage()) - .content(answer.getContent()) - .heartCount(1) - .build()); - - return new MemberAnswerList(memberAnswerInfos); + protected SliceResponse getSliceMemberAnswerInfos() { + List memberAnswerInfos = List.of(MemberAnswerInfo.builder() + .questionId(answer.getQuestion().getId()) + .answerId(answer.getId()) + .writerId(member.getId()) + .profileImage(answer.getMember().getProfileImage()) + .content(answer.getContent()) + .heartCount(1) + .build()); + + return SliceResponse.builder() + .number(0) + .size(1000) + .content(memberAnswerInfos) + .numberOfElements(1) + .hasPrevious(FALSE) + .hasNext(FALSE) + .build(); } protected BoardCommentRequest getBoardCommentRequest() { return new BoardCommentRequest("게시글 댓글"); } - protected BoardCommentInfos getBoardCommentInfos() { + protected SliceResponse getSliceBoardCommentInfos() { List commentInfos = - List.of(BoardCommentInfo.builder() - .boardCommentId(1L) - .writerId(member.getId()) - .content("댓글") - .createdAt(LocalDateTime.now()) - .heartCount(2) - .isLiked(TRUE) - .isReport(FALSE) - .build()); - - return new BoardCommentInfos(commentInfos); + List.of(BoardCommentInfo.builder() + .boardCommentId(1L) + .writerId(member.getId()) + .content("댓글") + .createdAt(LocalDateTime.now()) + .heartCount(2) + .isLiked(TRUE) + .isReport(FALSE) + .build()); + + + return SliceResponse.builder() + .number(0) + .size(10) + .content(commentInfos) + .numberOfElements(1) + .hasPrevious(false) + .hasNext(true) + .build(); } protected AnswerCommentRequest getAnswerCommentRequest() { return AnswerCommentRequest.builder() - .answerComment("댓글이 잘 달렸으면 좋겠어 . .") - .build(); + .answerComment("댓글이 잘 달렸으면 좋겠어 . .") + .build(); } - protected AnswerCommentInfos getAnswerCommentInfos () { + protected AnswerCommentInfos getAnswerCommentInfos() { List answerCommentInfos = List.of(AnswerCommentInfo.builder() - .answerCommentId(1L) - .writerId(member.getId()) - .content("댓글 1") - .createdAt(LocalDateTime.of(2022, 11, 1, 12, 02)) - .heartCount(3L) - .build()); + .answerCommentId(1L) + .writerId(member.getId()) + .content("댓글 1") + .createdAt(LocalDateTime.of(2022, 11, 1, 12, 02)) + .heartCount(3L) + .build()); return new AnswerCommentInfos(answerCommentInfos); } - } diff --git a/src/test/java/com/server/capple/support/ServiceTestConfig.java b/src/test/java/com/server/capple/support/ServiceTestConfig.java index 92ead598..b9a0064b 100644 --- a/src/test/java/com/server/capple/support/ServiceTestConfig.java +++ b/src/test/java/com/server/capple/support/ServiceTestConfig.java @@ -136,6 +136,7 @@ protected Board createBoard() { .isReport(FALSE) .build()); } + protected BoardComment createBoardComment() { return boardCommentRepository.save( BoardComment.builder() @@ -151,8 +152,6 @@ protected BoardCommentRequest getBoardCommentRequest() { return new BoardCommentRequest("게시글 댓글"); } - - protected AnswerCommentRequest getAnswerCommentRequest() { return AnswerCommentRequest.builder() .answerComment("댓글이 잘 달렸으면 좋겠어 . .")