一、服务端
<!--即时通讯服务端--> <dependency> <!-- websocket --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <!-- fastjson --> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.4.4</version> </dependency>
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { /** * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class WebSocketMapUtil { public static ConcurrentMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>(); public static void put(String key, WebSocketServer webSocketServer){ webSocketMap.put(key, webSocketServer); } public static WebSocketServer get(String key){ return webSocketMap.get(key); } public static void remove(String key){ webSocketMap.remove(key); } public static Collection<WebSocketServer> getValues(){ return webSocketMap.values(); } }
import java.io.IOException; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import cn.hutool.json.JSONObject; import org.springframework.stereotype.Component; @Component @ServerEndpoint(value = "/websocket/service") public class WebSocketServer { private Session session; /** * 连接建立后触发的方法 */ @OnOpen public void onOpen(Session session) { this.session = session; WebSocketMapUtil.put(session.getId(), this); } /** *连接关闭后触发的方法 */ @OnClose public void onClose() { //从map中删除 WebSocketMapUtil.remove(session.getId()); } /** *接收到客户端消息时触发的方法 */ @OnMessage public void onMessage(String params, Session session) throws Exception { //获取服务端到客户端的通道 WebSocketServer myWebSocket = WebSocketMapUtil.get(session.getId()); String result = "收到来自" + session.getId() + "的消息" + params; //返回消息给Web Socket客户端(浏览器) myWebSocket.sendMessage(1,"成功!", result); } public void sendMessage(int code, String msg, Object data) throws IOException { JSONObject result = new JSONObject(); result.put("code", code); result.put("msg", msg); result.put("data", data); this.session.getBasicRemote().sendText(result.toString()); } /** * 向指定客户端发送消息 * @param uid 客户端id */ public synchronized void send(String uid){ try { WebSocketServer myWebSocket = WebSocketMapUtil.get(uid); myWebSocket.sendMessage(1,"ok","null"); }catch (Exception e){ e.getMessage(); } } }
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/web/socket") public class WebSocketController { @Resource private WebSocketServer myWebSocket; /** * 向客户端发送消息 * @param uid 客户端连接id * @return */ @GetMapping("/send") public String send(String uid){ myWebSocket.send(uid); return "OK"; } }
分别引入对应的类
二、 客户端
创建index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>即时通讯</title> </head> <body> <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; //判断当前浏览器是否支持WebSocket, 主要此处要更换为自己的地址 if ('WebSocket' in window) { // websocket = new WebSocket("即时通讯协议://服务器:服务端端口/服务类的路由"); websocket = new WebSocket("ws://127.0.0.1:8080/websocket/service"); } else { alert('Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function() { setMessageInnerHTML("error"); }; //连接成功建立的回调方法 websocket.onopen = function(event) { setMessageInnerHTML("连接成功"); } //接收到消息的回调方法 websocket.onmessage = function(event) { setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose = function() { setMessageInnerHTML("关闭连接"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 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>
三、测试
调用控制器类的接口 传入指定客户端id即可对指定客户端发送消息: