废话不说,直接上代码:
项目结构:
这里包一定要导入清楚!
test.java
package net.jiangyi.util;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Author: JiangYi
* @Date: 2018/10/18 21:06
* @Description:
*/
//将目前的类定义为一个websocket服务器
@ServerEndpoint("/go")
public class Test {
//创建一个线程安全发的set集合
private static CopyOnWriteArraySet<Test> set = new CopyOnWriteArraySet<Test>();
//与某一个客户端连接会话,需要通过他来来给客户端来发送数据
private Session session;
//连接建立成功成功调用的方法
@OnOpen
public void OnOpen(Session session){
this.session=session;
set.add(this);
System.out.println("OnOpen()方法被执行````");
System.out.println("websocket连接建立成功`````");
}
//连接关闭的的方法
@OnClose
public void OnClose(){
set.remove(this);
System.out.println("OnClose()方法被执行``");
System.out.println("websocket 连接已近被关闭");
}
//接收消息的方法
@OnMessage
public void OnMessage(String msg,Session session){
System.out.println("已经从客户端接收到消息"+msg);
//这里每秒发送一条数据
for(int i=0;i<10;i++){
try {
Thread.currentThread().sleep(1000);
//向所有客户端发送消息
for(Test t:set){
t.sendResponse("这是第"+(i+1)+"条消息```");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("向所有的客户端发送数据```");
}
//出错的方法,注意参数不能错
@OnError
public void OnError(Session session,Throwable error){
System.out.println("OnError()方法被执行·····");
System.out.println("websocket出错");
}
//发送数据到客户端
public void sendResponse(String str){
System.out.println("sendResponse()方法被执行");
try {
this.session.getBasicRemote().sendText(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
index.jsp
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/10/18
Time: 21:02
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<script type="text/javascript" src="jquery-3.3.1.js"></script>
<script type="text/javascript">
$(function(){
var websocket = null;
//判断浏览器是否支持websocket
if('WebSocket' in window) {
//如果支持,创建websocket对象,注意url格式
websocket = new WebSocket('ws://localhost:8080/chart/go');
}else {
alert('浏览器版本不支持websocket!');
}
//定义连接错误的回调方法
websocket.onerror = function() {
alert('websocket连接出错!');
}
//定义连接成功的回调方法
websocket.onopen = function() {
alert('websocket连接成功!');
}
//定义websocket关闭的回调方法
websocket.onclose = function() {
alert('websocket已关闭!')
}
//当窗口关闭时,主动去关闭websocket连接
window.onbeforeunload = function() {
closeWebSocket();
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
handleMsg(event.data);
}
$('#send').click(function() {
websocket.send($('#input').val());
});
});
//关闭websocket
function closeWebSocket() {
websocket.close();
}
function handleMsg(msg) {
$('#msg').append(msg + '\n');
}
</script>
<body>
<input name="input" id="input" type="text" />
<input name="send" id="send" type="button" value="发送请求" />
<br><hr style="width:50%;" align="left">
<textarea name="msg" id="msg" style="width: 260px;height:190px">
</textarea>
</body>
这里再介绍两个知识:
1.CopyOnWriteArraySet是一个线程安全的set集合。
2. websocket session发送文本消息有两个方法:getAsyncRemote()和getBasicRemote() 同事推荐使用getAsyncRemote()这个方法,网上找了下解释:就是getAsyncRemote是非阻塞式的,getBasicRemote是阻塞式的,表示不懂。推送消息的过程中遇到了一个bug,CSDN的一位网友正好遇到过这个bug, 于是顺便把getAsyncRemote()和getBasicRemote() 的区别给请教了一下,那位网友是这样解释的:
getAsyncRemote()和getBasicRemote()确实是异步与同步的区别,大部分情况下,推荐使用getAsyncRemote()。由于getBasicRemote()的同步特性,并且它支持部分消息的发送即sendText(xxx,boolean isLast). isLast的值表示是否一次发送消息中的部分消息,对于如下情况:
session.getBasicRemote().sendText(message, false);
session.getBasicRemote().sendBinary(data);
session.getBasicRemote().sendText(message, true);
由于同步特性,第二行的消息必须等待第一行的发送完成才能进行,而第一行的剩余部分消息要等第二行发送完才能继续发送,所以在第二行会抛出IllegalStateException异常。如果要使用getBasicRemote()同步发送消息,则避免尽量一次发送全部消息,使用部分消息来发送。
ps:代码运行流程图: