首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
使用springboot的唯一区别是要@Component声明下,而使用独立容器是由容器自己管理websocket的,但在springboot中连容器都是spring管理的。
虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
1.new一个websocket的类,里面的字段可以自己定义,前台需要什么可以写在里面使用推送。
public class WebSocketMessage {
/**
* 消息内容
*/
private String context;
private Integer onsiteLearningRecordId;
/**
* 签到通知状态1发生更新0连接成功
*/
private Integer state;
private Integer userId;
private Integer type;
private Integer staffType;
private Integer signType;
/**
* 省略get/set方法
*/
}
2.Spring的service层发送、
WebSocketMessage webSocketMessage = new WebSocketMessage();
webSocketMessage.setOnsiteLearningRecordId(entity.getBusinessPkId());
webSocketMessage.setState(1);
webSocketMessage.setType(entity.getEventTye());
webSocketMessage.setStaffType(entity.getStaffType());
webSocketMessage.setSignType(2);
try {
WsServer.sendMessage(webSocketMessage);
} catch (IOException | EncodeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
3.websocket的类
@ServerEndpoint(value = "/webSocket/{onisteLearningRecordId}")
@Component
public class WsServer {
//打印日志使用
private static Logger logger = LoggerFactory.getLogger(WsServer.class);
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WsServer> webSocketSet = new CopyOnWriteArraySet<WsServer>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//根据这个id来判定
private int onsiteLearningRecordId;
/**
* 连接建立成功调用的方法
*
* @throws EncodeException
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "onisteLearningRecordId") int onsiteLearningRecordId)
throws EncodeException {
this.session = session;
this.onsiteLearningRecordId = onsiteLearningRecordId;
webSocketSet.add(this); // 加入set中
try {
WebSocketMessage webSocketMessage = new WebSocketMessage();
webSocketMessage.setContext("连接成功");
webSocketMessage.setState(0);
sendOpenMessage(webSocketMessage);
} catch (IOException e) {
logger.error("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); // 从set中删除
subOnlineCount(); // 在线数减1
logger.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
//群发消息
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
logger.error("发生错误");
error.printStackTrace();
}
public static void sendMessage(WebSocketMessage webSocketMessage) throws IOException, EncodeException {
//webSocketSet是onOpen时websocket连接时就有了
for (WsServer wsServer : webSocketSet) {
if (wsServer.onsiteLearningRecordId == webSocketMessage.getOnsiteLearningRecordId()) {
logger.info("onsite learning staff sign-in:{} ", webSocketMessage);
String message = JSON.toJSONString(webSocketMessage);
//发送消息
wsServer.session.getBasicRemote().sendText(message);
}
}
}
public void sendOpenMessage(WebSocketMessage webSocketMessage) throws IOException, EncodeException {
String message = JSON.toJSONString(webSocketMessage);
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
*/
public static void sendInfo(String message) throws IOException {
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WsServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WsServer.onlineCount--;
}
}