利用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条评论
点击登录参与评论