diff --git a/src/main/java/com/sb/web/account/controller/FxController.java b/src/main/java/com/sb/web/account/controller/FxController.java index 9ee1c54..4ef8fd9 100644 --- a/src/main/java/com/sb/web/account/controller/FxController.java +++ b/src/main/java/com/sb/web/account/controller/FxController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; +import java.time.Instant; import java.util.HashMap; import java.util.Map; @@ -28,10 +29,12 @@ public class FxController { public Map rate(@RequestParam String from, @RequestParam(defaultValue = "KRW") String to) { BigDecimal rate = fxService.getRate(from, to); + Instant updatedAt = fxService.getCachedAt(from); Map res = new HashMap<>(); res.put("from", from == null ? null : from.toUpperCase()); res.put("to", to == null ? null : to.toUpperCase()); res.put("rate", rate); // 조회 실패 시 null + res.put("updatedAt", updatedAt != null ? updatedAt.toString() : null); return res; } } diff --git a/src/main/java/com/sb/web/account/service/FxService.java b/src/main/java/com/sb/web/account/service/FxService.java index 527663c..03300ed 100644 --- a/src/main/java/com/sb/web/account/service/FxService.java +++ b/src/main/java/com/sb/web/account/service/FxService.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; import java.math.BigDecimal; +import java.time.Instant; import java.time.LocalDate; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -21,9 +22,17 @@ public class FxService { private static final String URL = "https://open.er-api.com/v6/latest/{base}"; private final RestClient restClient = RestClient.builder().build(); - private record Cached(LocalDate date, JsonNode rates) {} + private record Cached(LocalDate date, Instant fetchedAt, JsonNode rates) {} private final Map cache = new ConcurrentHashMap<>(); + /** from 통화 1단위 → to 통화 환율. 조회 실패 시 null. */ + /** 해당 통화 환율이 마지막으로 캐시된 시각. 캐시 없으면 null. */ + public Instant getCachedAt(String from) { + if (from == null) return null; + Cached c = cache.get(from.trim().toUpperCase()); + return c != null ? c.fetchedAt() : null; + } + /** from 통화 1단위 → to 통화 환율. 조회 실패 시 null. */ public BigDecimal getRate(String from, String to) { if (from == null || to == null) return null; @@ -54,7 +63,7 @@ public class FxService { if (rates.isMissingNode() || !rates.isObject()) { return c != null ? c.rates() : null; } - cache.put(base, new Cached(today, rates)); + cache.put(base, new Cached(today, Instant.now(), rates)); return rates; } catch (Exception e) { log.warn("환율 조회 실패 base={}: {}", base, e.toString());