728x90
반응형
resources 폴더 안에 yml 파일에 epost-open API에 사용할 key, base url, tracking 용으로 사용할 url을 설정
project안에 client, service, dto로 나누어 .kt 파일 생성
client
package net.batch.external.client
import net.batch.config.FeignConfig
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
@FeignClient(name = "epostOpenClient", url = "\${epost-open.base}", configuration = [FeignConfig::class])
interface EpostOpenClient {
@GetMapping(path = ["\${epost-open.tracking}"], produces = [MediaType.APPLICATION_XML_VALUE])
fun getTracking(
@RequestParam regKey: String,
@RequestParam target: String,
@RequestParam query: String
): ResponseEntity<String>
}
service
package net.batch.external.service
import net.batch.external.client.EpostOpenClient
import net.batch.external.data.ApisDataDto
import net.batch.external.data.EpostOpenDto
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.util.*
@Service
class EpostOpenService(
@Value("\${epost-open.key}")
private val regKey: String,
private val epostOpenClient: EpostOpenClient,
) {
fun getTrackingInfo(trackingNumber: String): EpostOpenDto.EodTrackingResponse? {
return epostOpenClient.getTracking(
regKey = regKey,
target = "emsTrace",
query = trackingNumber
).body.let {
EpostOpenDto.EodTrackingResponse.of(it)
}
}
}
dto
package net.batch.external.data
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import org.jsoup.Jsoup
import org.jsoup.parser.Parser
object EpostOpenDto {
@JacksonXmlRootElement(localName = "trace")
data class EodTrackingResponse(
@field:JacksonXmlProperty(localName = "sendernm") // 발송인 이름
var sendernm: String? = null,
@field:JacksonXmlProperty(localName = "receivernm") // 수취인 이름
var receivernm: String? = null,
@field:JacksonXmlProperty(localName = "regino") // 등기번호
var regino: String? = null,
@field:JacksonXmlProperty(localName = "mailtypenm") // 국제우편물 구분
var mailtypenm: String? = null,
@field:JacksonXmlProperty(localName = "mailkindnm") // 국제우편물 종료
var mailkindnm: String? = null,
@field:JacksonXmlProperty(localName = "deliverydate") // 배달일자
var deliverydate: String? = null,
@field:JacksonXmlProperty(localName = "deliveryyn") // 배달완료 여부
var deliveryyn: String? = null,
@field:JacksonXmlProperty(localName = "signernm") // 수령인 이름
var signernm: String? = null,
@field:JacksonXmlProperty(localName = "relationnm") // 수취인과의 관계
var relationnm: String? = null,
@field:JacksonXmlProperty(localName = "connectedregino") // 연계 등기번호
var connectedregino: String? = null,
@field:JacksonXmlProperty(localName = "postmannm") // 집배원 이름
var postmannm: String? = null,
@field:JacksonXmlProperty(localName = "inboundoutboundnm") // 국내수출입 구분명
var inboundoutboundnm: String? = null,
@field:JacksonXmlProperty(localName = "recvpostzipcd") // 접수우체국 우편번호
var recvpostzipcd: String? = null,
@field:JacksonXmlProperty(localName = "recvposttelno") // 접수우체국 전화번호
var recvposttelno: String? = null,
@field:JacksonXmlProperty(localName = "destcountrycd") // 도착국가 코드
var destcountrycd: String? = null,
@field:JacksonXmlProperty(localName = "destcountrynm") // 도착국가 이름
var destcountrynm: String? = null,
@field:JacksonXmlProperty(localName = "gcdate") // 배달보장 일자
var gcdate: String? = null,
@field:JacksonXmlProperty(localName = "postimpccd") // 우체국IMPC코드
var postimpccd: String? = null,
@field:JacksonXmlProperty(localName = "receiverzipcd") // 수취인 우편번호
var receiverzipcd: String? = null,
@field:JacksonXmlProperty(localName = "customsfailednm") // 미통관 사유코드
var customsfailednm: String? = null,
@field:JacksonXmlProperty(localName = "sendcnt") // 발송횟수
var sendcnt: String? = null,
@field:JacksonXmlProperty(localName = "sendflightno") // 발송편명
var sendflightno: String? = null,
@field:JacksonXmlProperty(localName = "airdate") // 항공기 출항일시
var airdate: String? = null,
@field:JacksonXmlProperty(localName = "deliposttelno") // 배달우체국 전화번호
var deliposttelno: String? = null,
@field:JacksonXmlProperty(localName = "itemlist")
var itemList: ItemList? = null
) {
data class ItemList(
@field:JacksonXmlProperty(localName = "item")
var item: List<Item>? = null,
) {
data class Item(
@field:JacksonXmlProperty(localName = "sortingdate") // 구분 일시
var sortingdate: String? = null,
@field:JacksonXmlProperty(localName = "eventhms") // 이벤트 시간
var eventhms: String? = null,
@field:JacksonXmlProperty(localName = "eventregiponm") // 현재 위치(우체국명)
var eventregiponm: String? = null,
@field:JacksonXmlProperty(localName = "delivrsltnm") // 배달결과 상세
var delivrsltnm: String? = null,
@field:JacksonXmlProperty(localName = "nondelivreasnnm") // 미배달사유 상세
var nondelivreasnnm: String? = null,
@field:JacksonXmlProperty(localName = "eventnm") // 이벤트 이름
var eventnm: String? = null,
@field:JacksonXmlProperty(localName = "eventymd") // 이벤트 날짜
var eventymd: String? = null,
@field:JacksonXmlProperty(localName = "upucd") // UPU이벤트 코드
var upucd: String? = null,
)
}
companion object {
fun of(xml: String?): EodTrackingResponse? {
if (xml == null) return null
val doc = Jsoup.parse(xml.trimIndent(), "", Parser.xmlParser())
// trace 데이터 출력
val trace = doc.select("trace")
return EodTrackingResponse(
sendernm = trace.select("sendernm").text(),
receivernm = trace.select("receivernm").text(),
regino = trace.select("regino").text(),
mailtypenm = trace.select("mailtypenm").text(),
mailkindnm = trace.select("mailkindnm").text(),
deliverydate = trace.select("deliverydate").text(),
deliveryyn = trace.select("deliveryyn").text(),
signernm = trace.select("signernm").text(),
relationnm = trace.select("relationnm").text(),
connectedregino = trace.select("connectedregino").text(),
postmannm = trace.select("postmannm").text(),
inboundoutboundnm = trace.select("inboundoutboundnm").text(),
recvpostzipcd = trace.select("recvpostzipcd").text(),
recvposttelno = trace.select("recvposttelno").text(),
destcountrycd = trace.select("destcountrycd").text(),
destcountrynm = trace.select("destcountrynm").text(),
gcdate = trace.select("gcdate").text(),
postimpccd = trace.select("postimpccd").text(),
receiverzipcd = trace.select("receiverzipcd").text(),
customsfailednm = trace.select("customsfailednm").text(),
sendcnt = trace.select("sendcnt").text(),
sendflightno = trace.select("sendflightno").text(),
airdate = trace.select("airdate").text(),
deliposttelno = trace.select("deliposttelno").text(),
itemList = parseXML(xml)
)
}
// ItemList 안에 Item 파싱하는 부분
private fun parseXML(xml: String?): ItemList? {
if (xml == null) return null
val doc = Jsoup.parse(xml, "", Parser.xmlParser())
val items = mutableListOf<ItemList.Item>()
val elements = doc.select("item")
for (element in elements) {
val item = ItemList.Item()
item.sortingdate = element.select("sortingdate").text()
item.eventhms = element.select("eventhms").text()
item.eventregiponm = element.select("eventregiponm").text()
item.delivrsltnm = element.select("delivrsltnm").text()
item.nondelivreasnnm = element.select("nondelivreasnnm").text()
item.eventnm = element.select("eventnm").text()
item.eventymd = element.select("eventymd").text()
item.upucd = element.select("upucd").text()
items.add(item)
}
return ItemList(items)
}
}
}
}
XML 형태로 응답되어지는 데이터를 파싱하여 데이터 모델로 응답되도록 하였다.
테스트 코드를 작성하여 제대로 파싱이 되어 응답되어지는 확인
package net.batch.external.service
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
@SpringBootTest
@ActiveProfiles("local")
class EpostOpenServiceTest(
@Autowired
private val epostOpenService: EpostOpenService
) {
@Test
fun getTrackingInfo() {
val response = epostOpenService.getTrackingInfo(trackingNumber)
response
}
}
728x90
반응형
'TIL > Kotlin' 카테고리의 다른 글
[TIL/Kotlin] Junit5로 테스트 코드 작성하기 (0) | 2023.12.12 |
---|---|
[TIL/Kotlin] Kotlin, SpringBoot, JPA nativeQuery 사용시 주의사항 (0) | 2023.12.05 |
[TIL/Kotlin] 코틀린 고급문법_sealed 클래스, 위임된 프로퍼티, 클래스 위임 (0) | 2023.05.27 |
[TIL/Kotlin] 코틀린 고급문법_열거 클래스(Enum Class)와 열거 클래스에 프로퍼티와 멤버 함수 선언 및 활용하기 (0) | 2023.05.27 |
[TIL/Kotlin] 코틀린 고급문법_배열(Array)과 배열을 가변 인수로 활용하기 (0) | 2023.05.26 |