SpringBoot WebSocket服务端创建
引入maven
<!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
新建WebSocket配置文件
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Component
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}
新建WebSocket服务
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;@Component
@ServerEndpoint("/webSocket/{sid}")
public class WebSocketServer implements EnvironmentAware {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();private static Environment globalEnvironment;//接收sidprivate String sid="";//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;@Autowiredprivate Environment environment;/* 连接建立成功调用的方法 @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/@OnOpenpublic void onOpen(Session session,@PathParam("sid") String sid) {//防止重复连接for (WebSocketServer item : webSocketSet) {if (item.sid.equals(sid)) {webSocketSet.remove(item);subOnlineCount(); //在线数减1break;}}this.session = session;this.environment = globalEnvironment;webSocketSet.add(this); //加入set中addOnlineCount(); //在线数加1System.out.println("有新用户连接,连接名:"+sid+",当前在线人数为" + getOnlineCount());this.sid=sid;}/* 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this); //从set中删除subOnlineCount(); //在线数减1System.out.println("连接关闭:"+sid+"当前在线人数为" + getOnlineCount());}/* 收到客户端消息后调用的方法 @param message 客户端发送过来的消息* @param session 可选的参数*/@OnMessagepublic void onMessage(String message, Session session) {System.out.println("收到来自:"+sid+"的信息:"+message);
// //群发消息for (WebSocketServer item : webSocketSet) {try {System.out.println("推送消息到:"+sid+",推送内容:"+message);item.sendMessage("服务器返回:"+message);} catch (IOException e) {e.printStackTrace();continue;}}}/* 发生错误时调用*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}/* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);//this.session.getAsyncRemote().sendText(message);}/* 群发自定义消息* */public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {//log.info("推送消息到窗口"+sid+",推送内容:"+message);System.out.println("推送消息到:"+sid+",推送内容:"+message);for (WebSocketServer item : webSocketSet) {try {//这里可以设定只推送给这个sid的,为null则全部推送if(sid==null||sid.length()==0) {item.sendMessage(message);}else if(item.sid.equals(sid)){item.sendMessage(message);}} catch (IOException e) {continue;}}}//推送给指定sidpublic static boolean sendInfoBySid(@PathParam("sid") String sid,String message) throws IOException {//log.info("推送消息到窗口"+sid+",推送内容:"+message);boolean result=false;if(webSocketSet.size()==0){result=false;}for (WebSocketServer item : webSocketSet) {try {if(item.sid.equals(sid)){item.sendMessage(message);System.out.println("推送消息到:"+sid+",推送内容:"+message);result=true;}} catch (IOException e) {continue;}}return result;}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}@Overridepublic void setEnvironment(final Environment environment) {this.environment = environment;if (globalEnvironment == null && environment != null) {globalEnvironment = environment;}}
}
前端连接示例代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>本地websocket测试</title><meta name="robots" content="all" /><meta name="keywords" content="本地,websocket,测试工具" /><meta name="description" content="本地,websocket,测试工具" /><style>.btn-group{display: inline-block;}</style></head><body><input type='text' value='ws://127.0.0.1:6767/webSocket/10' class="form-control" style='width:390px;display:inline'id='wsaddr' /><div class="btn-group" ><button type="button" class="btn btn-default" onclick='addsocket();'>连接</button><button type="button" class="btn btn-default" onclick='closesocket();'>断开</button><button type="button" class="btn btn-default" onclick='$("#wsaddr").val("")'>清空</button></div><div class="row"><div id="output" style="border:1px solid #ccc;height:365px;overflow: auto;margin: 20px 0;"></div><input type="text" id='message' class="form-control" style='width:810px' placeholder="待发信息" onkeydown="en(event);"><span class="input-group-btn"><button class="btn btn-default" type="button" onclick="doSend();">发送</button></span></div></div></body> <script crossorigin="anonymous" integrity="sha384-LVoNJ6yst/aLxKvxwp6s2GAabqPczfWh6xzm38S/YtjUyZ+3aTKOnD/OJVGYLZDl" src="https://lib.baomitu.com/jquery/3.5.0/jquery.min.js"></script><script language="javascript" type="text/javascript">function formatDate(now) {var year = now.getFullYear();var month = now.getMonth() + 1;var date = now.getDate();var hour = now.getHours();var minute = now.getMinutes();var second = now.getSeconds();return year + "-" + (month = month < 10 ? ("0" + month) : month) + "-" + (date = date < 10 ? ("0" + date) : date) +" " + (hour = hour < 10 ? ("0" + hour) : hour) + ":" + (minute = minute < 10 ? ("0" + minute) : minute) + ":" + (second = second < 10 ? ("0" + second) : second);}var output;var websocket;function init() {output = document.getElementById("output");testWebSocket();}function addsocket() {var wsaddr = $("#wsaddr").val();if (wsaddr == '') {alert("请填写websocket的地址");return false;}StartWebSocket(wsaddr);}function closesocket() {websocket.close();}function StartWebSocket(wsUri) {websocket = new WebSocket(wsUri);websocket.onopen = function(evt) {onOpen(evt)};websocket.onclose = function(evt) {onClose(evt)};websocket.onmessage = function(evt) {onMessage(evt)};websocket.onerror = function(evt) {onError(evt)};}function onOpen(evt) {writeToScreen("<span style='color:red'>连接成功,现在你可以发送信息啦!!!</span>");}function onClose(evt) {console.log('websocket 断开: ' + evt.code + ' ' + evt.reason + ' ' + evt.wasClean)console.log(evt)writeToScreen("<span style='color:red'>websocket连接已断开!!!</span>");websocket.close();}function onMessage(evt) {writeToScreen('<span style="color:blue">服务端回应 ' + formatDate(new Date()) + '</span><br/><span class="bubble">' +evt.data + '</span>');}function onError(evt) {writeToScreen('<span style="color: red;">发生错误:</span> ' + evt.data);}function doSend() {var message = $("#message").val();if (message == '') {alert("请先填写发送信息");$("#message").focus();return false;}if (typeof websocket === "undefined") {alert("websocket还没有连接,或者连接失败,请检测");return false;}if (websocket.readyState == 3) {alert("websocket已经关闭,请重新连接");return false;}console.log(websocket);$("#message").val('');writeToScreen('<span style="color:green">你发送的信息 ' + formatDate(new Date()) + '</span><br/>' + message);websocket.send(message);}function writeToScreen(message) {var div = "<div class='newmessage'>" + message + "</div>";var d = $("#output");var d = d[0];var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;$("#output").append(div);if (doScroll) {d.scrollTop = d.scrollHeight - d.clientHeight;}}function en(event) {var evt = evt ? evt : (window.event ? window.event : null);if (evt.keyCode == 13) {doSend()}}</script></html>