一、原理:
在未了解socket前一直以为javaweb项目就是通过前端页面触发事件后向后台请求,再通过后台响应给前端的一个过程。本来是这样的,但Websocket是可以Web浏览器和服务器之间进行任意的双向数据传输,是基于TCP协议实现,包含初始的握手过程,以及后续的多次数据帧双向传输过程。其目的是在WebSocket应用和WebSocket服务器进行频繁双向通信时,可以使服务器避免打开多个HTTP连接进行工作来节约资源,提高了工作效率和资源利用率。
当然不用websocket也可以实现从后台向前端发送信息的功能,比如用前端轮巡的方式(setInterval("function(){请求后台代码}",1000) 也可以实现,但这样正如上述所说的,给浏览器以及后台包括数据库访问都带来一定的压力,所以,采用更好的技术。
二、pom引用:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
三、后台代码:
@Component
@ServerEndpoint(value = "/websocket")
public class WebSocketTest {
private static int onlineCount = 0;
private static CopyOnWriteArrayList<WebSocketTest> webSocketSet = new CopyOnWriteArrayList<WebSocketTest>();
private Session session;
public WebSocketTest() {
System.out.println("WebSocketTest.WebSocketTest()");
System.out.println(this);
}
@OnOpen
public void onOpen(Session session) {
System.out.println("WebSocketTest.onOpen()");
this.session = session;
webSocketSet.add(this);// 加入set中
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}
@OnClose
public void onClose() {
System.out.println("WebSocketTest.onClose()");
System.out.println(this);
webSocketSet.remove(this);
subOnlineCount();
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("WebSocketTest.onMessage()");
System.out.println("来自客户端的消息:" + message);
// 群发消息
for (WebSocketTest item : webSocketSet) {
try {
System.out.println(item);
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("发生错误!");
System.out.println("WebSocketTest.onError()");
throwable.printStackTrace();
}
// 下面是自定义的一些方法
public void sendMessage(String message) throws IOException {
System.out.println("WebSocketTest.sendMessage()");
System.out.println(this);
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketTest.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketTest.onlineCount--;
}
public static CopyOnWriteArrayList<WebSocketTest> getWebSocketSet() {
return webSocketSet;
}
public static void setWebSocketSet(CopyOnWriteArrayList<WebSocketTest> webSocketSet) {
WebSocketTest.webSocketSet = webSocketSet;
}
这里记得,在添加一个配置类:注入ServerEndpointExporter对象Bean到容器
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- <script type="text/javascript" src="jquery-2.2.4.js"></script> -->
</head>
<body>
Welcome<br/><input id="text" type="text"/>
<button onclick="send()">发送消息</button>
<hr/>
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr/>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
var prefix = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/websocket";
if ('WebSocket' in window) {
websocket = new WebSocket(prefix);
}else if ('MozWebSocket' in window) {
websocket = new WebSocket(prefix);
}else {
websocket = new SockJS(prefix);
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
这里就可以运行了,看看效果,在运行成功之前遇到了两个问题,其中一个是前端报错:
failed: Error during WebSocket handshake: Unexpected response code: 404
最后发现是配置类没有被注入到容器里面,可以用@Configuration,或者是websocket所在的类没有被注入到容器中,加@Component就可以了,因为@ServerEndpoint不会被容器当成一个对象注入的。
当然在解决问题之前,网上搜的相关异常解决问题各有所获,但并不能解决问题,最多的是版本问题,这里提供一下我的springboot版本,和jdk版本作为参考
如果有用请点赞,如果有更好的意见,谢谢你的留言。