อัปเดตค่าเงินบาทแบบเรียลไทม์ด้วย Spring Boot + SSE + Frankfurter API




🔎 Frankfurter คืออะไร?

Frankfurter.app
เป็นบริการ ฟรี ที่ให้ข้อมูล อัตราแลกเปลี่ยนสกุลเงินรายวัน (Exchange Rates)
โดยดึงข้อมูลจาก ธนาคารกลางยุโรป (European Central Bank)

จุดเด่นคือ:

  • ✅ ใช้งานฟรี ไม่ต้องสมัคร ไม่ต้องมี API key

  • ✅ รองรับหลายสกุลเงิน เช่น USD, THB, EUR, JPY

  • ✅ ได้ข้อมูลในรูปแบบ JSON อ่านง่าย

  • ✅ เหมาะสำหรับการทดสอบ หรือทำโปรเจกต์สาธิต

ตัวอย่างการเรียก API:

https://api.frankfurter.app/latest?from=USD&to=THB

ผลลัพธ์ที่ได้:

{ "amount": 1.0, "base": "USD", "date": "2025-10-15", "rates": { "THB": 36.74 } }

หมายความว่า “1 ดอลลาร์สหรัฐ (USD) = 36.74 บาท (THB)”


🧭 เป้าหมายของเรา

เราจะสร้างเว็บเล็ก ๆ ที่ แสดงค่าเงินบาทแบบเรียลไทม์
โดยไม่ต้องกด refresh เอง
แนวคิดคือใช้เทคโนโลยีที่ชื่อว่า SSE (Server-Sent Events)
ซึ่งจะให้ฝั่ง Server ส่งข้อมูลใหม่มาที่หน้าเว็บโดยอัตโนมัติ


⚙️ เครื่องมือที่ใช้

เครื่องมือหน้าที่
Spring Bootสร้าง backend ที่ดึงค่าเงินบาทจาก API
SSE (Server-Sent Events)ส่งข้อมูลจาก server ไปหน้าเว็บแบบเรียลไทม์
HTML + JavaScriptแสดงผลข้อมูลบนหน้าเว็บ
Frankfurter APIแหล่งข้อมูลค่าเงิน (USD → THB)

📁 โครงสร้างโปรเจกต์

realtime-baht/ ├─ src/ ├─ main/ ├─ java/com/example/baht/ ├─ controller/CurrencyController.java ├─ service/CurrencyService.java └─ RealtimeBahtApplication.java └─ resources/ ├─ static/index.html 👈 หน้าเว็บ └─ application.yaml 👈 การตั้งค่า └─ pom.xml

🧩 ขั้นตอนที่ 1 — เขียน Service ดึงข้อมูลจาก Frankfurter

package com.example.baht.service; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; import java.util.*; import java.util.concurrent.*; @Service public class CurrencyService { private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>(); private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public CurrencyService() { // ส่งข้อมูลทุก 10 วินาที scheduler.scheduleAtFixedRate(this::broadcastRate, 0, 10, TimeUnit.SECONDS); } public void addEmitter(SseEmitter emitter) { emitters.add(emitter); emitter.onCompletion(() -> emitters.remove(emitter)); emitter.onTimeout(() -> emitters.remove(emitter)); } private void broadcastRate() { Double rate = fetchUsdToThb(); if (rate == null) return; for (SseEmitter emitter : emitters) { try { emitter.send(SseEmitter.event() .name("baht-update") .data(rate)); } catch (IOException e) { emitters.remove(emitter); } } } private Double fetchUsdToThb() { try { RestTemplate restTemplate = new RestTemplate(); String url = "https://api.frankfurter.app/latest?from=USD&to=THB"; Map<?, ?> response = restTemplate.getForObject(url, Map.class); Map<String, Double> rates = (Map<String, Double>) response.get("rates"); return rates.get("THB"); } catch (Exception e) { System.err.println("Error fetching rate: " + e.getMessage()); return null; } } }

✅ ส่วนนี้คือหัวใจของระบบ

  • ดึงค่าเงินบาทจาก Frankfurter API

  • ส่งข้อมูลออกทาง SseEmitter ให้กับทุก Client


🧩 ขั้นตอนที่ 2 — เขียน Controller สำหรับเปิด Stream

package com.example.baht.controller; import org.springframework.web.bind.annotation.*; import org.springframework.http.MediaType; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.beans.factory.annotation.Autowired; import com.example.baht.service.CurrencyService; @RestController @RequestMapping("/api") public class CurrencyController { @Autowired private CurrencyService currencyService; @GetMapping(value = "/baht/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter streamBaht() { SseEmitter emitter = new SseEmitter(0L); // ไม่ timeout currencyService.addEmitter(emitter); return emitter; } }

Endpoint /api/baht/stream จะเปิดช่องทาง “ถ่ายทอดสด”
เมื่อมีข้อมูลใหม่ Spring จะส่งให้ browser โดยอัตโนมัติ


🧩 ขั้นตอนที่ 3 — สร้างหน้าเว็บ index.html

วางไฟล์นี้ใน
src/main/resources/static/index.html

<!DOCTYPE html> <html lang="th"> <head> <meta charset="UTF-8"> <title>Realtime ค่าเงินบาท</title> </head> <body> <h2>💵 ค่าเงินบาท (USD → THB)</h2> <div>อัตราปัจจุบัน: <span id="rate">--</span></div> <script> const source = new EventSource("/api/baht/stream"); source.addEventListener("baht-update", (event) => { document.getElementById("rate").textContent = parseFloat(event.data).toFixed(2); }); source.onerror = () => console.log("❌ Lost connection..."); </script> </body> </html>

เปิดหน้าเว็บที่ http://localhost:8080
คุณจะเห็นตัวเลขค่าเงินบาทเปลี่ยนเองทุก 10 วินาที 🎯


⚙️ ขั้นตอนที่ 4 — ตั้งค่าใน application.yaml

ไฟล์นี้อยู่ที่ src/main/resources/application.yaml

server: port: 8080 # พอร์ตของแอป servlet: context-path: / spring: mvc: async: request-timeout: -1 # ปิด timeout ของ SSE connection

อธิบายสั้น ๆ:

  • port → ระบุพอร์ตที่ Spring Boot จะรัน

  • request-timeout: -1 → ปิดระบบตัดการเชื่อมต่ออัตโนมัติ (จำเป็นสำหรับ SSE)


🧠 การทำงานโดยรวม

  1. Spring Boot รันขึ้นมาบนพอร์ต 8080

  2. หน้าเว็บเปิดการเชื่อมต่อผ่าน EventSource("/api/baht/stream")

  3. Backend เรียกข้อมูลจาก Frankfurter API ทุก 10 วินาที

  4. ส่งอัตราแลกเปลี่ยนใหม่มายัง browser

  5. หน้าเว็บอัปเดตตัวเลขอัตโนมัติ โดยไม่ต้อง refresh


🎯 สรุปข้อดีของวิธีนี้

หัวข้อจุดเด่น
🔄 SSE (Server-Sent Events)สื่อสารแบบ “ทางเดียวจาก Server → Client” เหมาะกับข้อมูลอัปเดตต่อเนื่อง
🌐 Frankfurter APIฟรี, ไม่ต้องสมัคร, JSON เข้าใจง่าย
⚙️ Spring Bootเขียน backend ได้สะดวก มี SseEmitter รองรับในตัว
🧩 HTML + JSใช้เพียง EventSource ก็รับข้อมูลเรียลไทม์ได้ทันที

💬 สรุปสั้น ๆ

“Frankfurter.app” ช่วยให้เราเข้าถึงข้อมูลอัตราแลกเปลี่ยนฟรี
เมื่อรวมกับ “Spring Boot + SSE” ก็สามารถสร้างระบบ
“อัปเดตค่าเงินบาทแบบเรียลไทม์” ได้ง่ายภายในไม่กี่ไฟล์เท่านั้น 🎉

ความคิดเห็น

โพสต์ยอดนิยมจากบล็อกนี้