利用WebSocket实现服务器和浏览器客户端双向即时通信
每个浏览器客户端和服务器连接,会创建一个新的WebSocket对象,通过sessionId来对客户端进行唯一标识
1 index.jsp
负责和服务器建立连接,向服务器发送数据
<%-- Created by IntelliJ IDEA. User: wanmait Date: 2021/3/9 Time: 15:54 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>万码学堂wanmait</title> <meta http-equiv="author" content="万码学堂wanmait"> <style type="text/css"> #sendDiv{ border: 1px solid gray; width: 800px; border-radius: 10px; margin: auto; height: 150px; display: table-cell; vertical-align: middle; } </style> </head> <body> <h1>WebSocket测试</h1> <div id="sendDiv"> sessionId:${pageContext.session.id} <br> <input type="button" value="连接服务器" onclick="connectWebSocket()"> <br> 向服务器发送内容:<input id="sendText" type="text" /> <input type="button" value="发送" onclick="sendMessage()"> <br> <input type="button" value="关闭连接" onclick="closeWebSocket()"> </div> <hr /> <div id="message"> <h1>message:</h1> </div> <script type="text/javascript"> var websocket;//用来存放该客户端和服务器之间的连接对象 //通过该连接对象发送和接收数据 //连接服务器 WebSocket //url-->ws://host:tomcat端口/项目名/WebSocket类的@ServerEndpoint注解 function connectWebSocket() { var sessionId = "${pageContext.session.id}";//获得当前会话的sessionId 作为该客户端的唯一标识 连接时发送给服务器WebSocket //不同浏览器的连接语句 if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/socketTest/webSocket/" + sessionId); } else if ('MozWebSocket' in window) { websocket = new MozWebSocket("ws://localhost:8080/socketTest/webSocket/" + sessionId); } else { websocket = new SockJS("localhost:8080/socketTest/webSocket/" + sessionId); } //连接成功建立的回调方法 连接成功 自动执行该方法 websocket.onopen = function () { appendMessageToDiv("连接成功") } //连接发生错误的回调方法 websocket.onerror = function () { appendMessageToDiv("连接错误") }; //连接关闭的回调方法 websocket.onclose = function () { appendMessageToDiv("连接关闭"); } //设置接收到服务器发送消息的回调方法 接收到服务器发送的消息 调用acceptMessage websocket.onmessage = acceptMessage; //设置该回调方法 表示当服务器发送消息 该acceptMessage方法立即执行 } //connectWebSocket方法的结束 //id为message的div中间 追加显示信息 function appendMessageToDiv(mes) { var messageDiv = document.getElementById("message"); messageDiv.innerHTML += "<h4>"+mes+"</h4>"; } //接收消息的方法 function acceptMessage(event) { //event.dataWebSocket服务器发送的内容 appendMessageToDiv(event.data); //接收的内容显示到message div } //关闭WebSocket连接 function closeWebSocket() { websocket.close();//断开和服务器的WebSocket连接 } //发送消息 function sendMessage() { var message = document.getElementById('sendText').value;//获得文本框输入的内容 websocket.send(message);//发送给服务器 } //添加浏览器关闭事件,当浏览器关闭时 断开连接。 window.onbeforeunload = function () { websocket.close();//断开和服务器的WebSocket连接 } </script> </body> </html>
2 WebSocket.java
服务器等待客户端连接,接收和发送数据
/* author:万码学堂 wanmait */ package com.wanmait.socketTest.util; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; //每次浏览器客户端连接 会自动创建一个新的WebSocket对象 @ServerEndpoint("/webSocket/{sessionId}") public class WebSocket { private Session session;//该Session不等同于HttpSession 是WebSocket的一次会话 private String sessionId;//存放客户端浏览器连接时发送的sessionId 是浏览器客户端的唯一标识 //每个浏览器客户端来连接 自动调用该方法 @OnOpen() public void onOpen(@PathParam("sessionId") String sessionId, Session session) throws IOException { this.sessionId = sessionId;//浏览器客户端发送的sessionId 客户端的唯一标识 this.session = session; WebSocketUtils.getWebSocketUtils().addClient(sessionId,this);//将客户端连接创建的新WebSocket对象保存到Map 中间 客户端发送的sessionId是唯一标识 System.out.println(sessionId+":客户端连接成功"); } //浏览器客户端webSocket关闭 即客户端执行websocket.close()方法 该onClose方法 自动执行 @OnClose() public void onClose() throws IOException { WebSocketUtils.getWebSocketUtils().remove(sessionId);//从map中间 移除该浏览器客户端生成的WebSocket对象 System.out.println(sessionId+":客户端关闭"); } //浏览器客户端发送消息 服务器接收 即浏览器执行websocket.send()方法 服务器该方法 自动执行 //参数message 是浏览器客户端发送的数据 @OnMessage() public void onMessage(String message) throws IOException { System.out.println(sessionId+"客户端发送:"+message); } //客户端服务器出现异常 执行该方法 @OnError() public void onError(Session session, Throwable error) { error.printStackTrace(); } //向该WebSocket对应的浏览器客户端发送数据 public void sendMessageToClient(String message) { this.session.getAsyncRemote().sendText(message); } }
3 WebSocketUtils.java
负责处理每个浏览器客户端连接的WebSocket对象
package com.wanmait.socketTest.util; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class WebSocketUtils { //单一实例 public WebSocketUtils(){} private static WebSocketUtils webSocketUtils = new WebSocketUtils(); public static WebSocketUtils getWebSocketUtils() { return webSocketUtils; } private Map<String, WebSocket> clients = new ConcurrentHashMap<>(); //每连接一个客户端 会自动创建一个新的WebSocket对象 clients用来存放所有的WebSocket对象 //浏览器客户端发送的sessionId为clients的key关键字 创建的WebSocket对象为clients的value值 //往clients集合中间 增加新的WebSocket对象 新的浏览器客户端 public void addClient(String sessionId,WebSocket webSocket) { clients.put(sessionId,webSocket); } //将关闭的客户端创建的WebSocket对象 从clients中间移除 public void remove(String sessionId) { clients.remove(sessionId);//根据key从map中间移除 } //向其中的某个客户端发送数据 public void sendMessageTo(String message,String sessionId) { WebSocket webSocket = clients.get(sessionId);//从map中间获得sessionId对应的客户端 webSocket.sendMessageToClient(message);//向客户端发送数据 } //向所有客户端发送数据 public void sendMessageToAll(String message) { //clients.values()获得map中间所有的value值 即所有的客户端WebSocket对象 for(WebSocket webSocket:clients.values()) { webSocket.sendMessageToClient(message);//向客户端发送数据 } } }
注意:
需要下载javax.websocket-api.jar包
点击连接服务器,网页和服务器控制台会显示连接成功
点击发送按钮,将文本框内容发送给服务器,服务器控制台显示浏览器客户端发送的信息
测试以下,用SendNoticeServlet向所有的客户端发送消息
package com.wanmait.socketTest.controller; import com.wanmait.socketTest.util.WebSocketUtils; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/SendNoticeServlet") public class SendNoticeServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String message = "万码学堂,wanmait,做最负责人的教育"; WebSocketUtils.getWebSocketUtils().sendMessageToAll(message); } }
访问SendNoticeServlet,所有的浏览器客户端都会收到发送的信息
0条评论
点击登录参与评论