一般通常情况下,我们都是前端主动朝后端发送请求,那么有没有可能,后端主动给前端推送消息呢?这时候就可以借助websocket来实现。下面给出一个简单的实现样例。
首先创建一个websocketDemo工程,该工程的整体结构如下:
(1)修改POM文件,增加相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>websocketDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
</project>
(2)新增application.properties文件,增加端口配置信息,并设置端口为8085
server.port=8085
(3)新增socket处理器MyWebSocketHandler
package com.mycompany.handler;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
System.out.println("连接建立");
sessions.put(session.getId(), session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
System.out.println("连接关闭");
sessions.remove(session.getId());
}
public void sendToAll(String message) {
sessions.forEach((id, session) -> {
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage(message));
} catch (Exception e) {
System.out.println("出现异常,原因" + e);
sessions.remove(id);
}
} else {
sessions.remove(id);
}
});
}
}
(5)新增socket配置类
package com.mycompany.config;
import com.mycompany.handler.MyWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {
@Autowired
private MyWebSocketHandler myWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/ws")
.setAllowedOrigins("*");
}
}
(6)新增控制器类,我们编写了一个接口,用来触发推消息的功能,也就当调用/api/push接口时,就会给浏览器推送消息,推送的消息内容为msg字段的值
package com.mycompany.controller;
import com.mycompany.handler.MyWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushController {
@Autowired
private MyWebSocketHandler myWebSocketHandler;
@GetMapping("/api/push")
public String push(String msg) {
myWebSocketHandler.sendToAll(msg);
return "推送成功";
}
}
(7)编写启动类WebsocketApplication
package com.mycompany;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebsocketApplication {
public static void main(String[] args) {
SpringApplication.run(WebsocketApplication.class, args);
}
}
(8)编写一个index.html页面,注意其中的端口需要和application.properties中的端口保持一致
<!DOCTYPE html>
<script>
const socket = new WebSocket('ws://localhost:8085/ws');
socket.onmessage = (e) => {
console.log('收到推送:', e.data);
document.getElementById('msg').innerHTML += e.data + '<br>';
};
</script>
<div id="msg"></div>
(9)验证测试。首先启动项目WebsocketApplication,然后通过浏览器打开index.html页面
然后我们在浏览器地址栏输入localhost:8085/api/push?msg=你好呀,然后我们会看到浏览器中的index.html页面会显示收到推送的内容。我们可以多次刷新/api/push接口,然后会看到index.html页面也打印多次推送的信息,如下图。