Skip to content

Commit be24627

Browse files
committed
#17 Merge: 충돌 해결
2 parents 998f5d0 + fbe30d5 commit be24627

31 files changed

+414
-136
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import org.springframework.data.jpa.repository.EntityGraph;
66
import org.springframework.data.jpa.repository.JpaRepository;
77
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
89

10+
import java.awt.print.Pageable;
911
import java.math.BigDecimal;
1012
import java.time.LocalDateTime;
1113
import java.util.List;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class ChartDataScheduler {
2424
private final BinanceQueryService binanceQueryService;
2525
private final MemeCoinQueryService memeCoinQueryService;
2626

27-
@Scheduled(fixedRate = 600000) // 10분 간격 실행
27+
@Scheduled(cron = "0 0/10 * * * ?") // 0, 10, 20, 30, 40, 50분에 실행
2828
@Transactional
2929
public void updateChartData() {
3030
List<MemeCoin> memeCoins = memeCoinRepository.findAll();

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import com.memesphere.domain.collection.entity.Collection;
66
import com.memesphere.domain.collection.dto.response.CollectionPageResponse;
77
import com.memesphere.domain.collection.service.CollectionQueryService;
8+
import com.memesphere.global.apipayload.code.status.ErrorStatus;
9+
import com.memesphere.global.apipayload.exception.GeneralException;
810
import com.memesphere.global.jwt.CustomUserDetails;
911
import com.memesphere.global.jwt.TokenProvider;
1012
import com.memesphere.global.validation.annotation.CheckPage;
@@ -22,7 +24,6 @@
2224
@Tag(name="콜렉션", description = "콜렉션 관련 API")
2325
@RestController
2426
@RequiredArgsConstructor
25-
//@RequestMapping("/collection")
2627
public class CollectionRestController {
2728
private final CollectionQueryService collectionQueryService;
2829
private final CollectionCommandService collectionCommandService;
@@ -31,12 +32,14 @@ public class CollectionRestController {
3132
@GetMapping("/collection")
3233
@Operation(summary = "사용자의 밈코인 콜렉션 모음 조회 API")
3334
public ApiResponse<CollectionPageResponse> getCollectionList (
34-
// @AuthenticationPrincipal User user, // 현재 로그인한 사용자 (아직 구현 x)
35+
@AuthenticationPrincipal CustomUserDetails userDetails, // 현재 로그인한 사용자
3536
@CheckPage @RequestParam(name = "page") Integer page // 페이지 번호
3637
) {
3738
Integer pageNumber = page - 1;
38-
// Long userId = user.getId();
39-
Long userId = 1L;
39+
Long userId = (userDetails == null) ? null : userDetails.getUser().getId();
40+
41+
// 유저를 찾지 못하면(로그인을 안 했으면) 콜렉션 접근 못하도록 에러 처리
42+
if (userId == null) throw new GeneralException(ErrorStatus.USER_NOT_FOUND);
4043

4144
Page<Collection> collectionPage = collectionQueryService.getCollectionPage(userId, pageNumber);
4245
return ApiResponse.onSuccess(CollectionConverter.toCollectionPageDTO(collectionPage));

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
import org.springframework.stereotype.Service;
1010
import org.springframework.transaction.annotation.Transactional;
1111

12+
import java.util.Collections;
1213
import java.util.List;
1314
import java.util.stream.Collectors;
1415

1516
@Service
1617
@RequiredArgsConstructor
1718
public class CollectionQueryServiceImpl implements CollectionQueryService {
18-
private final UserRepository userRepository;
1919
private final CollectionRepository collectionRepository;
2020

2121
@Transactional(readOnly = true)
@@ -28,6 +28,8 @@ public Page<Collection> getCollectionPage(Long userId, Integer pageNumber) {
2828
@Transactional(readOnly = true)
2929
@Override
3030
public List<Long> getUserCollectionIds(Long userId) {
31+
if (userId == null) return Collections.emptyList();
32+
3133
return collectionRepository.findAllByUserId(userId).stream()
3234
.map(Collection::getMemeCoinId)
3335
.collect(Collectors.toList());

src/main/java/com/memesphere/domain/dashboard/controller/DashboardController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ public ApiResponse<DashboardOverviewResponse> getOverview() {
6060
- "volume": 밈코인 거래량(확인용)
6161
- "price": 밈코인 현재가
6262
- "priceChange": 가격 변화량
63-
- "changeAbsolute": 가격 변화량(절대값)
64-
- "changeDirection": 밈코인 상승(up, 0 이상)/하락(down)
65-
- "changeRate": 가격 변화율
63+
- "priceChangeAbsolute": 가격 변화량(절대값)
64+
- "priceChangeDirection": 밈코인 상승(up, 0 이상)/하락(down)
65+
- "priceChangeRate": 가격 변화율
66+
- "rankChangeDirection": 순위 상승(up, 0 이상)/하락(down)
6667
```""")
6768
public ApiResponse<DashboardTrendListResponse> getTrendList() {
6869
return ApiResponse.onSuccess(dashboardQueryService.getTrendList());

src/main/java/com/memesphere/domain/dashboard/converter/DashboardConverter.java

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import com.memesphere.domain.dashboard.dto.response.DashboardTrendListResponse;
77
import com.memesphere.domain.dashboard.dto.response.DashboardTrendResponse;
88

9+
910
import java.math.BigDecimal;
1011
import java.time.LocalDateTime;
12+
import java.util.ArrayList;
1113
import java.util.List;
12-
import java.util.stream.Collectors;
1314

1415
public class DashboardConverter {
1516
// ** 총 거래량 및 총 개수 응답 형식 ** //
@@ -21,20 +22,46 @@ public static DashboardOverviewResponse toOverView(BigDecimal totalVolume, Long
2122
}
2223

2324
// ** 트렌드 응답 형식 ** //
24-
public static DashboardTrendListResponse toTrendList(LocalDateTime recordedTime, List<ChartData> dataList) {
25-
List<DashboardTrendResponse> trendList = dataList.stream()
26-
.map(data -> toTrend(data))
27-
.collect(Collectors.toList());
25+
public static DashboardTrendListResponse toTrendList(LocalDateTime recordedTime,
26+
List<ChartData> dataList,
27+
List<MemeCoin> prevCoinList) {
28+
29+
List<DashboardTrendResponse> trendList = new ArrayList<>();
30+
31+
// 현재 top5에 들지 않는 밈코인 순위 처리
32+
List<MemeCoin> currCoinList = dataList.stream().map(ChartData::getMemeCoin).toList();
33+
for (MemeCoin prevCoin : prevCoinList) {
34+
if (!currCoinList.contains(prevCoin)) prevCoin.updateRank(null);
35+
}
36+
37+
38+
// 현재 top5 밈코인
39+
for (int i = 0; i < 5; i++) {
40+
ChartData data = dataList.get(i);
41+
DashboardTrendResponse trend = toTrend(data, prevCoinList, i + 1);
42+
trendList.add(trend);
43+
}
2844

2945
return DashboardTrendListResponse.builder()
3046
.timestamp(recordedTime)
3147
.trendList(trendList)
3248
.build();
3349
}
3450

35-
public static DashboardTrendResponse toTrend(ChartData data) {
51+
public static DashboardTrendResponse toTrend(ChartData data,
52+
List<MemeCoin> prevCoinList,
53+
Integer currRank) {
3654
MemeCoin memeCoin = data.getMemeCoin();
3755

56+
// 이전에 기록된 밈코인 순위와 현재 밈코인 순위 변화
57+
// prevRank == -1 : 새로 등록 순위
58+
Integer prevRank = prevCoinList.indexOf(memeCoin);
59+
prevRank = (prevRank == -1) ? null : prevRank + 1;
60+
String rankDirection = (prevRank == null || currRank <= prevRank) ? "up" : "down";
61+
62+
// 순위 업데이트
63+
memeCoin.updateRank(currRank);
64+
3865
return DashboardTrendResponse.builder()
3966
.coinId(memeCoin.getId())
4067
.image(memeCoin.getImage())
@@ -43,9 +70,10 @@ public static DashboardTrendResponse toTrend(ChartData data) {
4370
.volume(data.getVolume())
4471
.price(data.getPrice())
4572
.priceChange(data.getPriceChange())
46-
.changeAbsolute(data.getPriceChange().abs())
47-
.changeDirection(data.getPriceChangeRate().compareTo(BigDecimal.ZERO) < 0 ? "down" : "up")
48-
.changeRate(data.getPriceChangeRate())
73+
.priceChangeAbsolute(data.getPriceChange().abs())
74+
.priceChangeDirection(data.getPriceChangeRate().compareTo(BigDecimal.ZERO) < 0 ? "down" : "up")
75+
.priceChangeRate(data.getPriceChangeRate())
76+
.rankChangeDirection(rankDirection)
4977
.build();
5078
}
5179
}

src/main/java/com/memesphere/domain/dashboard/dto/response/DashboardTrendResponse.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ public class DashboardTrendResponse {
3030
@Schema(description = "가격 변화량", example = "-0.03")
3131
private BigDecimal priceChange;
3232

33-
@Schema(description = "변화량 절대값", example = "0.03")
34-
private BigDecimal changeAbsolute;
33+
@Schema(description = "가격 변화량 절대값", example = "0.03")
34+
private BigDecimal priceChangeAbsolute;
3535

36-
@Schema(description = "변화 방향", example = "down")
37-
private String changeDirection;
36+
@Schema(description = "가격 변화 방향", example = "down")
37+
private String priceChangeDirection;
3838

39-
@Schema(description = "변화율", example = "-6.35")
40-
private BigDecimal changeRate;
39+
@Schema(description = "가격 변화율", example = "-6.35")
40+
private BigDecimal priceChangeRate;
41+
42+
@Schema(description = "순위 변화 방향", example = "down")
43+
private String rankChangeDirection;
4144
}

src/main/java/com/memesphere/domain/dashboard/service/DashboardQueryServiceImpl.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.memesphere.domain.dashboard.service;
22

3+
import com.memesphere.domain.chartdata.entity.ChartData;
34
import com.memesphere.domain.collection.service.CollectionQueryService;
45
import com.memesphere.domain.dashboard.converter.DashboardConverter;
56
import com.memesphere.domain.dashboard.dto.response.DashboardOverviewResponse;
6-
import com.memesphere.domain.chartdata.entity.ChartData;
77
import com.memesphere.domain.dashboard.dto.response.DashboardTrendListResponse;
88
import com.memesphere.domain.chartdata.repository.ChartDataRepository;
9-
import com.memesphere.domain.user.entity.User;
109
import com.memesphere.domain.user.repository.UserRepository;
1110
import com.memesphere.global.apipayload.code.status.ErrorStatus;
1211
import com.memesphere.global.apipayload.exception.GeneralException;
@@ -30,16 +29,15 @@
3029
import java.util.List;
3130

3231
@Service
33-
@Transactional(readOnly = true)
3432
@RequiredArgsConstructor
3533
public class DashboardQueryServiceImpl implements DashboardQueryService {
36-
private final UserRepository userRepository;
3734
private final MemeCoinRepository memeCoinRepository;
3835
private final ChartDataRepository chartDataRepository;
3936
private final CollectionQueryService collectionQueryService;
4037

4138
// ** 총 거래량 및 총 개수 ** //
4239
@Override
40+
@Transactional(readOnly = true)
4341
public DashboardOverviewResponse getOverview() {
4442
// 등록된 모든 밈코인의 총 거래량
4543
BigDecimal totalVolume = chartDataRepository.findTotalVolume();
@@ -52,18 +50,25 @@ public DashboardOverviewResponse getOverview() {
5250

5351
// ** 트렌드 ** //
5452
@Override
53+
@Transactional
5554
public DashboardTrendListResponse getTrendList() {
56-
// 거래량 top5 밈코인-차트데이터
55+
// 이전에 기록된 top5 밈코인
56+
List<MemeCoin> prevCoinList = memeCoinRepository.findTop5OrderByRank();
57+
58+
// 최신 거래량 top5 밈코인-차트데이터
5759
List<ChartData> dataList = chartDataRepository.findTop5OrderByVolumeDesc();
5860

5961
// 코인 아이디 1 기준 기록 시간
6062
LocalDateTime recordedTime = chartDataRepository.findRecordedTimeByCoinId1();
6163

62-
return DashboardConverter.toTrendList(recordedTime, dataList);
64+
DashboardTrendListResponse trendList = DashboardConverter.toTrendList(recordedTime, dataList, prevCoinList);
65+
memeCoinRepository.saveAll(prevCoinList); // 순위 업데이트
66+
return trendList;
6367
}
6468

6569
// ** 차트 ** //
6670
@Override
71+
@Transactional(readOnly = true)
6772
public SearchPageResponse getChartPage(Long userId, ViewType viewType, SortType sortType, Integer pageNumber) {
6873

6974
// 로그인 x -> 콜렉션 빈 리스트
@@ -87,7 +92,7 @@ public SearchPageResponse getChartPage(Long userId, ViewType viewType, SortType
8792
Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, sortField));
8893
Page<MemeCoin> coinPage = memeCoinRepository.findAllLatestChartData(pageable);
8994

90-
// null 체크 후 예외 처리}
95+
// null 체크 후 예외 처리
9196
return SearchConverter.toSearchPageDTO(coinPage, viewType, userCollectionIds);
9297
}
9398
}

src/main/java/com/memesphere/domain/image/controller/ImageController.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
import com.memesphere.domain.image.dto.response.PresignedUrlResponse;
44
import com.memesphere.domain.image.dto.request.ImageExtensionRequest;
55
import com.memesphere.domain.image.service.ImageService;
6+
import com.memesphere.domain.image.service.ProfileService;
67
import com.memesphere.global.apipayload.ApiResponse;
78
import io.swagger.v3.oas.annotations.Operation;
89
import lombok.RequiredArgsConstructor;
910
import org.springframework.http.MediaType;
1011
import org.springframework.web.bind.annotation.*;
1112

12-
@RequestMapping("/s3")
13+
@RequestMapping("/image")
1314
@RestController
1415
@RequiredArgsConstructor
1516
public class ImageController {
1617

1718
private final ImageService imageService;
19+
private final ProfileService profileService;
1820

1921
@PostMapping(value = "/upload", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
2022
@Operation(
@@ -30,4 +32,16 @@ public ApiResponse<PresignedUrlResponse> uploadFile(@RequestBody ImageExtensionR
3032

3133
return ApiResponse.onSuccess(url);
3234
}
35+
36+
//프로필 이미지 조회 Api
37+
@GetMapping("/profile/{user_id}")
38+
@Operation(summary = "프로필 이미지 조회 API",
39+
description = "회원가입한 유저의 프로필 이미지를 반환합니다.")
40+
public ApiResponse<String> getProfile(@PathVariable("user_id") Long user_id) {
41+
String profileImage = profileService.getProfileImage(user_id);
42+
43+
// null이거나 ""이면 result를 null로 반환
44+
return ApiResponse.onSuccess((profileImage == null || profileImage.isEmpty()) ? "null" : profileImage);
45+
}
46+
3347
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.memesphere.domain.image.service;
2+
3+
import com.memesphere.domain.user.entity.User;
4+
import com.memesphere.domain.user.repository.UserRepository;
5+
import com.memesphere.global.apipayload.code.status.ErrorStatus;
6+
import com.memesphere.global.apipayload.exception.GeneralException;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
@RequiredArgsConstructor
12+
public class ProfileService {
13+
private final UserRepository userRepository;
14+
15+
// 프로필 이미지 반환
16+
public String getProfileImage(Long userId) {
17+
User user = userRepository.findById(userId)
18+
.orElseThrow(() -> new GeneralException(ErrorStatus.USER_NOT_FOUND));
19+
return user.getProfileImage();
20+
}
21+
}

0 commit comments

Comments
 (0)