11package com.back.koreaTravelGuide.domain.ai.tour.client
22
3- import com.back.koreaTravelGuide.domain.ai.tour.dto.InternalData
3+ import com.back.koreaTravelGuide.domain.ai.tour.dto.TourItem
44import com.back.koreaTravelGuide.domain.ai.tour.dto.TourResponse
5+ import com.back.koreaTravelGuide.domain.ai.tour.dto.TourSearchParams
56import com.fasterxml.jackson.databind.ObjectMapper
67import org.slf4j.LoggerFactory
78import org.springframework.beans.factory.annotation.Value
@@ -22,7 +23,7 @@ class TourApiClient(
2223 private val logger = LoggerFactory .getLogger(TourApiClient ::class .java)
2324
2425 // 요청 URL 구성
25- private fun buildUrl (params : InternalData ): URI =
26+ private fun buildUrl (params : TourSearchParams ): URI =
2627 UriComponentsBuilder .fromUri(URI .create(apiUrl))
2728 .path(" /areaBasedList2" )
2829 .queryParam(" serviceKey" , serviceKey)
@@ -39,7 +40,7 @@ class TourApiClient(
3940 .toUri()
4041
4142 // 지역 기반 관광 정보 조회 (areaBasedList2)
42- fun fetchTourInfo (params : InternalData ): List < TourResponse > {
43+ fun fetchTourInfo (params : TourSearchParams ): TourResponse {
4344 logger.info(" 지역 기반 관광 정보 조회 시작" )
4445
4546 val url = buildUrl(params)
@@ -51,14 +52,17 @@ class TourApiClient(
5152 * takeUnless { it.isNullOrBlank() }: 공백 응답을 걸러냄
5253 * ?.let { parseItems(it) } ?: emptyList(): 유효한 응답은 파싱, 아니면 빈 리스트 반환
5354 */
54- return runCatching { restTemplate.getForObject(url, String ::class .java) }
55- .onFailure { logger.error(" 관광 정보 조회 실패" , it) }
56- .getOrNull()
57- .takeUnless { it.isNullOrBlank() }
58- ?.let { parseItems(it) } ? : emptyList()
55+ val response =
56+ runCatching { restTemplate.getForObject(url, String ::class .java) }
57+ .onFailure { logger.error(" 관광 정보 조회 실패" , it) }
58+ .getOrNull()
59+ .takeUnless { it.isNullOrBlank() }
60+ ?.let { parseItems(it) }
61+
62+ return response ? : TourResponse (items = emptyList())
5963 }
6064
61- private fun parseItems (json : String ): List < TourResponse > {
65+ private fun parseItems (json : String ): TourResponse {
6266 val root = objectMapper.readTree(json)
6367
6468 // header.resultCode 값 추출위한 노스 탐색 과정
@@ -72,7 +76,7 @@ class TourApiClient(
7276 // resultCode가 "0000"이 아닌 경우 체크
7377 if (resultCode != " 0000" ) {
7478 logger.warn(" 관광 정보 API resultCode={}" , resultCode)
75- return emptyList()
79+ return TourResponse (items = emptyList() )
7680 }
7781
7882 // path("키") 형태로 노드를 탐색, 응답 Json 형태의 순서에 따라 순차적으로 내려감
@@ -84,27 +88,30 @@ class TourApiClient(
8488 .path(" item" )
8589
8690 // 탐색 결과가 비어 있는 경우
87- if (! itemsNode.isArray || itemsNode.isEmpty) return emptyList()
91+ if (! itemsNode.isArray || itemsNode.isEmpty) return TourResponse (items = emptyList() )
8892
89- // itemsNode가 배열이므로 map으로 각 노드를 TourResponse로 변환
90- return itemsNode.map { node ->
91- TourResponse (
92- contentId = node.path(" contentid" ).asText(),
93- contentTypeId = node.path(" contenttypeid" ).asText(),
94- createdTime = node.path(" createdtime" ).asText(),
95- modifiedTime = node.path(" modifiedtime" ).asText(),
96- title = node.path(" title" ).asText(),
97- addr1 = node.path(" addr1" ).takeIf { it.isTextual }?.asText(),
98- areaCode = node.path(" areacode" ).takeIf { it.isTextual }?.asText(),
99- firstimage = node.path(" firstimage" ).takeIf { it.isTextual }?.asText(),
100- firstimage2 = node.path(" firstimage2" ).takeIf { it.isTextual }?.asText(),
101- mapX = node.path(" mapx" ).takeIf { it.isTextual }?.asText(),
102- mapY = node.path(" mapy" ).takeIf { it.isTextual }?.asText(),
103- mlevel = node.path(" mlevel" ).takeIf { it.isTextual }?.asText(),
104- sigunguCode = node.path(" sigungucode" ).takeIf { it.isTextual }?.asText(),
105- lDongRegnCd = node.path(" lDongRegnCd" ).takeIf { it.isTextual }?.asText(),
106- lDongSignguCd = node.path(" lDongSignguCd" ).takeIf { it.isTextual }?.asText(),
107- )
108- }
93+ // itemsNode가 배열이므로 map으로 각 노드를 TourItem으로 변환 후 컨테이너로 감싼다.
94+ val items =
95+ itemsNode.map { node ->
96+ TourItem (
97+ contentId = node.path(" contentid" ).asText(),
98+ contentTypeId = node.path(" contenttypeid" ).asText(),
99+ createdTime = node.path(" createdtime" ).asText(),
100+ modifiedTime = node.path(" modifiedtime" ).asText(),
101+ title = node.path(" title" ).asText(),
102+ addr1 = node.path(" addr1" ).takeIf { it.isTextual }?.asText(),
103+ areaCode = node.path(" areacode" ).takeIf { it.isTextual }?.asText(),
104+ firstimage = node.path(" firstimage" ).takeIf { it.isTextual }?.asText(),
105+ firstimage2 = node.path(" firstimage2" ).takeIf { it.isTextual }?.asText(),
106+ mapX = node.path(" mapx" ).takeIf { it.isTextual }?.asText(),
107+ mapY = node.path(" mapy" ).takeIf { it.isTextual }?.asText(),
108+ mlevel = node.path(" mlevel" ).takeIf { it.isTextual }?.asText(),
109+ sigunguCode = node.path(" sigungucode" ).takeIf { it.isTextual }?.asText(),
110+ lDongRegnCd = node.path(" lDongRegnCd" ).takeIf { it.isTextual }?.asText(),
111+ lDongSignguCd = node.path(" lDongSignguCd" ).takeIf { it.isTextual }?.asText(),
112+ )
113+ }
114+
115+ return TourResponse (items = items)
109116 }
110117}
0 commit comments