๐Ÿ“Œ SpringBoot + ๊ธฐ์ƒ์ฒญ ์ดˆ๋‹จ๊ธฐ์‹คํ™ฉ API ์—ฐ๋™ (RestTemplate + Thymeleaf)

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

SPRING BOOT

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

๐Ÿ“… 2025-05-09

๐Ÿ“ ํ•™์Šต ๋‚ด์šฉ

  • RESTful API ๊ฐœ๋… ์ •๋ฆฌ
  • ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ API ์‹ ์ฒญ ๋ฐ ์ธ์ฆํ‚ค ์‚ฌ์šฉ
  • ๊ธฐ์ƒ์ฒญ ์ดˆ๋‹จ๊ธฐ์‹คํ™ฉ API ํ˜ธ์ถœ
  • JSON ์‘๋‹ต ๊ตฌ์กฐ ํ™•์ธ โ†’ Java DTO ํด๋ž˜์Šค ์ž๋™ ์ƒ์„ฑ
  • ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ: Thymeleaf ๋ทฐ ์—ฐ๋™

โœ… 1. RESTful API๋ž€?

  • REST: ์ž์›์„ URI๋กœ ํ‘œํ˜„ํ•˜๊ณ , HTTP ๋ฉ”์„œ๋“œ๋กœ ์กฐ์ž‘ํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ
  • RESTful API๋Š” REST ์›์น™์„ ์ง€ํ‚จ API
    • GET: ์กฐํšŒ
    • POST: ์ƒ์„ฑ
    • PUT: ์ˆ˜์ •
    • DELETE: ์‚ญ์ œ

โœ… 2. ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ์—์„œ API ์‹ ์ฒญ ๋ฐ ์ธ์ฆํ‚ค ํ™•์ธ

  • ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ์—์„œ โ€œ๊ธฐ์ƒ์ฒญ ์ดˆ๋‹จ๊ธฐ์‹คํ™ฉโ€ ๊ฒ€์ƒ‰ ํ›„ ์‹ ์ฒญ
  • ๋ฐœ๊ธ‰๋œ serviceKey๋Š” ๋ฐ˜๋“œ์‹œ ๋””์ฝ”๋”ฉ๋œ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ
์˜ˆ์‹œ ๋””์ฝ”๋”ฉ ํ‚ค:
xYZ80mMcU8S57mCCY/q8sRsk7o7G8NtnfnK7mVEuVxdtozrl0skuhvNf34epviHrru/jiRQ41FokE9H4lK0Hhg==

โ— ๋””์ฝ”๋”ฉํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ž˜ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:

<returnAuthMsg>SERVICE_KEY_IS_NOT_REGISTERED_ERROR</returnAuthMsg>

โœ… 3. Gradle ์˜์กด์„ฑ ์ถ”๊ฐ€

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.19.0'
}

โœ… 4. JSON ์‘๋‹ต ๊ตฌ์กฐ ํ™•์ธ ๋ฐ Java ํด๋ž˜์Šค ์ž๋™ ์ƒ์„ฑ

๐Ÿ”Ž Step 1: ์ฝ˜์†”์—์„œ JSON ์‘๋‹ต ํ™•์ธ

{
  "response": {
    "header": { "resultCode": "00", "resultMsg": "NORMAL_SERVICE" },
    "body": {
      "dataType": "JSON",
      "items": {
        "item": [
          {
            "baseDate": "20250509",
            "baseTime": "1600",
            "category": "PTY",
            "nx": 89,
            "ny": 90,
            "obsrValue": "0"
          }
        ]
      },
      "pageNo": 1,
      "numOfRows": 10,
      "totalCount": 8
    }
  }
}

๐Ÿ”„ Step 2: JSON โ†’ Java ์ž๋™ ๋ณ€ํ™˜

๊ฒฐ๊ณผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ํด๋ž˜์Šค๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋จ ๐Ÿ‘‡

@Data
private static class Item {
    public String baseDate;
    public String baseTime;
    public String category;
    public int nx;
    public int ny;
    public String obsrValue;
}
@Data private static class Items { public ArrayList<Item> item; }
@Data private static class Body { public String dataType; public Items items; public int pageNo; public int numOfRows; public int totalCount; }
@Data private static class Header { public String resultCode; public String resultMsg; }
@Data private static class Response { public Header header; public Body body; }
@Data private static class Root { public Response response; }

๐Ÿ“Œ ์ด ๊ณผ์ •์„ ํ†ตํ•ด RestTemplate์œผ๋กœ ๋ฐ›์€ JSON์„ ์ž๋™์œผ๋กœ Java ๊ฐ์ฒด๋กœ ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์Œ.


โœ… 5. API ํ˜ธ์ถœ ๋ฐ JSON ํŒŒ์‹ฑ

String fullUrl = ...; // ์œ„์—์„œ ๋งŒ๋“  URL

RestTemplate rt = new RestTemplate();
ResponseEntity<Root> response = rt.exchange(fullUrl, HttpMethod.GET, null, Root.class);

โœ… 6. ๋ฐ์ดํ„ฐ ์ถ”์ถœ

Root root = response.getBody();
Response rs = root.getResponse();
Body body = rs.getBody();
Items items = body.getItems();
List<Item> list = items.getItem();

list.forEach(item -> log.info(item.toString()));

โœ… 7. Thymeleaf๋กœ ๋ทฐ์—์„œ ์ถœ๋ ฅ

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>๋Œ€๊ตฌ ๋‚ ์”จ</title>
</head>
<body>
<h1>๐ŸŒค ๋Œ€๊ตฌ ์ค‘๊ตฌ ๋‚ ์”จ ์‹ค์‹œ๊ฐ„ ์กฐํšŒ</h1>
<hr/>
<th:block th:each="item : ${list}">
    <div>๋‚ ์งœ: <span th:text="${item.baseDate}"></span></div>
    <div>์‹œ๊ฐ„: <span th:text="${item.baseTime}"></span></div>
    <div>ํ•ญ๋ชฉ: <span th:text="${item.category}"></span></div>
    <div>X์ขŒํ‘œ: <span th:text="${item.nx}"></span></div>
    <div>Y์ขŒํ‘œ: <span th:text="${item.ny}"></span></div>
    <div>๊ด€์ธก๊ฐ’: <span th:text="${item.obsrValue}"></span></div>
    <br/>
</th:block>
</body>
</html>

โœ… 8. ์ตœ์ข… Controller ์ „์ฒด ์ฝ”๋“œ

@Controller
@Slf4j
@RequestMapping("/openData")
public class OpenData02Controller {

    String url = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst";
    String serviceKey = "๋””์ฝ”๋”ฉ๋œ_ํ‚ค_์ž…๋ ฅ";

    @GetMapping("/forcast")
    public void forcast(Model model) {
        String fullUrl = url
            + "?serviceKey=" + serviceKey
            + "&pageNo=1"
            + "&numOfRows=10"
            + "&&base_date=20250509"
            + "&base_time=1600"
            + "&dataType=JSON"
            + "&nx=89"
            + "&ny=90";

        RestTemplate rt = new RestTemplate();
        ResponseEntity<Root> response = rt.exchange(fullUrl, HttpMethod.GET, null, Root.class);

        List<Item> list = response.getBody().getResponse().getBody().getItems().getItem();
        model.addAttribute("list", list);
    }

    // DTO ํด๋ž˜์Šค ์ƒ๋žต: ์œ„ ์ •์˜ ์ฐธ๊ณ 
}

๐Ÿ”ฅ ์ •๋ฆฌ ์š”์•ฝ

ํ•ญ๋ชฉ์„ค๋ช…
๐Ÿ”‘ ์ธ์ฆํ‚ค๋ฐ˜๋“œ์‹œ ๋””์ฝ”๋”ฉ๋œ ํ˜•ํƒœ ์‚ฌ์šฉ
โœ… JSON ๊ตฌ์กฐ์ฝ˜์†” ํ™•์ธ ํ›„ jsonschema2pojo๋กœ ๋ณ€ํ™˜
๐Ÿ” RestTemplateexchange + DTO ๋งคํ•‘์œผ๋กœ ์ฒ˜๋ฆฌ
๐Ÿงฉ Thymeleaf๋ฆฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ th:each๋กœ ์ถœ๋ ฅ

๐Ÿ”— ์ฐธ๊ณ  ๋งํฌ


profile
Here, My Pale Blue.๐ŸŒ

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