WEB实时推送消息的7种方式

目录

1. 轮询(Polling)

2. 长轮询(Long Polling)

3. Server-Sent Events(SSE)

4. WebSocket

5. STOMP over WebSocket

6. MQTT(Message Queuing Telemetry Transport)

7. Redis Pub/Sub


在 Web 开发中,实时推送消息是一个常见的需求,以下为你介绍 Java 实现 Web 实时推送消息的 7 种方式:

1. 轮询(Polling)

解释:客户端定时向服务器发送请求,检查是否有新消息。这种方式简单但效率低,会产生大量不必要的请求。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Polling Example</title>
</head>
<body>
    <div id="messages"></div>
    <script>
        function poll() {
            fetch('/messages')
              .then(response => response.text())
              .then(data => {
                    document.getElementById('messages').innerHTML = data;
                    setTimeout(poll, 5000); // 每5秒轮询一次
                });
        }
        poll();
    </script>
</body>
</html>
  • 后端(Spring Boot)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MessageController {
    @GetMapping("/messages")
    public String getMessages() {
        // 模拟返回消息
        return "New message at " + System.currentTimeMillis();
    }
}

2. 长轮询(Long Polling)

解释:客户端向服务器发送请求,服务器如果没有新消息则保持连接,直到有新消息或超时,然后返回消息,客户端收到消息后再发起新的请求。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Long Polling Example</title>
</head>
<body>
    <div id="messages"></div>
    <script>
        function longPoll() {
            fetch('/long-poll')
              .then(response => response.text())
              .then(data => {
                    document.getElementById('messages').innerHTML = data;
                    longPoll(); // 收到消息后再次发起请求
                });
        }
        longPoll();
    </script>
</body>
</html>
  • 后端(Spring Boot)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class LongPollingController {
    @GetMapping("/long-poll")
    public String longPoll() {
        try {
            // 模拟等待新消息
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "New message after long poll";
    }
}

3. Server-Sent Events(SSE)

解释:服务器可以向客户端发送实时更新,客户端使用EventSource对象监听服务器发送的事件。SSE 是单向通信,只能服务器向客户端发送消息。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Example</title>
</head>
<body>
    <div id="messages"></div>
    <script>
        const eventSource = new EventSource('/sse');
        eventSource.onmessage = function(event) {
            document.getElementById('messages').innerHTML += event.data + '<br>';
        };
    </script>
</body>
</html>
  • 后端(Spring Boot)
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
public class SSEController {
    @GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<Integer>> streamEvents() {
        AtomicInteger counter = new AtomicInteger(0);
        return Flux.interval(Duration.ofSeconds(1))
               .map(seq -> ServerSentEvent.<Integer>builder()
                       .data(counter.incrementAndGet())
                       .build());
    }
}

4. WebSocket

解释:WebSocket 是一种双向通信协议,允许浏览器和服务器之间进行实时通信。建立连接后,双方可以随时发送消息。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Example</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput">
    <button onclick="sendMessage()">Send</button>
    <script>
        const socket = new WebSocket('ws://localhost:8080/ws');
        socket.onmessage = function(event) {
            document.getElementById('messages').innerHTML += event.data + '<br>';
        };
        function sendMessage() {
            const message = document.getElementById('messageInput').value;
            socket.send(message);
        }
    </script>
</body>
</html>
  • 后端(Spring Boot)
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class WebSocketHandler extends TextWebSocketHandler {
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        String payload = message.getPayload();
        session.sendMessage(new TextMessage("Server received: " + payload));
    }
}

5. STOMP over WebSocket

解释:STOMP(Simple Text Oriented Messaging Protocol)是一个简单的文本消息协议,基于 WebSocket 提供更高级的消息传递功能,如消息队列、主题订阅等。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>STOMP over WebSocket Example</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput">
    <button onclick="sendMessage()">Send</button>
    <script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@6.1.2/bundles/stomp.umd.min.js"></script>
    <script>
        const socket = new WebSocket('ws://localhost:8080/stomp');
        const client = Stomp.over(socket);
        client.connect({}, function(frame) {
            client.subscribe('/topic/messages', function(message) {
                document.getElementById('messages').innerHTML += message.body + '<br>';
            });
        });
        function sendMessage() {
            const message = document.getElementById('messageInput').value;
            client.send('/app/send', {}, message);
        }
    </script>
</body>
</html>
  • 后端(Spring Boot)
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/stomp").withSockJS();
    }
}

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class StompController {
    @MessageMapping("/send")
    @SendTo("/topic/messages")
    public String handleMessage(String message) {
        return "Server received: " + message;
    }
}

6. MQTT(Message Queuing Telemetry Transport)

解释:MQTT 是一种轻量级的消息传输协议,适用于低带宽、不稳定网络环境。客户端可以订阅主题,服务器向订阅者推送消息。
代码示例

  • 前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MQTT Example</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput">
    <button onclick="sendMessage()">Send</button>
    <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
    <script>
        const client = mqtt.connect('ws://localhost:1884');
        client.subscribe('test/topic');
        client.on('message', function(topic, message) {
            document.getElementById('messages').innerHTML += message.toString() + '<br>';
        });
        function sendMessage() {
            const message = document.getElementById('messageInput').value;
            client.publish('test/topic', message);
        }
    </script>
</body>
</html>
  • 后端(Java)
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class MQTTServer {
    public static void main(String[] args) {
        String broker = "tcp://localhost:1883";
        String clientId = "JavaServer";
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(true);
            sampleClient.connect(connOpts);
            sampleClient.subscribe("test/topic");
            sampleClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("Connection lost: " + cause.getMessage());
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    System.out.println("Received message: " + new String(message.getPayload()));
                    // 可以在这里进行消息处理和推送
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    System.out.println("Delivery complete");
                }
            });
        } catch (MqttException me) {
            me.printStackTrace();
        }
    }
}

7. Redis Pub/Sub

解释:Redis 的发布 / 订阅机制允许客户端订阅频道,发布者向频道发布消息,订阅者会收到消息。
代码示例

  • 后端(Spring Boot)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.stereotype.Service;

@Service
public class RedisMessagePublisher {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ChannelTopic topic;

    public void publish(String message) {
        redisTemplate.convertAndSend(topic.getTopic(), message);
    }
}

@Service
public class RedisMessageSubscriber implements MessageListener {
    @Override
    public void onMessage(Message message, byte[] pattern) {
        System.out.println("Received message: " + new String(message.getBody()));
        // 可以在这里进行消息处理和推送
    }
}

以上就是 Java 实现 Web 实时推送消息的 7 种方式,你可以根据具体的业务需求选择合适的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪九天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值