springboot 的内置 tomcat 时,就不需要引入 javaee-api 了,spring-boot 已经包含了。使用 springboot 的 websocket 功能首先引入 springboot 组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| plugins { java id("org.springframework.boot") version "2.7.9" id("io.spring.dependency-management") version "1.0.15.RELEASE" }
group = "com.example" version = "0.0.1-SNAPSHOT" java.sourceCompatibility = JavaVersion.VERSION_17
repositories { mavenCentral() }
dependencies { implementation("org.springframework.boot:spring-boot-starter-websocket") testImplementation("org.springframework.boot:spring-boot-starter-test") }
tasks.withType<Test> { useJUnitPlatform() }
|
使用 @ServerEndpoint创立websocket endpoint
首先要注入 ServerEndpointExporter,这个 bean 会自动注册使用了 @ServerEndpoint 注解声明的 Websocket endpoint。要注意,如果使用独立的 servlet 容器,而不是直接使用 springboot 的内置容器,就不要注入 ServerEndpointExporter,因为它将由容器自己提供和管理。
1 2 3 4 5 6 7 8
| @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }
}
|
接下来就是写 websocket 的具体实现类,很简单,直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| package com.example.demo;
import org.springframework.stereotype.Component;
import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = "/websocket") @Component public class MyWebSocket { private static int onlineCount = 0;
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
private Session session;
@OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); addOnlineCount(); System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); try { sendMessage("on open------------------"); } catch (IOException e) { System.out.println("IO异常"); } }
@OnClose public void onClose() { webSocketSet.remove(this); subOnlineCount(); System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); }
@OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message);
for (MyWebSocket item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } }
@OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); }
public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); }
public static void sendInfo(String message) throws IOException { for (MyWebSocket item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { continue; } } }
public static synchronized int getOnlineCount() { return onlineCount; }
public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; }
public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } }
|
3、前端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| <!DOCTYPE HTML> <html>
<head> <title>My WebSocket</title> </head>
<body> Welcome<br /> <input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> <div id="message"> </div> </body>
<script type="text/javascript"> var websocket = null; if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/websocket"); } else { alert('Not support websocket') }
websocket.onerror = function () { setMessageInnerHTML("error"); };
websocket.onopen = function (event) { setMessageInnerHTML("open"); }
websocket.onmessage = function (event) { setMessageInnerHTML(event.data); }
websocket.onclose = function () { setMessageInnerHTML("close"); }
window.onbeforeunload = function () { websocket.close(); }
function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; }
function closeWebSocket() { websocket.close(); }
function send() { var message = document.getElementById('text').value; websocket.send(message); } </script>
</html>
|
总结
springboot 已经做了深度的集成和优化,要注意是否添加了不需要的依赖、配置或声明。由于很多讲解组件使用的文章是和 spring 集成的,会有一些配置,在使用 springboot 时,由于 springboot 已经有了自己的配置,再这些配置有可能导致各种各样的异常。
参考
spring boot Websocket(使用笔记) - 长乐忘忧 - 博客园
https://www.cnblogs.com/bianzy/p/5822426.html