Skip to content

Commit fc72cec

Browse files
Merge pull request #118 from SeoyeonPark1223/feature-117
#117 Feature: 컬렉션 sortType, viewType 기준 구현
2 parents 59e6aaa + 06f0412 commit fc72cec

File tree

10 files changed

+126
-20
lines changed

10 files changed

+126
-20
lines changed

src/main/java/com/memesphere/domain/chartdata/scheduler/ChartDataScheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void updateChartData() {
4242
String symbol = memeCoin.getSymbol() + "USDT";
4343
BinanceTickerResponse response = binanceQueryService.getTickerData(symbol);
4444

45-
ChartData chartData = toChartData(memeCoin,response);
45+
ChartData chartData = toChartData(memeCoin, response);
4646

4747
memeCoinQueryService.updateChartData(memeCoin.getId(), chartData);
4848

src/main/java/com/memesphere/domain/collection/controller/CollectionRestController.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.memesphere.domain.collection.controller;
22

33
import com.memesphere.domain.collection.service.CollectionCommandService;
4+
import com.memesphere.domain.search.entity.SortType;
5+
import com.memesphere.domain.search.entity.ViewType;
46
import com.memesphere.global.apipayload.ApiResponse;
57
import com.memesphere.domain.collection.entity.Collection;
68
import com.memesphere.domain.collection.dto.response.CollectionPageResponse;
@@ -32,6 +34,8 @@ public class CollectionRestController {
3234
@GetMapping("/collection")
3335
@Operation(summary = "사용자의 밈코인 콜렉션 모음 조회 API")
3436
public ApiResponse<CollectionPageResponse> getCollectionList (
37+
@RequestParam(name = "viewType", defaultValue = "GRID") ViewType viewType, // 뷰 타입 (grid 또는 list)
38+
@RequestParam(name = "sortType", defaultValue = "PRICE_CHANGE") SortType sortType, // 정렬 기준 (MKTCap, 24h Volume, Price)
3539
@AuthenticationPrincipal CustomUserDetails userDetails, // 현재 로그인한 사용자
3640
@CheckPage @RequestParam(name = "page") Integer page // 페이지 번호
3741
) {
@@ -41,8 +45,8 @@ public ApiResponse<CollectionPageResponse> getCollectionList (
4145
// 유저를 찾지 못하면(로그인을 안 했으면) 콜렉션 접근 못하도록 에러 처리
4246
if (userId == null) throw new GeneralException(ErrorStatus.USER_NOT_FOUND);
4347

44-
Page<Collection> collectionPage = collectionQueryService.getCollectionPage(userId, pageNumber);
45-
return ApiResponse.onSuccess(CollectionConverter.toCollectionPageDTO(collectionPage));
48+
Page<Collection> collectionPage = collectionQueryService.getCollectionPage(userId, pageNumber, viewType, sortType);
49+
return ApiResponse.onSuccess(CollectionConverter.toCollectionPageDTO(collectionPage, viewType));
4650
}
4751

4852
@PostMapping("/collection/{coinId}")
Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.memesphere.domain.collection.converter;
22

33
import com.memesphere.domain.chartdata.entity.ChartData;
4+
import com.memesphere.domain.collection.dto.response.CollectionListPreviewResponse;
45
import com.memesphere.domain.collection.entity.Collection;
56
import com.memesphere.domain.memecoin.entity.MemeCoin;
67
import com.memesphere.domain.collection.dto.response.CollectionPageResponse;
7-
import com.memesphere.domain.collection.dto.response.CollectionPreviewResponse;
8+
import com.memesphere.domain.collection.dto.response.CollectionGridPreviewResponse;
9+
import com.memesphere.domain.search.entity.ViewType;
810
import com.memesphere.domain.user.entity.User;
11+
import io.swagger.v3.oas.annotations.media.Schema;
912
import org.springframework.data.domain.Page;
1013

14+
import java.math.BigDecimal;
1115
import java.util.List;
1216
import java.util.stream.Collectors;
1317

@@ -18,26 +22,36 @@ public static Collection toCollection(User user, MemeCoin coin) {
1822
.user(user).memeCoin(coin).build();
1923
}
2024

21-
public static CollectionPageResponse toCollectionPageDTO(Page<Collection> collectionPage) {
22-
List<CollectionPreviewResponse> collectionItems = collectionPage.getContent().stream()
23-
.map(collection -> toCollectionPreviewDTO(collection))
24-
.collect(Collectors.toList());
25+
public static CollectionPageResponse toCollectionPageDTO(Page<Collection> collectionPage, ViewType viewType) {
26+
List<CollectionGridPreviewResponse> gridItems = null;
27+
List<CollectionListPreviewResponse> listItems = null;
28+
29+
if (viewType == ViewType.GRID) {
30+
gridItems = collectionPage.stream()
31+
.map(collection -> toCollectionGridPreviewDTO(collection))
32+
.collect(Collectors.toList());
33+
} else if (viewType == ViewType.LIST) {
34+
listItems = collectionPage.stream()
35+
.map(collection -> toCollectionListPreviewDTO(collection))
36+
.collect(Collectors.toList());
37+
}
2538

2639
return CollectionPageResponse.builder()
27-
.collectionItems(collectionItems)
28-
.listSize(collectionItems.size())
40+
.gridItems(gridItems)
41+
.listItems(listItems)
42+
.listSize(collectionPage.getContent().size())
2943
.totalPage(collectionPage.getTotalPages())
3044
.totalElements(collectionPage.getTotalElements())
3145
.isFirst(collectionPage.isFirst())
3246
.isLast(collectionPage.isLast())
3347
.build();
3448
}
3549

36-
private static CollectionPreviewResponse toCollectionPreviewDTO(Collection collection) {
50+
private static CollectionGridPreviewResponse toCollectionGridPreviewDTO(Collection collection) {
3751
MemeCoin memeCoin = collection.getMemeCoin();
3852
ChartData chartData = memeCoin.getChartDataList().get(0);
3953

40-
return CollectionPreviewResponse.builder()
54+
return CollectionGridPreviewResponse.builder()
4155
.coinId(memeCoin.getId())
4256
.name(memeCoin.getName())
4357
.symbol(memeCoin.getSymbol())
@@ -49,4 +63,19 @@ private static CollectionPreviewResponse toCollectionPreviewDTO(Collection colle
4963
.priceChangeRate(chartData.getPriceChangeRate())
5064
.build();
5165
}
66+
67+
public static CollectionListPreviewResponse toCollectionListPreviewDTO(Collection collection) {
68+
MemeCoin memeCoin = collection.getMemeCoin();
69+
ChartData chartData = memeCoin.getChartDataList().get(0);
70+
71+
return CollectionListPreviewResponse.builder()
72+
.coinId(memeCoin.getId())
73+
.name(memeCoin.getName())
74+
.symbol(memeCoin.getSymbol())
75+
.currentPrice(chartData.getPrice())
76+
.priceChangeRate(chartData.getPriceChangeRate())
77+
.weightedAveragePrice(chartData.getWeighted_average_price())
78+
.volume(chartData.getVolume())
79+
.build();
80+
}
5281
}

src/main/java/com/memesphere/domain/collection/dto/response/CollectionPreviewResponse.java renamed to src/main/java/com/memesphere/domain/collection/dto/response/CollectionGridPreviewResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
@Builder
1313
@AllArgsConstructor
1414
@NoArgsConstructor
15-
public class CollectionPreviewResponse {
15+
public class CollectionGridPreviewResponse {
1616
@Schema(description = "밈코인 id", example = "1")
1717
Long coinId;
1818
@Schema(description = "밈코인 name", example = "도지코인")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.memesphere.domain.collection.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.math.BigDecimal;
10+
11+
@Getter
12+
@Builder
13+
@AllArgsConstructor
14+
@NoArgsConstructor
15+
public class CollectionListPreviewResponse {
16+
@Schema(description = "밈코인 id", example = "1")
17+
Long coinId;
18+
@Schema(description = "밈코인 name", example = "도지코인")
19+
String name;
20+
@Schema(description = "밈코인 symbol", example = "DOGE")
21+
String symbol;
22+
@Schema(description = "차트 데이터의 price", example = "2000")
23+
BigDecimal currentPrice;
24+
@Schema(description = "차트 데이터의 price_change_rate", example = "+2.4%")
25+
BigDecimal priceChangeRate;
26+
@Schema(description = "차트 데이터의 weighted average price", example = "10000")
27+
BigDecimal weightedAveragePrice; // market cap 대신 사용
28+
@Schema(description = "차트 데이터의 volume", example = "5")
29+
BigDecimal volume;
30+
}
31+

src/main/java/com/memesphere/domain/collection/dto/response/CollectionPageResponse.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.memesphere.domain.collection.dto.response;
22

3+
import com.memesphere.domain.collection.entity.Collection;
4+
import com.memesphere.domain.search.dto.response.SearchGridPreviewResponse;
5+
import com.memesphere.domain.search.dto.response.SearchListPreviewResponse;
36
import io.swagger.v3.oas.annotations.media.Schema;
47
import lombok.AllArgsConstructor;
58
import lombok.Builder;
@@ -13,8 +16,10 @@
1316
@AllArgsConstructor
1417
@NoArgsConstructor
1518
public class CollectionPageResponse {
16-
@Schema(description = "콜렉션 아이템들")
17-
List<CollectionPreviewResponse> collectionItems;
19+
@Schema(description = "gridView용 컬렉션 아이템들")
20+
List<CollectionGridPreviewResponse> gridItems; // Grid View용 데이터
21+
@Schema(description = "listView용 컬렉션 아이템들")
22+
List<CollectionListPreviewResponse> listItems; // List View용 데이터
1823
Integer listSize;
1924
Integer totalPage;
2025
Long totalElements;

src/main/java/com/memesphere/domain/collection/repository/CollectionRepository.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,27 @@
66
import org.springframework.data.domain.Page;
77
import org.springframework.data.domain.Pageable;
88
import org.springframework.data.jpa.repository.JpaRepository;
9+
import org.springframework.data.jpa.repository.Query;
10+
import org.springframework.data.repository.query.Param;
911

1012
import java.util.List;
1113
import java.util.Optional;
1214

1315
public interface CollectionRepository extends JpaRepository<Collection, Long> {
14-
Page<Collection> findAllByUserId(Long userId, Pageable pageable);
1516
List<Collection> findAllByUserId(Long userId);
1617
Optional<Collection> findByUserAndMemeCoin(User user, MemeCoin memeCoin);
18+
19+
@Query("SELECT c FROM Collection c " +
20+
"JOIN c.memeCoin m " +
21+
"JOIN m.chartDataList cd " +
22+
"WHERE c.user.id = :userId " +
23+
"AND cd.recordedTime = (SELECT MAX(cd2.recordedTime) FROM ChartData cd2 WHERE cd2.memeCoin = m) " +
24+
"ORDER BY " +
25+
" CASE WHEN :sortField = 'priceChange' THEN cd.priceChange END DESC, " +
26+
" CASE WHEN :sortField = 'volume' THEN cd.volume END DESC, " +
27+
" CASE WHEN :sortField = 'price' THEN cd.price END DESC")
28+
Page<Collection> findWithLatestChartDataSorted(
29+
@Param("userId") Long userId,
30+
@Param("sortField") String sortField,
31+
Pageable pageable);
1732
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.memesphere.domain.collection.service;
22

33
import com.memesphere.domain.collection.entity.Collection;
4+
import com.memesphere.domain.search.entity.SortType;
5+
import com.memesphere.domain.search.entity.ViewType;
46
import org.springframework.data.domain.Page;
57

68
import java.util.List;
79

810
public interface CollectionQueryService {
9-
Page<Collection> getCollectionPage(Long userId, Integer pageNumber);
11+
Page<Collection> getCollectionPage(Long userId, Integer pageNumber, ViewType viewType, SortType sortType);
1012
List<Long> getUserCollectionIds(Long userId);
1113
}

src/main/java/com/memesphere/domain/collection/service/CollectionQueryServiceImpl.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
import com.memesphere.domain.collection.entity.Collection;
44
import com.memesphere.domain.collection.repository.CollectionRepository;
5+
import com.memesphere.domain.search.entity.SortType;
6+
import com.memesphere.domain.search.entity.ViewType;
57
import com.memesphere.domain.user.repository.UserRepository;
8+
import com.memesphere.global.apipayload.code.status.ErrorStatus;
9+
import com.memesphere.global.apipayload.exception.GeneralException;
610
import lombok.RequiredArgsConstructor;
711
import org.springframework.data.domain.Page;
812
import org.springframework.data.domain.PageRequest;
13+
import org.springframework.data.domain.Pageable;
914
import org.springframework.stereotype.Service;
1015
import org.springframework.transaction.annotation.Transactional;
1116

@@ -20,8 +25,24 @@ public class CollectionQueryServiceImpl implements CollectionQueryService {
2025

2126
@Transactional(readOnly = true)
2227
@Override
23-
public Page<Collection> getCollectionPage(Long userId, Integer pageNumber) {
24-
Page<Collection> collectionPage = collectionRepository.findAllByUserId(userId, PageRequest.of(pageNumber, 9 ));
28+
public Page<Collection> getCollectionPage(Long userId, Integer pageNumber, ViewType viewType, SortType sortType) {
29+
30+
int pageSize = switch (viewType) {
31+
case GRID -> 9;
32+
case LIST -> 20;
33+
default -> throw new GeneralException(ErrorStatus.UNSUPPORTED_VIEW_TYPE);
34+
};
35+
36+
String sortField = switch (sortType) {
37+
case PRICE_CHANGE -> "priceChange";
38+
case VOLUME_24H -> "volume";
39+
case PRICE -> "price";
40+
default -> throw new GeneralException(ErrorStatus.UNSUPPORTED_SORT_TYPE);
41+
};
42+
43+
Pageable pageable = PageRequest.of(pageNumber, pageSize);
44+
45+
Page<Collection> collectionPage = collectionRepository.findWithLatestChartDataSorted(userId, sortField, pageable);
2546
return collectionPage;
2647
}
2748

src/main/java/com/memesphere/domain/search/dto/response/SearchListPreviewResponse.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public class SearchListPreviewResponse {
1919
String name;
2020
@Schema(description = "밈코인 symbol", example = "DOGE")
2121
String symbol;
22-
// market cap = currentPrice x volume
2322
@Schema(description = "차트 데이터의 price", example = "2000")
2423
BigDecimal currentPrice;
2524
@Schema(description = "차트 데이터의 weighted average price", example = "10000")

0 commit comments

Comments
 (0)