SpringBoot/SpringCloud整合WebSocket
引入WebSocket Jar包
<!--WebSocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocket 配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @description:WebSocket 配置类
* @author: gxz
* @create: 2024/5/8
*/
@Configuration
public class WebSocketConfig {
/**
* 给spring容器注入这个ServerEndpointExporter对象
* 相当于xml:
* <beans>
* <bean id="serverEndpointExporter" class="org.springframework.web.socket.server.standard.ServerEndpointExporter"/>
* </beans>
* <p>
* 检测所有带有@serverEndpoint注解的bean并注册他们。
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointConfigurator(){
return new ServerEndpointExporter();
}
//如果打包成jar包运行,bean注入这个配置类,war包的不需要。
}
WebSocket 处理类
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @description:WebSocket 处理类
* @author: gxz
* @create: 2024/5/8 15:44
*/
@Component
@ServerEndpoint("/webSocket/{uId}")
@Slf4j
public class WebSocketServerUtil {
/**
* 与某个客户端的连接对话,需要通过它来给客户端发送消息
*/
private Session session;
/**
* 用于存所有的连接服务的客户端,这个对象存储是安全的
*/
private static CopyOnWriteArraySet<WebSocketServerUtil > webSocketSet = new CopyOnWriteArraySet<>();
/**
* 用于存所有的连接第三方ws服务的客户端
*/
private static ConcurrentHashMap<Long,WebSocketServerUtil > webSocketMap = new ConcurrentHashMap<>();
/**
* 标识当前连接客户端的用户名
*/
private Long uId = null;
@OnOpen
public void onOpen(Session session, @PathParam("uId") Long uId){
this.session = session;
this.uId = uId;
if(webSocketMap.containsKey(uId)){
webSocketMap.remove(uId);
webSocketMap.put(uId,this);
}else{
webSocketMap.put(uId,this);
webSocketSet.add(this);
}
log.info("【websocket消息】有新的连接,总数:{}",webSocketMap.size());
}
@OnClose
public void onClose(){
if(webSocketMap.containsKey(uId)){
webSocketMap.remove(uId);
//从set中删除
webSocketSet.remove(this);
}
log.info("【websocket消息】连接断开,总数:{}",webSocketSet.size());
}
@OnMessage
public void onMessage(String message){
log.info("【websocket消息】收到客户端发来的消息:{}",message);
}
public void sendMessage(String message){
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送自定义消息
* */
public static void sendInfo(String message,Long uId) throws Exception {
log.info("发送消息到:"+uId+",报文:"+message);
if(webSocketMap.containsKey(uId)){
webSocketMap.get(uId).sendMessage(message);
}else{
log.error("用户"+uId+",不在线!");
throw new Exception("连接已关闭,请刷新页面后重试");
}
}
}
WebSocket 发送消息
Long uId = new Long("1");
Map msgMap = new HashMap();
msgMap.put("step",1);
msgMap.put("type",2);
msgMap.put("msg","hello");
String s = JSONObject.toJSONString(msgMap);
try {
WebSocketServerUtil.sendInfo(s,uId);
} catch (Exception e) {
throw new RuntimeException(e);
}
vue整合WebSocket
/**
* 初始化websocket连接
*/
initWebSocket() {
let uId = 1;
let websocket = null;
if (typeof WebSocket === "undefined") {
alert("该浏览器不支持websocket!");
} else {
websocket = new WebSocket("ws://127.0.0.1:9206/webSocket/" + uId);
websocket.onopen = function(event) {
console.log("建立连接");
websocket.send('Hello WebSockets!');
}
websocket.onclose = function(event) {
console.log('连接关闭')
// this.reconnect(); //尝试重连websocket
}
//建立通信后,监听到后端的数据传递
websocket.onmessage = function(event) {
let data = JSON.parse(event.data);
//业务处理....
if (data.step == 1) {
alert(data.msg);
}
}
websocket.onerror = function() {
// notify.warn("websocket通信发生错误!");
// initWebSocket()
}
window.onbeforeunload = function() {
websocket.close();
}
}
},
// 重连
reconnect() {
console.log("正在重连");
// 进行重连
setTimeout(function() {
this.initWebSocket();
}, 1000);
},
完成上述所有操作后,由于websocket接口没有token,所以要在拦截器白名单设置,不验证token
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage","/loginByPhone"
,"/webSocket/**","/app/api/login"
).anonymous()