DEV Community

DevCorner2
DevCorner2

Posted on

Server Sent Event

Below is a step-by-step guide to creating a complete Spring Boot project using SSE (Server-Sent Events) to stream real-time updates (like stock prices). This example includes:

  • Project setup
  • Backend code with Spring Boot
  • SSE streaming endpoint
  • Frontend (HTML + JS) for consuming the stream
  • Optional enhancements

āœ… 1. Project Setup

šŸ› ļø Using Spring Initializr

Go to https://start.spring.io and generate a project with the following settings:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.x or higher
  • Dependencies:

    • Spring Web
    • Spring Boot DevTools (optional, for hot reload)

Click "Generate" to download the zip and extract it.


šŸ“ 2. Directory Structure

sse-streaming-stock/
ā”œā”€ā”€ src/
│   ā”œā”€ā”€ main/
│   │   ā”œā”€ā”€ java/
│   │   │   └── com/example/sse/
│   │   │       ā”œā”€ā”€ SseStreamingStockApplication.java
│   │   │       └── controller/StockPriceController.java
│   │   └── resources/
│   │       ā”œā”€ā”€ static/
│   │       │   └── index.html
│   │       └── application.properties
ā”œā”€ā”€ pom.xml
Enter fullscreen mode Exit fullscreen mode

šŸ“¦ 3. Backend Code

šŸ”¹ SseStreamingStockApplication.java

package com.example.sse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SseStreamingStockApplication {
    public static void main(String[] args) {
        SpringApplication.run(SseStreamingStockApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

šŸ”¹ controller/StockPriceController.java

package com.example.sse.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.time.LocalTime;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RestController
public class StockPriceController {

    private final Random random = new Random();

    @GetMapping("/stream-stocks")
    public SseEmitter streamStockPrices() {
        SseEmitter emitter = new SseEmitter(0L); // never timeout
        ExecutorService executor = Executors.newSingleThreadExecutor();

        executor.execute(() -> {
            try {
                int id = 0;
                while (true) {
                    double price = 150 + random.nextDouble() * 10;
                    String symbol = "AAPL";
                    String time = LocalTime.now().toString();

                    String json = String.format(
                        "{\"symbol\": \"%s\", \"price\": %.2f, \"time\": \"%s\"}",
                        symbol, price, time
                    );

                    emitter.send(SseEmitter.event()
                        .id(String.valueOf(id++))
                        .name("stock-update")
                        .data(json));

                    Thread.sleep(1000);
                }
            } catch (IOException | InterruptedException e) {
                emitter.completeWithError(e);
            }
        });

        return emitter;
    }
}
Enter fullscreen mode Exit fullscreen mode

🌐 4. Frontend Code (Client)

šŸ”¹ src/main/resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stock Price Stream</title>
    <style>
        body { font-family: Arial; padding: 20px; }
        .stock { font-size: 20px; color: green; }
    </style>
</head>
<body>
    <h1>Live Stock Price (SSE)</h1>
    <div id="stock" class="stock">Waiting for updates...</div>

    <script>
        const eventSource = new EventSource('/stream-stocks');

        eventSource.addEventListener("stock-update", (event) => {
            const data = JSON.parse(event.data);
            document.getElementById("stock").innerText = 
                `Symbol: ${data.symbol} | Price: $${data.price.toFixed(2)} | Time: ${data.time}`;
        });

        eventSource.onerror = () => {
            document.getElementById("stock").innerText = "Connection lost.";
        };
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

āš™ļø 5. application.properties

# Prevent request timeout for long-lived SSE connections
server.servlet.context-path=/
spring.mvc.async.request-timeout=0
Enter fullscreen mode Exit fullscreen mode

ā–¶ļø 6. Run the Project

From the terminal, run:

./mvnw spring-boot:run
Enter fullscreen mode Exit fullscreen mode

Then open http://localhost:8080 in your browser. You should see real-time stock price updates every second.


🧠 Optional Enhancements

  • Stream multiple stock symbols
  • Add endpoint to subscribe to specific symbols
  • Integrate real stock market API (e.g., Alpha Vantage, IEX Cloud)
  • Use Flux + WebFlux for reactive SSE (instead of MVC)
  • Broadcast to multiple clients with SseEmitters list
  • Handle reconnections and missed events

Would you like a version using Spring WebFlux or a version with real stock data next?

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.