springboot集成websocket
在一些项目中,需要做到实时通讯,目前大部分的选择都是websokect。
话不多说,开始造
添加依赖
<!-- websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
新建websocket服务类
package com.qk.common.shiro;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @时间:2023年5月6日 上午11:07:59
* @作者:秦二少
* @描述:websocket服务类
*/
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {
private final static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<String,WebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
public static ConcurrentHashMap<String, WebSocketServer> getWebSocketMap() {
return webSocketMap;
}
public static void setWebSocketMap(ConcurrentHashMap<String, WebSocketServer> webSocketMap) {
WebSocketServer.webSocketMap = webSocketMap;
}
/**
* @类名: WebSocketServer.java
* @时间: 2023年5月6日 上午11:08:17
* @作者: 秦二少
* @param session
* @param userId
* @描述: 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
//加入map中
webSocketMap.put(userId, this);
//sendMessage("CONNECT_SUCCESS", userId);
System.out.println("【websocket消息】有新的连接,连接id"+userId+";总数:"+ webSocketMap.size());
}
/**
* @类名: WebSocketServer.java
* @时间: 2023年5月6日 上午11:08:35
* @作者: 秦二少
* @param userId
* @描述: 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("userId") String userId) {
//从Map中删除
webSocketMap.remove(userId);
System.out.println("【websocket消息】连接断开,总数:"+ webSocketMap.size());
}
/**
* @类名: WebSocketServer.java
* @时间: 2023年5月5日 下午5:30:34
* @作者: 秦二少
* @param message 客户端发送过来的消息
* @描述: 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(String message) {
log.info("来自客户端的消息:" + message);
if (!message.equals("ping")) {
System.out.println("【websocket消息】收到客户端发来的消息:"+message);
}
}
/**
* @类名: WebSocketServer.java
* @时间: 2023年5月6日 上午11:08:57
* @作者: 秦二少
* @param session
* @param error
* @描述: 发生错误
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* @类名: WebSocketServer.java
* @时间: 2023年5月5日 下午5:32:41
* @作者: 秦二少
* @param message 发送的消息
* @param userId 客户端
* @描述: 主动向客户端发送消息
*/
public static void sendMessage(String message, String userId) {
WebSocketServer webSocket = webSocketMap.get(userId);
if (webSocket != null) {
try {
webSocket.session.getBasicRemote().sendText(message);
System.out.println("【websocket消息】发送消息成功,用户="+userId+",消息内容"+message.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 群发自定义消息
*/
/*public static void sendInfo(String message){
for (String userId : webSocketMap.keySet()) {
WebSocketServer webSocket = webSocketMap.get(userId);
webSocket.sendMessage(message,userId);
}
}*/
}
新增websocket配置类
package com.qk.common.shiro;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @时间:2023年5月6日 上午11:09:59
* @作者:秦二少
* @描述:开启WebSocket的支持,并把该类注入到spring容器中
*/
@Configuration
public class WebSocketConfig {
//如果使用了springboot启动项目,则需要bean注入,而如果使用了外置tomcat容器,则并不要bean注入,否侧会报错
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
调用方法:
WebSocketServer.sendMessage("这里是你需要发送的消息",userId);
到此后端部分已完成!
新建websocket客户端js
document.addEventListener('readystatechange', e => {
if (document.readyState == 'complete') {//这个等同于window.onload
var websocket = null;
var wsurl = "";
var userId=$("#qk-userId").val();//获取页面上用户ID
// 判断是http还是https协议兼容各种访问
var qkurl=window.location.href;
if(qkurl.indexOf("你的域名")>=0){
var protocolStr = document.location.protocol;
if(protocolStr == "http:"){
wsurl = "ws://你的域名/websocket/"+userId;
}else if(protocolStr == "https:"){
wsurl = "wss://你的域名/websocket/"+userId;
}
}else{
wsurl = "ws://localhost:8080/websocket/"+userId;
}
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
websocket = new WebSocket(wsurl);
}else{
alert('你的浏览器版本过低,建议使用最新版的谷歌浏览器!');
}
//连接发生错误的回调方法
websocket.onerror = function(){
reconnect(wsurl);
};
//连接成功建立的回调方法
websocket.onopen = function(event){
}
//接收到消息的回调方法
websocket.onmessage = function(event){
var obj = JSON.parse(event.data);
buildJsonMsg(obj.tag,obj.msg);
}
//连接关闭的回调方法
websocket.onclose = function(){
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//关闭连接
function closeWebSocket(){
websocket.close();
}
//发送消息
/* function send(){
var message = document.getElementById('text').value;
var obj = {
form:""+'${user.username }',//发送方
to:"admin",//收取方
msg:message
};
websocket.send(JSON.stringify(obj));
}*/
//组织消息
function buildJsonMsg(tag,msg) {
//在此处将后台传递过来的消息修改到页面中
}
function reconnect(wsurl) {
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
websocket = new WebSocket(wsurl);
}, 3000);
}
}
})
OK!完成了,就是这么简单!