From 7d30575cde78c18da14ae0d01abfc1da115786f2 Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:14:49 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20#155=20SliceResponse=20=EB=B9=8C?= =?UTF-8?q?=EB=8D=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/capple/global/common/SliceResponse.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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..97050fec 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,14 @@ 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; + } } From 939d3c546ed340eb633f5ec8bc4bc374c3a5c800 Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:20:08 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20#159=20=EC=A7=88=EB=AC=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20pagincation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/QuestionController.java | 15 +++--- .../dto/response/QuestionResponse.java | 8 --- .../question/mapper/QuestionMapper.java | 49 +++++++++++-------- .../repository/QuestionRepository.java | 15 ++---- .../question/service/QuestionService.java | 6 ++- .../question/service/QuestionServiceImpl.java | 26 +++------- .../question/service/QuestionServiceTest.java | 4 +- 7 files changed, 57 insertions(+), 66 deletions(-) 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..550dd2ad 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, "createdAt")))); } @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..7b53fc40 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 @@ -1,52 +1,59 @@ package com.server.capple.domain.question.mapper; +import com.server.capple.domain.question.dao.QuestionInfoInterface; 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 com.server.capple.global.common.SliceResponse; +import org.springframework.data.domain.Slice; 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(); + .isAnswered(isAnswered) + .build(); } - public QuestionInfos toQuestionInfos(List questionInfoList) { - return QuestionInfos.builder() - .questionInfos(questionInfoList) - .build(); + public SliceResponse toSliceQuestionInfo(Slice questionSlice) { + return SliceResponse.builder() + .number(questionSlice.getNumber()) + .size(questionSlice.getSize()) + .content(questionSlice.getContent().stream() + .map(questionInfoInterface -> toQuestionInfo(questionInfoInterface.getQuestion(), questionInfoInterface.getIsAnsweredByMember()) + ).toList()) + .numberOfElements(questionSlice.getNumberOfElements()) + .hasPrevious(questionSlice.hasPrevious()) + .hasNext(questionSlice.hasNext()) + .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..928d4399 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,10 @@ 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' " + + "ORDER BY q.livedAt DESC") + 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..decbe71b 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,22 @@ 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.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -27,34 +25,26 @@ 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) { + return questionMapper.toSliceQuestionInfo(questionRepository.findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(member, pageable)); } @Override 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..49413697 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, "createdAt"))).getContent(); //then assertEquals(questionInfos.size(), 2); From 180e637763ffd637f8c8a068f430f5c5bb0d603f Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:47:37 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20#159=20=EC=A7=88=EB=AC=B8?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=8B=B5=EB=B3=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20pagination?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/controller/AnswerController.java | 38 +++++++------- .../domain/answer/dao/AnswerRDBDao.java | 10 ++++ .../domain/answer/mapper/AnswerMapper.java | 13 +++++ .../answer/repository/AnswerRepository.java | 11 +++- .../domain/answer/service/AnswerService.java | 5 +- .../answer/service/AnswerServiceImpl.java | 51 +++++++++---------- 6 files changed, 76 insertions(+), 52 deletions(-) create mode 100644 src/main/java/com/server/capple/domain/answer/dao/AnswerRDBDao.java 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..2e7fa324 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,18 @@ 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.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 +26,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 +34,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 +56,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)); 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/mapper/AnswerMapper.java b/src/main/java/com/server/capple/domain/answer/mapper/AnswerMapper.java index 4900087b..8cfd7293 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 @@ -1,5 +1,6 @@ package com.server.capple.domain.answer.mapper; +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.AnswerInfo; import com.server.capple.domain.answer.dto.AnswerResponse.AnswerList; @@ -8,6 +9,8 @@ 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 com.server.capple.global.common.SliceResponse; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Component; import java.util.List; @@ -60,4 +63,14 @@ public MemberAnswerList toMemberAnswerList(List memberAnswerIn return new MemberAnswerList(memberAnswerInfos); } + public SliceResponse toAnswerInfoSliceResponse(Slice answerInfoSliceInterface, List content) { + return SliceResponse.builder() + .number(answerInfoSliceInterface.getNumber()) + .size(answerInfoSliceInterface.getSize()) + .content(content) + .numberOfElements(answerInfoSliceInterface.getNumberOfElements()) + .hasPrevious(answerInfoSliceInterface.hasPrevious()) + .hasNext(answerInfoSliceInterface.hasNext()) + .build(); + } } 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..0b38a496 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,11 +1,13 @@ 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; @@ -16,8 +18,13 @@ public interface AnswerRepository extends JpaRepository { boolean existsByQuestionAndMember(Question question, Member member); - @Query("SELECT a FROM Answer a WHERE a.question.id = :questionId ORDER BY a.createdAt DESC") - Optional> findByQuestion( + @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 " + + "ORDER BY a.createdAt DESC") + Optional> findByQuestion( @Param("questionId") Long questionId, 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..d34d6300 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.AnswerInfo; 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.global.common.SliceResponse; import org.springframework.data.domain.Pageable; @@ -20,7 +21,7 @@ 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); 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..35a201e9 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,9 +1,10 @@ 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.entity.Answer; import com.server.capple.domain.answer.mapper.AnswerMapper; @@ -14,10 +15,12 @@ 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; @@ -91,24 +94,18 @@ 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).orElseThrow(() + -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND)); + return answerMapper.toAnswerInfoSliceResponse(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()); } // 유저가 작성한 답변 조회 @@ -116,9 +113,9 @@ public AnswerList getAnswerList(Long memberId, Long questionId, String keyword, 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() + answers.stream() + .map(answer -> answerMapper.toMemberAnswerInfo(answer, answerHeartRedisRepository.getAnswerHeartsCount(answer.getId()), answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answer.getId()))) + .toList() ); } @@ -126,10 +123,10 @@ public MemberAnswerList getMemberAnswer(Member member) { @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() + answerHeartRedisRepository.getMemberHeartsAnswer(member.getId()) + .stream() + .map(answerId -> answerMapper.toMemberAnswerInfo(findAnswer((answerId)), answerHeartRedisRepository.getAnswerHeartsCount(answerId), answerHeartRedisRepository.isMemberLikedAnswer(member.getId(), answerId))) + .toList() ); } @@ -144,7 +141,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) ); } } From 7c5f48c8322318cdc6fbb23a8ac39400737e23ef Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:25:23 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20#159=20SliceResponse=20=EB=A7=A4?= =?UTF-8?q?=ED=8D=BC=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capple/global/common/SliceResponse.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 97050fec..979851cf 100644 --- a/src/main/java/com/server/capple/global/common/SliceResponse.java +++ b/src/main/java/com/server/capple/global/common/SliceResponse.java @@ -35,4 +35,19 @@ public SliceResponse(int number, int size, List content, int 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(); + } } From 8daf05efd1592955bb81c978722d856332b0bdc1 Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:26:31 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20#159=20SliceResponse=20=EB=A7=A4?= =?UTF-8?q?=ED=8D=BC=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20=EA=B5=AC=ED=98=84=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capple/domain/answer/mapper/AnswerMapper.java | 14 -------------- .../domain/answer/service/AnswerServiceImpl.java | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) 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 8cfd7293..400a4e83 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 @@ -1,6 +1,5 @@ package com.server.capple.domain.answer.mapper; -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.AnswerInfo; import com.server.capple.domain.answer.dto.AnswerResponse.AnswerList; @@ -9,8 +8,6 @@ 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 com.server.capple.global.common.SliceResponse; -import org.springframework.data.domain.Slice; import org.springframework.stereotype.Component; import java.util.List; @@ -62,15 +59,4 @@ public MemberAnswerInfo toMemberAnswerInfo(Answer answer, int heartCount, Boolea public MemberAnswerList toMemberAnswerList(List memberAnswerInfos) { return new MemberAnswerList(memberAnswerInfos); } - - public SliceResponse toAnswerInfoSliceResponse(Slice answerInfoSliceInterface, List content) { - return SliceResponse.builder() - .number(answerInfoSliceInterface.getNumber()) - .size(answerInfoSliceInterface.getSize()) - .content(content) - .numberOfElements(answerInfoSliceInterface.getNumberOfElements()) - .hasPrevious(answerInfoSliceInterface.hasPrevious()) - .hasNext(answerInfoSliceInterface.hasNext()) - .build(); - } } 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 35a201e9..2d23c3af 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 @@ -97,7 +97,7 @@ public AnswerLike toggleAnswerHeart(Member loginMember, Long answerId) { public SliceResponse getAnswerList(Long memberId, Long questionId, Pageable pageable) { Slice answerInfoSliceInterface = answerRepository.findByQuestion(questionId, pageable).orElseThrow(() -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND)); - return answerMapper.toAnswerInfoSliceResponse(answerInfoSliceInterface, answerInfoSliceInterface.getContent().stream().map( + return SliceResponse.toSliceResponse(answerInfoSliceInterface, answerInfoSliceInterface.getContent().stream().map( answerInfoDto -> answerMapper.toAnswerInfo( answerInfoDto.getAnswer(), memberId, From 3f20f0fe4021dc85a095da18ab436a62c0fccb76 Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:38:34 +0900 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20#159=20=EB=B3=B8=EC=9D=B8?= =?UTF-8?q?=EC=9D=98=20=EC=9E=91=EC=84=B1=ED=95=9C=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20pagination?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/controller/AnswerController.java | 10 +- .../answer/repository/AnswerRepository.java | 13 +- .../domain/answer/service/AnswerService.java | 3 +- .../answer/service/AnswerServiceImpl.java | 16 ++- .../controller/AnswerControllerTest.java | 9 +- .../answer/service/AnswerServiceTest.java | 8 +- .../capple/support/ControllerTestConfig.java | 118 +++++++++++------- 7 files changed, 105 insertions(+), 72 deletions(-) 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 2e7fa324..1a7e5451 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 @@ -4,6 +4,7 @@ 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; @@ -71,8 +72,13 @@ 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 입니다.") 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 0b38a496..3a6bcbe1 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 @@ -5,7 +5,6 @@ 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; @@ -25,15 +24,9 @@ public interface AnswerRepository extends JpaRepository { "WHERE a.question.id = :questionId " + "ORDER BY a.createdAt DESC") Optional> findByQuestion( - @Param("questionId") Long questionId, - Pageable pageable); - - @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); + @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); + 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 d34d6300..ef1ba2b4 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 @@ -3,6 +3,7 @@ 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.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.member.entity.Member; @@ -23,7 +24,7 @@ public interface AnswerService { SliceResponse getAnswerList(Long memberId, Long questionId, Pageable pageable); - MemberAnswerList getMemberAnswer(Member member); + SliceResponse getMemberAnswer(Member member, Pageable pageable); MemberAnswerList getMemberHeartAnswer(Member member); } 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 2d23c3af..f9f5486f 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 @@ -5,6 +5,7 @@ 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.MemberAnswerInfo; import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.answer.mapper.AnswerMapper; @@ -110,12 +111,15 @@ public SliceResponse getAnswerList(Long memberId, Long questionId, P // 유저가 작성한 답변 조회 @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() ); } 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..7217192d 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 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..9545258c 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 diff --git a/src/test/java/com/server/capple/support/ControllerTestConfig.java b/src/test/java/com/server/capple/support/ControllerTestConfig.java index d7945268..8ac02813 100644 --- a/src/test/java/com/server/capple/support/ControllerTestConfig.java +++ b/src/test/java/com/server/capple/support/ControllerTestConfig.java @@ -5,11 +5,12 @@ 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.MemberAnswerInfo; import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; 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; @@ -17,6 +18,7 @@ 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 +62,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,73 +78,93 @@ 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()); + protected MemberAnswerList getMemberAnswerList() { + 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 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() { List commentInfos = - List.of(BoardCommentInfo.builder() - .boardCommentId(1L) - .writerId(member.getId()) - .content("댓글") - .createdAt(LocalDateTime.now()) - .heartCount(2) - .isLiked(TRUE) - .isReport(FALSE) - .build()); + List.of(BoardCommentInfo.builder() + .boardCommentId(1L) + .writerId(member.getId()) + .content("댓글") + .createdAt(LocalDateTime.now()) + .heartCount(2) + .isLiked(TRUE) + .isReport(FALSE) + .build()); return new BoardCommentInfos(commentInfos); } 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); } From 33966a6e09dc423bf7e731d846e558d3facd6fcd Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:02:41 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20#159=20=EC=A2=8B=EC=95=84?= =?UTF-8?q?=ED=95=9C=20=EB=8B=B5=EB=B3=80=20=EC=A1=B0=ED=9A=8C=20paginatio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/controller/AnswerController.java | 9 +++++++-- .../domain/answer/dto/AnswerResponse.java | 16 ---------------- .../domain/answer/mapper/AnswerMapper.java | 12 ------------ .../answer/repository/AnswerRepository.java | 3 +++ .../domain/answer/service/AnswerService.java | 3 +-- .../answer/service/AnswerServiceImpl.java | 17 ++++++++--------- .../answer/controller/AnswerControllerTest.java | 8 ++++---- .../answer/service/AnswerServiceTest.java | 4 ++-- .../capple/support/ControllerTestConfig.java | 14 -------------- 9 files changed, 25 insertions(+), 61 deletions(-) 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 1a7e5451..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 @@ -83,7 +83,12 @@ public BaseResponse> getMemberAnswer( @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/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 400a4e83..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,8 +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 3a6bcbe1..cbd5770a 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 @@ -11,10 +11,13 @@ import org.springframework.data.jpa.repository.Query; import java.util.Optional; +import java.util.Set; public interface AnswerRepository extends JpaRepository { Optional findById(Long answerId); + Slice findByIdIn(Set answerIds, Pageable pageable); + boolean existsByQuestionAndMember(Question question, Member member); @Query("SELECT a AS answer, (r IS NOT NULL) AS isReported " + 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 ef1ba2b4..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 @@ -4,7 +4,6 @@ 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.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.member.entity.Member; import com.server.capple.global.common.SliceResponse; @@ -26,5 +25,5 @@ public interface AnswerService { 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 f9f5486f..10d37036 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 @@ -6,7 +6,6 @@ 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.MemberAnswerInfo; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.answer.mapper.AnswerMapper; import com.server.capple.domain.answer.repository.AnswerHeartRedisRepository; @@ -25,8 +24,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -125,12 +122,14 @@ public SliceResponse getMemberAnswer(Member member, Pageable p // 유저가 좋아한 답변 조회 @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() ); } 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 7217192d..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 @@ -161,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) @@ -175,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 9545258c..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 @@ -138,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/support/ControllerTestConfig.java b/src/test/java/com/server/capple/support/ControllerTestConfig.java index 8ac02813..cf29447f 100644 --- a/src/test/java/com/server/capple/support/ControllerTestConfig.java +++ b/src/test/java/com/server/capple/support/ControllerTestConfig.java @@ -6,7 +6,6 @@ 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.MemberAnswerInfo; -import com.server.capple.domain.answer.dto.AnswerResponse.MemberAnswerList; import com.server.capple.domain.answer.entity.Answer; import com.server.capple.domain.answerComment.dto.AnswerCommentRequest; import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.AnswerCommentInfo; @@ -99,19 +98,6 @@ protected AnswerRequest getAnswerRequest() { .build(); } - protected MemberAnswerList getMemberAnswerList() { - 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 new MemberAnswerList(memberAnswerInfos); - } - protected SliceResponse getSliceMemberAnswerInfos() { List memberAnswerInfos = List.of(MemberAnswerInfo.builder() .questionId(answer.getQuestion().getId()) From 85117a29ac671af74aac9647901061f78b46b69c Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:23:24 +0900 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20#159=20=EC=A7=88=EB=AC=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20slice=20mapper=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/question/mapper/QuestionMapper.java | 16 ---------------- .../question/service/QuestionServiceImpl.java | 7 ++++++- 2 files changed, 6 insertions(+), 17 deletions(-) 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 7b53fc40..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 @@ -1,12 +1,9 @@ package com.server.capple.domain.question.mapper; -import com.server.capple.domain.question.dao.QuestionInfoInterface; 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.QuestionSummary; import com.server.capple.domain.question.entity.Question; -import com.server.capple.global.common.SliceResponse; -import org.springframework.data.domain.Slice; import org.springframework.stereotype.Component; @Component @@ -43,17 +40,4 @@ public QuestionInfo toQuestionInfo(Question question, boolean isAnswered/*, Inte .isAnswered(isAnswered) .build(); } - - public SliceResponse toSliceQuestionInfo(Slice questionSlice) { - return SliceResponse.builder() - .number(questionSlice.getNumber()) - .size(questionSlice.getSize()) - .content(questionSlice.getContent().stream() - .map(questionInfoInterface -> toQuestionInfo(questionInfoInterface.getQuestion(), questionInfoInterface.getIsAnsweredByMember()) - ).toList()) - .numberOfElements(questionSlice.getNumberOfElements()) - .hasPrevious(questionSlice.hasPrevious()) - .hasNext(questionSlice.hasNext()) - .build(); - } } 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 decbe71b..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 @@ -2,6 +2,7 @@ import com.server.capple.domain.answer.repository.AnswerRepository; 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.QuestionInfo; import com.server.capple.domain.question.dto.response.QuestionResponse.QuestionSummary; @@ -14,6 +15,7 @@ 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; @@ -44,7 +46,10 @@ public QuestionSummary getMainQuestion(Member member) { @Override public SliceResponse getQuestions(Member member, Pageable pageable) { - return questionMapper.toSliceQuestionInfo(questionRepository.findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(member, pageable)); + Slice questionSlice = questionRepository.findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(member, pageable); + return SliceResponse.toSliceResponse(questionSlice, questionSlice.getContent().stream() + .map(questionInfoInterface -> questionMapper.toQuestionInfo(questionInfoInterface.getQuestion(), questionInfoInterface.getIsAnsweredByMember()) + ).toList()); } @Override From 8bf270b1ea8fb20d7814aa12ff4faa34f4792b3f Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:26:24 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20#159=20pagination=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EC=BF=BC=EB=A6=AC=20ORDER=20BY=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20=EB=B0=8F=20=EB=B0=98=ED=99=98=20=EA=B0=92=20Option?= =?UTF-8?q?al=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capple/domain/answer/repository/AnswerRepository.java | 7 +++---- .../capple/domain/answer/service/AnswerServiceImpl.java | 3 +-- .../domain/question/repository/QuestionRepository.java | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) 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 cbd5770a..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 @@ -24,12 +24,11 @@ public interface AnswerRepository extends JpaRepository { "FROM Answer a " + "LEFT JOIN " + "Report r ON r.answer = a " + - "WHERE a.question.id = :questionId " + - "ORDER BY a.createdAt DESC") - Optional> findByQuestion( + "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") + @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/AnswerServiceImpl.java b/src/main/java/com/server/capple/domain/answer/service/AnswerServiceImpl.java index 10d37036..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 @@ -93,8 +93,7 @@ public AnswerLike toggleAnswerHeart(Member loginMember, Long answerId) { @Override public SliceResponse getAnswerList(Long memberId, Long questionId, Pageable pageable) { - Slice answerInfoSliceInterface = answerRepository.findByQuestion(questionId, pageable).orElseThrow(() - -> new RestApiException(AnswerErrorCode.ANSWER_NOT_FOUND)); + Slice answerInfoSliceInterface = answerRepository.findByQuestion(questionId, pageable); return SliceResponse.toSliceResponse(answerInfoSliceInterface, answerInfoSliceInterface.getContent().stream().map( answerInfoDto -> answerMapper.toAnswerInfo( answerInfoDto.getAnswer(), 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 928d4399..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 @@ -23,8 +23,7 @@ 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") + "WHERE q.questionStatus = 'OLD' OR q.questionStatus = 'LIVE'") Slice findAllByQuestionStatusIsLiveAndOldOrderByLivedAtDesc(@Param("member") Member member, Pageable pageable); } From 1fc5ccb616fe80a5f6c743b49a3f0718b05b0f9f Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:42:16 +0900 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20#159=20=EC=A7=88=EB=AC=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=A0=95=EB=A0=AC=EC=88=9C=EC=84=9C=20liv?= =?UTF-8?q?edAt=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capple/domain/question/controller/QuestionController.java | 2 +- .../capple/domain/question/service/QuestionServiceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 550dd2ad..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 @@ -40,7 +40,7 @@ private BaseResponse getMainQuestion(@AuthMember Member member) }) @GetMapping 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, "createdAt")))); + return BaseResponse.onSuccess(questionService.getQuestions(member, PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "livedAt")))); } @Operation(summary = "질문 좋아요/취소 API", description = " 질문 좋아요/취소 API 입니다." + 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 49413697..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 @@ -56,7 +56,7 @@ public void closeLiveQuestionTest() { @Transactional public void getQuestionsTest() { //given & when - List questionInfos = questionService.getQuestions(member, PageRequest.of(0, 1000, Sort.by(Sort.Direction.DESC, "createdAt"))).getContent(); + List questionInfos = questionService.getQuestions(member, PageRequest.of(0, 1000, Sort.by(Sort.Direction.DESC, "livedAt"))).getContent(); //then assertEquals(questionInfos.size(), 2);