- FxService: Cached 레코드에 fetchedAt(Instant) 추가, getCachedAt() 공개 - FxController: GET /api/fx/rate 응답에 updatedAt(ISO 문자열) 포함 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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<String, Object> rate(@RequestParam String from,
|
||||
@RequestParam(defaultValue = "KRW") String to) {
|
||||
BigDecimal rate = fxService.getRate(from, to);
|
||||
Instant updatedAt = fxService.getCachedAt(from);
|
||||
Map<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, Cached> 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());
|
||||
|
||||
Reference in New Issue
Block a user