diff --git a/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java b/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java index 3cac3a9..0e36e5c 100644 --- a/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java +++ b/backend/src/main/java/org/dgu/backend/common/constant/SuccessStatus.java @@ -39,7 +39,8 @@ public enum SuccessStatus implements BaseCode { // Upbit-Key SUCCESS_ADD_UPBIT_KEYS(HttpStatus.CREATED, "201", "업비트 키 등록에 성공했습니다"), // Chart - SUCCESS_GET_OHLCV_CHART(HttpStatus.OK, "200", "OHLCV 차트 조회에 성공했습니다."); + SUCCESS_GET_OHLCV_CHART(HttpStatus.OK, "200", "OHLCV 차트 조회에 성공했습니다."), + SUCCESS_GET_ALL_CHART_OPTIONS(HttpStatus.OK, "200", "차트 선택 지표 목록 조회에 성공했습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/backend/src/main/java/org/dgu/backend/controller/ChartController.java b/backend/src/main/java/org/dgu/backend/controller/ChartController.java index a986d17..dabaf70 100644 --- a/backend/src/main/java/org/dgu/backend/controller/ChartController.java +++ b/backend/src/main/java/org/dgu/backend/controller/ChartController.java @@ -25,4 +25,12 @@ public ResponseEntity>> getOHLCVCharts( List ohlcvResponses = chartService.getOHLCVCharts(koreanName, candleName); return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_OHLCV_CHART, ohlcvResponses); } + + // 차트 선택 지표 목록을 조회하는 API + @GetMapping("/options") + public ResponseEntity>> getAllChartOptions() { + + List chartOptionResponses = chartService.getAllChartOptions(); + return ApiResponse.onSuccess(SuccessStatus.SUCCESS_GET_ALL_CHART_OPTIONS, chartOptionResponses); + } } \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/dto/ChartDto.java b/backend/src/main/java/org/dgu/backend/dto/ChartDto.java index 1680820..d493cfe 100644 --- a/backend/src/main/java/org/dgu/backend/dto/ChartDto.java +++ b/backend/src/main/java/org/dgu/backend/dto/ChartDto.java @@ -7,7 +7,9 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import org.dgu.backend.domain.Candle; import org.dgu.backend.domain.CandleInfo; +import org.dgu.backend.domain.Market; import org.dgu.backend.util.BigDecimalSerializer; import java.math.BigDecimal; @@ -32,7 +34,7 @@ public static class OHLCVResponse { @JsonSerialize(using = BigDecimalSerializer.class) private BigDecimal volume; - public static ChartDto.OHLCVResponse of(CandleInfo candleInfo) { + public static OHLCVResponse of(CandleInfo candleInfo) { return OHLCVResponse.builder() .date(String.valueOf(candleInfo.getDateTime())) .openingPrice(BigDecimal.valueOf(candleInfo.getOpeningPrice())) @@ -43,4 +45,27 @@ public static ChartDto.OHLCVResponse of(CandleInfo candleInfo) { .build(); } } + + @Builder + @Getter + @AllArgsConstructor + @JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class ChartOptionResponse { + private String englishName; + private String koreanName; + private String marketName; + private String candleName; + private String candleKoreanName; + + public static ChartOptionResponse of(Market market, Candle candle) { + return ChartOptionResponse.builder() + .englishName(market.getEnglishName()) + .koreanName(market.getKoreanName()) + .marketName(market.getMarketName()) + .candleName(candle.getCandleName()) + .candleKoreanName(candle.getKoreanName()) + .build(); + } + } } \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/CandleErrorResult.java b/backend/src/main/java/org/dgu/backend/exception/CandleErrorResult.java new file mode 100644 index 0000000..229398e --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/CandleErrorResult.java @@ -0,0 +1,37 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.dgu.backend.common.code.BaseErrorCode; +import org.dgu.backend.common.dto.ErrorReasonDto; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum CandleErrorResult implements BaseErrorCode { + NOT_FOUND_CANDLE(HttpStatus.NOT_FOUND, "404", "존재하지 않는 캔들입니다."), + NOT_FOUND_CANDLES(HttpStatus.NOT_FOUND, "404", "캔들 목록이 존재하지 않습니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDto getReason() { + return ErrorReasonDto.builder() + .isSuccess(false) + .code(code) + .message(message) + .build(); + } + + @Override + public ErrorReasonDto getReasonHttpStatus() { + return ErrorReasonDto.builder() + .isSuccess(false) + .httpStatus(httpStatus) + .code(code) + .message(message) + .build(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/CandleException.java b/backend/src/main/java/org/dgu/backend/exception/CandleException.java new file mode 100644 index 0000000..d58a4df --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/CandleException.java @@ -0,0 +1,15 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class CandleException extends RuntimeException { + private final CandleErrorResult candleErrorResult; + + @Override + public String getMessage() { + return candleErrorResult.getMessage(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java b/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java index c63f72a..9cca2c0 100644 --- a/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java +++ b/backend/src/main/java/org/dgu/backend/exception/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.dgu.backend.common.ApiResponse; import org.dgu.backend.common.code.BaseErrorCode; +import org.dgu.backend.domain.Market; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MissingRequestHeaderException; @@ -68,4 +69,16 @@ public ResponseEntity> handleChartException(ChartExce ChartErrorResult errorResult = e.getChartErrorResult(); return ApiResponse.onFailure(errorResult); } + // Market + @ExceptionHandler(MarketException.class) + public ResponseEntity> handleMarketException(MarketException e) { + MarketErrorResult errorResult = e.getMarketErrorResult(); + return ApiResponse.onFailure(errorResult); + } + // Candle + @ExceptionHandler(CandleException.class) + public ResponseEntity> handleCandleException(CandleException e) { + CandleErrorResult errorResult = e.getCandleErrorResult(); + return ApiResponse.onFailure(errorResult); + } } \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/MarketErrorResult.java b/backend/src/main/java/org/dgu/backend/exception/MarketErrorResult.java new file mode 100644 index 0000000..23aba20 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/MarketErrorResult.java @@ -0,0 +1,37 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.dgu.backend.common.code.BaseErrorCode; +import org.dgu.backend.common.dto.ErrorReasonDto; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum MarketErrorResult implements BaseErrorCode { + NOT_FOUND_MARKET(HttpStatus.NOT_FOUND, "404", "존재하지 않는 가상화폐입니다."), + NOT_FOUND_MARKETS(HttpStatus.NOT_FOUND, "404", "가상화폐 목록이 존재하지 않습니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDto getReason() { + return ErrorReasonDto.builder() + .isSuccess(false) + .code(code) + .message(message) + .build(); + } + + @Override + public ErrorReasonDto getReasonHttpStatus() { + return ErrorReasonDto.builder() + .isSuccess(false) + .httpStatus(httpStatus) + .code(code) + .message(message) + .build(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/exception/MarketException.java b/backend/src/main/java/org/dgu/backend/exception/MarketException.java new file mode 100644 index 0000000..a20d7b5 --- /dev/null +++ b/backend/src/main/java/org/dgu/backend/exception/MarketException.java @@ -0,0 +1,15 @@ +package org.dgu.backend.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class MarketException extends RuntimeException { + private final MarketErrorResult marketErrorResult; + + @Override + public String getMessage() { + return marketErrorResult.getMessage(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/service/ChartService.java b/backend/src/main/java/org/dgu/backend/service/ChartService.java index 8346141..3a71c68 100644 --- a/backend/src/main/java/org/dgu/backend/service/ChartService.java +++ b/backend/src/main/java/org/dgu/backend/service/ChartService.java @@ -6,4 +6,5 @@ public interface ChartService { List getOHLCVCharts(String koreanName, String candleType); + List getAllChartOptions(); } \ No newline at end of file diff --git a/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java b/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java index fd32db5..972b802 100644 --- a/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java +++ b/backend/src/main/java/org/dgu/backend/service/ChartServiceImpl.java @@ -6,8 +6,7 @@ import org.dgu.backend.domain.CandleInfo; import org.dgu.backend.domain.Market; import org.dgu.backend.dto.ChartDto; -import org.dgu.backend.exception.ChartErrorResult; -import org.dgu.backend.exception.ChartException; +import org.dgu.backend.exception.*; import org.dgu.backend.repository.CandleInfoRepository; import org.dgu.backend.repository.CandleRepository; import org.dgu.backend.repository.MarketRepository; @@ -16,6 +15,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; @Service @@ -35,6 +35,24 @@ public List getOHLCVCharts(String koreanName, String can return fetchUpdatedCandleInfo(koreanName, candleName); } + // 차트 선택 지표 목록을 반환하는 메서드 + @Override + public List getAllChartOptions() { + List markets = marketRepository.findAll(); + if (markets.isEmpty()) { + throw new MarketException(MarketErrorResult.NOT_FOUND_MARKETS); + } + List candles = candleRepository.findAll(); + if (candles.isEmpty()) { + throw new CandleException(CandleErrorResult.NOT_FOUND_CANDLES); + } + + return markets.stream() + .flatMap(market -> candles.stream() + .map(candle -> ChartDto.ChartOptionResponse.of(market, candle))) + .collect(Collectors.toList()); + } + // 캔들 정보 최신화 메서드 @Transactional protected void updateCandleInfo(String koreanName, String candleName) { @@ -45,7 +63,13 @@ protected void updateCandleInfo(String koreanName, String candleName) { @Transactional protected List fetchUpdatedCandleInfo(String koreanName, String candleName) { Market market = marketRepository.findByKoreanName(koreanName); + if (Objects.isNull(market)) { + throw new MarketException(MarketErrorResult.NOT_FOUND_MARKET); + } Candle candle = candleRepository.findByCandleName(candleName); + if (Objects.isNull(candle)) { + throw new CandleException(CandleErrorResult.NOT_FOUND_CANDLE); + } LocalDateTime startDate = candleUtil.getStartDateByCandleName(candleName); List candleInfos = candleInfoRepository.findByMarketAndCandleAndDateTimeAfter(market, candle, startDate);