-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* [WALWAL-159] 피드 작업 * fix: 약간 수정 * fix: resolve review * fix: 테스트 케이스 앞에 public 삭제
- Loading branch information
Showing
9 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
src/main/java/com/depromeet/stonebed/domain/feed/api/FeedController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.depromeet.stonebed.domain.feed.api; | ||
|
||
import com.depromeet.stonebed.domain.feed.application.FeedService; | ||
import com.depromeet.stonebed.domain.feed.dto.request.FeedGetRequest; | ||
import com.depromeet.stonebed.domain.feed.dto.response.FeedGetResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@Tag(name = "7. [피드]", description = "피드 관련 API입니다.") | ||
@RestController | ||
@RequestMapping("/feed") | ||
@RequiredArgsConstructor | ||
public class FeedController { | ||
private final FeedService feedService; | ||
|
||
@GetMapping | ||
public FeedGetResponse getFeed( | ||
@RequestParam(required = false) String cursor, @RequestParam int limit) { | ||
FeedGetRequest request = new FeedGetRequest(cursor, limit); | ||
return feedService.getFeed(request); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
src/main/java/com/depromeet/stonebed/domain/feed/application/FeedService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.depromeet.stonebed.domain.feed.application; | ||
|
||
import com.depromeet.stonebed.domain.feed.dao.FeedRepository; | ||
import com.depromeet.stonebed.domain.feed.dto.request.FeedGetRequest; | ||
import com.depromeet.stonebed.domain.feed.dto.response.FeedContentGetResponse; | ||
import com.depromeet.stonebed.domain.feed.dto.response.FeedGetResponse; | ||
import com.depromeet.stonebed.domain.member.domain.Member; | ||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import com.depromeet.stonebed.global.util.MemberUtil; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class FeedService { | ||
private final FeedRepository feedRepository; | ||
private final MemberUtil memberUtil; | ||
|
||
@Transactional(readOnly = true) | ||
public FeedGetResponse getFeed(FeedGetRequest request) { | ||
Member currentMember = memberUtil.getCurrentMember(); | ||
|
||
List<MissionRecord> missionRecords = | ||
getMissionRecords(request.cursor(), currentMember.getId(), request.limit()); | ||
|
||
List<FeedContentGetResponse> feedContentList = | ||
missionRecords.stream().map(FeedContentGetResponse::from).toList(); | ||
|
||
String nextCursor = getNextCursor(missionRecords, request.limit()); | ||
|
||
return FeedGetResponse.from(feedContentList, nextCursor); | ||
} | ||
|
||
private String getNextCursor(List<MissionRecord> records, int limit) { | ||
if (records.size() < limit) { | ||
return null; | ||
} | ||
|
||
MissionRecord lastRecord = records.get(records.size() - 1); | ||
Long lastId = lastRecord.getId(); | ||
return String.valueOf(lastId); | ||
} | ||
|
||
private List<MissionRecord> getMissionRecords(String cursor, Long memberId, int limit) { | ||
if (cursor == null || cursor.isEmpty()) { | ||
return feedRepository.getFeedContents(memberId, limit); | ||
} | ||
|
||
return feedRepository.getFeedContentsUsingCursor(Long.parseLong(cursor), memberId, limit); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/com/depromeet/stonebed/domain/feed/dao/FeedRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.depromeet.stonebed.domain.feed.dao; | ||
|
||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface FeedRepository extends JpaRepository<MissionRecord, Long>, FeedRepositoryCustom {} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/depromeet/stonebed/domain/feed/dao/FeedRepositoryCustom.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.depromeet.stonebed.domain.feed.dao; | ||
|
||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import java.util.List; | ||
|
||
public interface FeedRepositoryCustom { | ||
List<MissionRecord> getFeedContentsUsingCursor(Long missionRecordId, Long memberId, int limit); | ||
|
||
List<MissionRecord> getFeedContents(Long memberId, int limit); | ||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/com/depromeet/stonebed/domain/feed/dao/FeedRepositoryImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.depromeet.stonebed.domain.feed.dao; | ||
|
||
import static com.depromeet.stonebed.domain.missionRecord.domain.QMissionRecord.missionRecord; | ||
|
||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class FeedRepositoryImpl implements FeedRepositoryCustom { | ||
private final JPAQueryFactory queryFactory; | ||
|
||
@Override | ||
public List<MissionRecord> getFeedContentsUsingCursor( | ||
Long missionRecordId, Long memberId, int limit) { | ||
return queryFactory | ||
.select(missionRecord) | ||
.from(missionRecord) | ||
.where( | ||
missionRecord | ||
.id | ||
.lt(missionRecordId) | ||
.and(missionRecord.member.id.eq(memberId))) | ||
.orderBy(missionRecord.id.desc()) | ||
.limit(limit) | ||
.fetch(); | ||
} | ||
|
||
@Override | ||
public List<MissionRecord> getFeedContents(Long memberId, int limit) { | ||
return queryFactory | ||
.select(missionRecord) | ||
.from(missionRecord) | ||
.where(missionRecord.member.id.eq(memberId)) | ||
.orderBy(missionRecord.id.desc()) | ||
.limit(limit) | ||
.fetch(); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/depromeet/stonebed/domain/feed/dto/request/FeedGetRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.depromeet.stonebed.domain.feed.dto.request; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
|
||
public record FeedGetRequest( | ||
@Schema(description = "커서 위치", example = "1") String cursor, | ||
@Schema(description = "피드 당 항목 수", example = "5") int limit) {} |
20 changes: 20 additions & 0 deletions
20
src/main/java/com/depromeet/stonebed/domain/feed/dto/response/FeedContentGetResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.depromeet.stonebed.domain.feed.dto.response; | ||
|
||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.time.LocalDate; | ||
|
||
public record FeedContentGetResponse( | ||
@Schema(description = "미션 ID", example = "1") Long missionId, | ||
@Schema(description = "작성자 ID", example = "1") Long authorId, | ||
@Schema(description = "미션 기록 이미지 URL", example = "example.jpeg") | ||
String missionRecordImageUrl, | ||
@Schema(description = "미션 기록 생성일") LocalDate createdDate) { | ||
public static FeedContentGetResponse from(MissionRecord missionRecord) { | ||
return new FeedContentGetResponse( | ||
missionRecord.getId(), | ||
missionRecord.getMember().getId(), | ||
missionRecord.getImageUrl(), | ||
missionRecord.getCreatedAt().toLocalDate()); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/depromeet/stonebed/domain/feed/dto/response/FeedGetResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.stonebed.domain.feed.dto.response; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.util.List; | ||
|
||
public record FeedGetResponse( | ||
List<FeedContentGetResponse> list, | ||
@Schema(description = "커서 위치", example = "1") String nextCursor) { | ||
public static FeedGetResponse from(List<FeedContentGetResponse> list, String nextCursor) { | ||
return new FeedGetResponse(list, nextCursor); | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
src/test/java/com/depromeet/stonebed/domain/feed/application/FeedServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package com.depromeet.stonebed.domain.feed.application; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.*; | ||
|
||
import com.depromeet.stonebed.domain.feed.dao.FeedRepository; | ||
import com.depromeet.stonebed.domain.feed.dto.request.FeedGetRequest; | ||
import com.depromeet.stonebed.domain.feed.dto.response.FeedGetResponse; | ||
import com.depromeet.stonebed.domain.member.domain.Member; | ||
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; | ||
import com.depromeet.stonebed.global.util.MemberUtil; | ||
import com.navercorp.fixturemonkey.FixtureMonkey; | ||
import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
|
||
public class FeedServiceTest { | ||
@Mock private FeedRepository feedRepository; | ||
|
||
@Mock private MemberUtil memberUtil; | ||
|
||
@InjectMocks private FeedService feedService; | ||
|
||
private FixtureMonkey fixtureMonkey; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
fixtureMonkey = | ||
FixtureMonkey.builder() | ||
.objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) | ||
.defaultNotNull(true) | ||
.build(); | ||
MockitoAnnotations.openMocks(this); | ||
} | ||
|
||
@Test | ||
void 피드_조회_성공() { | ||
// Given | ||
Member member = fixtureMonkey.giveMeOne(Member.class); | ||
List<MissionRecord> missionRecords = new ArrayList<>(); | ||
|
||
for (int i = 0; i < 5; i++) { | ||
missionRecords.add(fixtureMonkey.giveMeOne(MissionRecord.class)); | ||
} | ||
|
||
when(memberUtil.getCurrentMember()).thenReturn(member); | ||
when(feedRepository.getFeedContents(member.getId(), 5)).thenReturn(missionRecords); | ||
|
||
// When | ||
FeedGetResponse feedGetResponse = feedService.getFeed(new FeedGetRequest(null, 5)); | ||
|
||
// Then | ||
assertThat(feedGetResponse.list().size()).isEqualTo(5); | ||
String nextCursor = missionRecords.get(missionRecords.size() - 1).getId().toString(); | ||
assertThat(feedGetResponse.nextCursor()).isEqualTo(nextCursor); | ||
verify(memberUtil).getCurrentMember(); | ||
verify(feedRepository).getFeedContents(member.getId(), 5); | ||
} | ||
|
||
@Test | ||
void 피드_조회_커서_사용_성공() { | ||
// Given | ||
Member member = fixtureMonkey.giveMeOne(Member.class); | ||
List<MissionRecord> missionRecords = new ArrayList<>(); | ||
String cursor = "5"; | ||
|
||
for (int i = 0; i < 5; i++) { | ||
missionRecords.add(fixtureMonkey.giveMeOne(MissionRecord.class)); | ||
} | ||
|
||
when(memberUtil.getCurrentMember()).thenReturn(member); | ||
when(feedRepository.getFeedContentsUsingCursor(Long.parseLong(cursor), member.getId(), 5)) | ||
.thenReturn(missionRecords); | ||
|
||
// When | ||
FeedGetResponse feedGetResponse = feedService.getFeed(new FeedGetRequest(cursor, 5)); | ||
|
||
// Then | ||
assertThat(feedGetResponse.list().size()).isEqualTo(5); | ||
String nextCursor = missionRecords.get(missionRecords.size() - 1).getId().toString(); | ||
assertThat(feedGetResponse.nextCursor()).isEqualTo(nextCursor); | ||
verify(memberUtil).getCurrentMember(); | ||
verify(feedRepository) | ||
.getFeedContentsUsingCursor(Long.parseLong(cursor), member.getId(), 5); | ||
} | ||
|
||
@Test | ||
void 피드_조회_커서_사용_마지막_성공() { | ||
// Given | ||
Member member = fixtureMonkey.giveMeOne(Member.class); | ||
List<MissionRecord> missionRecords = new ArrayList<>(); | ||
String cursor = "5"; | ||
|
||
for (int i = 0; i < 3; i++) { | ||
missionRecords.add(fixtureMonkey.giveMeOne(MissionRecord.class)); | ||
} | ||
|
||
when(memberUtil.getCurrentMember()).thenReturn(member); | ||
when(feedRepository.getFeedContentsUsingCursor(Long.parseLong(cursor), member.getId(), 5)) | ||
.thenReturn(missionRecords); | ||
|
||
// When | ||
FeedGetResponse feedGetResponse = feedService.getFeed(new FeedGetRequest(cursor, 5)); | ||
|
||
// Then | ||
assertThat(feedGetResponse.list().size()).isEqualTo(3); | ||
assertThat(feedGetResponse.nextCursor()).isEqualTo(null); | ||
verify(memberUtil).getCurrentMember(); | ||
verify(feedRepository) | ||
.getFeedContentsUsingCursor(Long.parseLong(cursor), member.getId(), 5); | ||
} | ||
} |