Skip to content

Commit 8cdf511

Browse files
authored
Merge pull request #109 from nimuy99/feat/105-detail-price-info
#105 Feat: 코인 디테일 가격 정보 조회 기능 구현
2 parents a0fb187 + a1ca030 commit 8cdf511

File tree

8 files changed

+128
-8
lines changed

8 files changed

+128
-8
lines changed

src/main/java/com/memesphere/domain/chartdata/repository/ChartDataRepository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.math.BigDecimal;
1212
import java.time.LocalDateTime;
1313
import java.util.List;
14+
import java.util.Optional;
1415

1516
public interface ChartDataRepository extends JpaRepository<ChartData, Long> {
1617
@Query("SELECT SUM(c.volume) FROM ChartData c " +
@@ -32,4 +33,9 @@ public interface ChartDataRepository extends JpaRepository<ChartData, Long> {
3233
//TODO: 위아래 코드 합치는 방법 찾기
3334
List<ChartData> findByMemeCoinOrderByRecordedTimeDesc(MemeCoin memeCoin, Pageable pageable);
3435

36+
@Query("SELECT c FROM ChartData c " +
37+
"WHERE c.memeCoin.id = :coinId " +
38+
"AND c.recordedTime = " +
39+
"(SELECT MAX(c2.recordedTime) FROM ChartData c2 WHERE c2.memeCoin = c.memeCoin)")
40+
Optional<ChartData> findLatestByCoinId(Long coinId);
3541
}

src/main/java/com/memesphere/domain/detail/controller/DetailController.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.memesphere.domain.detail.controller;
22

3+
import com.memesphere.domain.detail.dto.response.PriceInfoResponse;
4+
import com.memesphere.domain.detail.service.DetailQueryServiceImpl;
35
import com.memesphere.global.apipayload.ApiResponse;
46
import com.memesphere.domain.detail.dto.response.DetailGetResponse;
5-
import com.memesphere.domain.detail.service.DetailService;
7+
import com.memesphere.domain.detail.service.DetailQueryService;
68
import io.swagger.v3.oas.annotations.Operation;
79
import io.swagger.v3.oas.annotations.tags.Tag;
810
import lombok.RequiredArgsConstructor;
@@ -17,7 +19,7 @@
1719
@RequestMapping("/detail")
1820
public class DetailController {
1921

20-
private final DetailService detailService;
22+
private final DetailQueryService detailQueryService;
2123

2224
@GetMapping("/{memeId}")
2325
@Operation(summary = "밈코인 세부 정보 조회 API",
@@ -35,10 +37,38 @@ public class DetailController {
3537
- "image": 밈코인 이미지
3638
- "keywords": 밈코인 키워드 (리스트 형식)
3739
- "collectionActive": 컬렉션 유무 (저장 유무)
40+
- "rank": 밈코인 순위(1 ~ 5위까지, 나머지 순위는 null)
3841
```""")
3942
public ApiResponse<DetailGetResponse> getDetail(@PathVariable("memeId") Long memeId) {
4043

41-
DetailGetResponse detailGetResponse = detailService.getDetail(memeId);
44+
DetailGetResponse detailGetResponse = detailQueryService.getDetail(memeId);
4245
return ApiResponse.onSuccess(detailGetResponse);
4346
}
47+
48+
@GetMapping("/{memeId}/price-info")
49+
@Operation(summary = "밈코인 가격 정보 조회 API",
50+
description = """
51+
해당 밈코인의 24시간 기준 가격 정보를 보여줍니다. \n
52+
53+
**요청 형식**:
54+
```
55+
"memeId": 코인 아이디
56+
```
57+
\n
58+
**응답 형식**:
59+
```
60+
- "coinId": 코인 아이디
61+
- "price": 현재가
62+
- "priceChange": 가격 변화량
63+
- "priceChangeAbsolute": 가격 변화량(절대값)
64+
- "priceChangeDirection": 밈코인 상승(up, 0 이상)/하락(down)
65+
- "priceChangeRate": 가격 변화율
66+
- "weightedAveragePrice": 거래량 가중 평균 가격
67+
- "highPrice": 24h 최고가
68+
- "lowPrice": 24h 최저가
69+
```""")
70+
public ApiResponse<PriceInfoResponse> getPriceInfo(@PathVariable("memeId") Long coinId) {
71+
72+
return ApiResponse.onSuccess(detailQueryService.findPriceInfo(coinId));
73+
}
4474
}

src/main/java/com/memesphere/domain/detail/converter/DetailConverter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package com.memesphere.domain.detail.converter;
22

3+
import com.memesphere.domain.chartdata.entity.ChartData;
4+
import com.memesphere.domain.detail.dto.response.PriceInfoResponse;
35
import com.memesphere.domain.memecoin.entity.MemeCoin;
46
import com.memesphere.domain.detail.dto.response.DetailGetResponse;
57

8+
import java.math.BigDecimal;
9+
610
public class DetailConverter {
711

812
public static DetailGetResponse toDetailGetResponse(MemeCoin memeCoin) {
@@ -15,6 +19,21 @@ public static DetailGetResponse toDetailGetResponse(MemeCoin memeCoin) {
1519
.image(memeCoin.getImage())
1620
.keywords(memeCoin.getKeywords())
1721
.collectionActive(memeCoin.getCollectionList().isEmpty())
22+
.rank(memeCoin.getTrendRank())
23+
.build();
24+
}
25+
26+
public static PriceInfoResponse toPriceInfoResponse(MemeCoin memeCoin, ChartData data) {
27+
return PriceInfoResponse.builder()
28+
.coinId(memeCoin.getId())
29+
.price(data.getPrice())
30+
.priceChange(data.getPriceChange())
31+
.priceChangeAbsolute(data.getPriceChange().abs())
32+
.priceChangeDirection(data.getPriceChangeRate().compareTo(BigDecimal.ZERO) < 0 ? "down" : "up")
33+
.priceChangeRate(data.getPriceChangeRate())
34+
.weightedAveragePrice(data.getWeighted_average_price())
35+
.highPrice(data.getHigh_price())
36+
.lowPrice(data.getLow_price())
1837
.build();
1938
}
2039
}

src/main/java/com/memesphere/domain/detail/dto/response/DetailGetResponse.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ public class DetailGetResponse {
3030

3131
@Schema(description = "컬렉션 유무", example = "True")
3232
private boolean collectionActive;
33+
34+
@Schema(description = "밈코인 순위", example = "1")
35+
private Integer rank;
3336
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.memesphere.domain.detail.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
import java.math.BigDecimal;
8+
9+
@Getter
10+
@Builder
11+
public class PriceInfoResponse {
12+
@Schema(description = "밈코인 아이디", example = "1")
13+
private Long coinId;
14+
15+
@Schema(description = "현재가", example = "0.20")
16+
private BigDecimal price;
17+
18+
@Schema(description = "가격 변화량", example = "-0.03")
19+
private BigDecimal priceChange;
20+
21+
@Schema(description = "가격 변화량 절대값", example = "0.03")
22+
private BigDecimal priceChangeAbsolute;
23+
24+
@Schema(description = "가격 변화 방향", example = "down")
25+
private String priceChangeDirection;
26+
27+
@Schema(description = "가격 변화율", example = "-6.35")
28+
private BigDecimal priceChangeRate;
29+
30+
@Schema(description = "거래량 가중 평균 가격", example = "-942.38")
31+
private BigDecimal weightedAveragePrice;
32+
33+
@Schema(description = "24h 최고가", example = "2500")
34+
private BigDecimal highPrice;
35+
36+
@Schema(description = "24h 최저가", example = "1500")
37+
private BigDecimal lowPrice;
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.memesphere.domain.detail.service;
2+
3+
4+
import com.memesphere.domain.detail.dto.response.DetailGetResponse;
5+
import com.memesphere.domain.detail.dto.response.PriceInfoResponse;
6+
7+
public interface DetailQueryService {
8+
DetailGetResponse getDetail(Long meme_id);
9+
PriceInfoResponse findPriceInfo(Long coinId);
10+
}

src/main/java/com/memesphere/domain/detail/service/DetailService.java renamed to src/main/java/com/memesphere/domain/detail/service/DetailQueryServiceImpl.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
package com.memesphere.domain.detail.service;
22

3+
import com.memesphere.domain.chartdata.entity.ChartData;
4+
import com.memesphere.domain.chartdata.repository.ChartDataRepository;
35
import com.memesphere.domain.detail.converter.DetailConverter;
4-
import com.memesphere.global.apipayload.code.status.ErrorStatus;
5-
import com.memesphere.global.apipayload.exception.GeneralException;
6-
import com.memesphere.domain.memecoin.entity.MemeCoin;
76
import com.memesphere.domain.detail.dto.response.DetailGetResponse;
7+
import com.memesphere.domain.detail.dto.response.PriceInfoResponse;
8+
import com.memesphere.domain.memecoin.entity.MemeCoin;
89
import com.memesphere.domain.memecoin.repository.MemeCoinRepository;
10+
import com.memesphere.global.apipayload.code.status.ErrorStatus;
11+
import com.memesphere.global.apipayload.exception.GeneralException;
912
import lombok.RequiredArgsConstructor;
1013
import org.springframework.stereotype.Service;
1114
import org.springframework.transaction.annotation.Transactional;
1215

1316
@Service
1417
@RequiredArgsConstructor
15-
public class DetailService {
16-
18+
public class DetailQueryServiceImpl implements DetailQueryService {
1719
private final MemeCoinRepository memeCoinRepository;
20+
private final ChartDataRepository chartDataRepository;
1821

1922
@Transactional
2023
public DetailGetResponse getDetail(Long meme_id) {
@@ -26,4 +29,14 @@ public DetailGetResponse getDetail(Long meme_id) {
2629

2730
return detailGetResponse;
2831
}
32+
33+
public PriceInfoResponse findPriceInfo(Long coinId) {
34+
MemeCoin memeCoin = memeCoinRepository.findById(coinId)
35+
.orElseThrow(() -> new GeneralException(ErrorStatus.MEMECOIN_NOT_FOUND));
36+
37+
ChartData data = chartDataRepository.findLatestByCoinId(coinId)
38+
.orElseThrow(() -> new GeneralException(ErrorStatus.CHARTDATA_NOT_FOUND));
39+
40+
return DetailConverter.toPriceInfoResponse(memeCoin, data);
41+
}
2942
}

src/main/java/com/memesphere/global/apipayload/code/status/ErrorStatus.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public enum ErrorStatus implements BaseCode {
3131

3232
// ChartData load 에러
3333
CANNOT_LOAD_CHARTDATA(HttpStatus.BAD_REQUEST, "CANNOT LOAD CHARTDATA", "ChartData를 Binance에서 로드할 수 없습니다."),
34+
CHARTDATA_NOT_FOUND(HttpStatus.NOT_FOUND, "CHARTDATA NOT FOUND", "차트 데이터를 찾을 수 없습니다."),
3435

3536
// notification 에러
3637
CANNOT_CHECK_VOLATILITY(HttpStatus.NOT_FOUND, "CANNOT CHECK VOLATILITY", "변동성을 확인할 수 없습니다."),

0 commit comments

Comments
 (0)