๐Ÿ“Œ [SpringBoot] ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ XML API ์—ฐ๋™ ์‹ค์Šต - ์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค ์ •๋ณด

My Pale Blue Dotยท2025๋…„ 5์›” 12์ผ

SPRING BOOT

๋ชฉ๋ก ๋ณด๊ธฐ
13/40
post-thumbnail

๐Ÿ“… 2025-05-12


โœ… ์‹ค์Šต ๊ฐœ์š”

  • ์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค ๋„์ฐฉ์ •๋ณด OpenAPI(XML)๋ฅผ Spring Boot์—์„œ ํ˜ธ์ถœ
  • JAXB๋กœ XML์„ Java ๊ฐ์ฒด๋กœ ์ž๋™ ๋ณ€ํ™˜
  • RestTemplate์„ ์ด์šฉํ•œ ์™ธ๋ถ€ API ํ†ต์‹ 
  • JSON ์ถœ๋ ฅ ๋ฐ ์ฝ˜์†” ์ถœ๋ ฅ ๋ฐฉ์‹ ์‹ค์Šต
  • ํ–ฅํ›„ CSV ์—ฐ๊ณ„ ๋ฐ DB ์ €์žฅ ํ™•์žฅ ๊ฐ€๋Šฅ

โœ… ์‹ค์Šต ์ˆœ์„œ ์š”์•ฝ

๋‹จ๊ณ„์„ค๋ช…
1๏ธโƒฃํ”„๋กœ์ ํŠธ ์ƒ์„ฑ (Web + JAXB + Lombok ํฌํ•จ)
2๏ธโƒฃAPI ํ‚ค ๋ฐœ๊ธ‰ (๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ)
3๏ธโƒฃXML ๊ตฌ์กฐ ๋ถ„์„
4๏ธโƒฃJava ํด๋ž˜์Šค (JAXB) ์ž‘์„ฑ
5๏ธโƒฃ์ปจํŠธ๋กค๋Ÿฌ ๊ตฌ์„ฑ ๋ฐ ์š”์ฒญ ์ˆ˜ํ–‰
6๏ธโƒฃ์‘๋‹ต ๊ฒฐ๊ณผ ์ฝ˜์†” ์ถœ๋ ฅ / JSON ๋ฐ˜ํ™˜
7๏ธโƒฃ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ ํ–ฅํ›„ ํ™•์žฅ ์„ค๋ช… ํฌํ•จ

โœ… ์‚ฌ์šฉ API ์ •๋ณด

  • ์„œ๋น„์Šค: ๋Œ€๊ตฌ๊ด‘์—ญ์‹œ ์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค ๋„์ฐฉ์ •๋ณด
  • ํ˜ธ์ถœ URL:
https://apis.data.go.kr/6270000/dbmsapi01/getRealtime
?serviceKey=๋ฐœ๊ธ‰๋ฐ›์€ํ‚ค
&bsId=7001001600
&routeNo=649
  • ๐Ÿ“Œ ์˜ˆ์‹œ ์ž…๋ ฅ๊ฐ’:
    • routeNo = 649 โ†’ ์„œ๋ถ€์ •๋ฅ˜์žฅ ๋ฐฉ๋ฉด
    • bsId = 7001001600 โ†’ ๋Œ€๊ตฌ๊ณ ๋“ฑํ•™๊ต๊ฑด๋„ˆ ์ •๋ฅ˜์žฅ

โœ… 1. ์˜์กด์„ฑ ์„ค์ • (build.gradle)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0'
    implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.2'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

โœ… 2. XML ์‘๋‹ต ๋งคํ•‘ ํด๋ž˜์Šค (BUSResult.java)

@XmlRootElement(name = "Result")
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class BUSResult {

    private Header header;
    private Body body;

    @Data
    public static class Header {
        private boolean success;
        private String resultCode;
        private String resultMsg;
    }

    @Data
    public static class Body {
        private Items items;
        private int totalCount;
    }

    @Data
    public static class Items {
        private String routeNo;

        @XmlElementWrapper(name = "arrList")
        @XmlElement(name = "arrList")
        private List<ArrList> arrList;
    }

    @Data
    public static class ArrList {
        private String routeId;
        private String routeNo;
        private int moveDir;
        private int bsGap;
        private String bsNm;
        private String vhcNo2;
        private String busTCd2;
        private String busTCd3;
        private String busAreaCd;
        private String arrState;
        private int prevBsGap;
    }
}

โœ… 3. ์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค ์ •๋ณด ์ปจํŠธ๋กค๋Ÿฌ (OpenData03Controller.java)

@RestController
@Slf4j
@RequestMapping("/openData")
public class OpenData03Controller {

    // ์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค ๋„์ฐฉ์ •๋ณด ์ฝ˜์†” ์ถœ๋ ฅ
    @GetMapping("/bus/realtime")
    public void bus_realtime() throws UnsupportedEncodingException {
        try {
            BUSResult result = fetchBusData();
            if (result != null) {
                // ์ฝ˜์†”์— ์ •๋ฅ˜์†Œ ๋„์ฐฉ ์ •๋ณด ์ถœ๋ ฅ
                result.getBody().getItems().getArrList().forEach(bus -> {
                    System.out.println("์ •๋ฅ˜์žฅ๋ช…: " + bus.getBsNm());
                    System.out.println("๋„์ฐฉ์˜ˆ์ •: " + bus.getArrState());
                    System.out.println("์ฐจ๋Ÿ‰๋ฒˆํ˜ธ: " + bus.getVhcNo2());
                    System.out.println("--------------------------");
                });
            } else {
                log.warn("์‘๋‹ต ๋ณธ๋ฌธ์ด null์ž…๋‹ˆ๋‹ค.");
            }
        } catch (Exception e) {
            log.error("์‹ค์‹œ๊ฐ„ ๋ฒ„์Šค API ํ˜ธ์ถœ ์‹คํŒจ", e);
        }
    }

    // JSON API๋กœ ์‘๋‹ต ๋ฐ˜ํ™˜
    @GetMapping("/bus/json")
    public ResponseEntity<BUSResult> bus_json() throws UnsupportedEncodingException {
        try {
            BUSResult result = fetchBusData();
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    // ๊ณตํ†ต ํ˜ธ์ถœ ๋กœ์ง ๋ถ„๋ฆฌ
    private BUSResult fetchBusData() throws UnsupportedEncodingException {
        String url = "https://apis.data.go.kr/6270000/dbmsapi01/getRealtime";
        String serviceKey = "๋ฐœ๊ธ‰๋ฐ›์€ ๋””์ฝ”๋”ฉ ํ‚ค";
        String bsId = "7001001600";
        String routeNo = "649";

        URI uri = UriComponentsBuilder
                .fromHttpUrl(url)
                .queryParam("serviceKey", URLEncoder.encode(serviceKey, "UTF-8"))
                .queryParam("bsId", bsId)
                .queryParam("routeNo", routeNo)
                .build(true)
                .toUri();

        RestTemplate rt = new RestTemplate();
        ResponseEntity<BUSResult> response = rt.exchange(uri, HttpMethod.GET, null, BUSResult.class);
        return response.getBody();
    }
}

โœ… 4. ์‹คํ–‰ ๊ฒฐ๊ณผ ์˜ˆ์‹œ

ํ˜ธ์ถœ ์ฃผ์†Œ

http://localhost:8090/openData/bus/realtime

์ฝ˜์†” ์ถœ๋ ฅ ๊ฒฐ๊ณผ

์ •๋ฅ˜์žฅ๋ช…: ๋Œ€๊ตฌ๊ณ ๋“ฑํ•™๊ต๊ฑด๋„ˆ
๋„์ฐฉ์˜ˆ์ •: 7๋ถ„
์ฐจ๋Ÿ‰๋ฒˆํ˜ธ: 5266
--------------------------
์ •๋ฅ˜์žฅ๋ช…: ์„œ๋ถ€์ •๋ฅ˜์žฅ(๊ด€๋ฌธ์‹œ์žฅ์•ž)
๋„์ฐฉ์˜ˆ์ •: 18๋ถ„
์ฐจ๋Ÿ‰๋ฒˆํ˜ธ: 5214
--------------------------

JSON API ํ˜ธ์ถœ ์˜ˆ์‹œ

http://localhost:8090/openData/bus/json

โœ… 5. ํ–ฅํ›„ ํ™•์žฅ ์•„์ด๋””์–ด

ํ™•์žฅ ๋ฐฉํ–ฅ์„ค๋ช…
โœ… ํ™”๋ฉด ์ถœ๋ ฅThymeleaf, React ์—ฐ๋™์œผ๋กœ ๋ฆฌ์ŠคํŠธ UI ๊ตฌ์„ฑ
โœ… DB ์ €์žฅJPA๋ฅผ ์ด์šฉํ•ด ์ •๋ฅ˜์†Œ ๋„์ฐฉ ์ •๋ณด ์˜์†ํ™”
โœ… CSV ์—ฐ๊ณ„๊ณต๊ณต๋ฐ์ดํ„ฐ ํฌํ„ธ์—์„œ ๋‹ค์šด๋ฐ›์€ ๋…ธ์„ /์ •๋ฅ˜์†Œ ์œ„์น˜ CSV ํŒŒ์ผ๊ณผ ์—ฐ๊ณ„ํ•˜์—ฌ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ ํ™œ์šฉ
โœ… ์ž๋™ํ™”์ผ์ • ๊ฐ„๊ฒฉ์œผ๋กœ ๋„์ฐฉ์ •๋ณด ๊ฐฑ์‹ ํ•˜์—ฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€