第一次接触websocket,不知道websocket是什么东西。要写一个后端向前端发送消息的任务。公司的大哥介绍了这篇文章,代码很简单。
注册使用bean 用来扫描端点
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author guoyufeng
* 注册baen来扫描端点
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
配置端点,WebSocket服务端
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author guoyufeng
* webSovket建立连接
*/
@Component
@ServerEndpoint("/webSocket/{userId}")
public class WebSocketService {
Logger log = LoggerFactory.getLogger(getClass());
/**用来存放每个客户端对应的MyWebSocket对象。*/
public static ConcurrentHashMap<String,WebSocketService> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话*/
private Session session;
/**接收userId*/
private String userId="";
/**
* 连接建立成功调用的方法
* */
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
//加入set中
} else {
webSocketMap.put(userId, this);
}
System.out.println(webSocketMap+"--------------------------------");
}
/**
* 服务器主动推送到客户端
*/
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 收到客户端消息后 --- 自动调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:"+userId+",报文:"+message);
}
/**
* 客户端关闭 -- 连接关闭自动回调的方法
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
//从set中删除
//subOnlineCount();
}
log.info("客户端关闭");
}
}
然后在启动的时候,报这个错误
Cannot deploy POJO class [net.shengjian.metaid.config.WebSocketService$$SpringCGLIB$$0] as it is not annotated with @ServerEndpoint
在网上搜解决方法,搜了两个
1.这位大佬的文章,可能是我比较菜,没有解决。但是问题确实是这个问题。
2.是这位大佬的这篇文章,这个可以启动,但是长连接的时候,连接不上。
最后请教别人,发现问题。
Spring管理采用单例模式(singleton),而 WebSocket 是多对象的,即每个客户端对应后台的一个 WebSocket 对象,也可以理解成 new 了一个 WebSocket,这样当然是不能获得自动注入的对象了,因为这两者刚好冲突。
可以得出结论,没有注入。
然后想到了有个单例变多例的注解。
@Scope("prototype")
在设置端口的类上加上之后,竟然可以启动成功,并且长连接成功。
完整代码
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author guoyufeng
* webSovket建立连接
*/
@Component
@Scope("prototype")
@ServerEndpoint("/webSocket/{userId}")
public class WebSocketService {
Logger log = LoggerFactory.getLogger(getClass());
/**用来存放每个客户端对应的MyWebSocket对象。*/
public static ConcurrentHashMap<String,WebSocketService> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话*/
private Session session;
/**接收userId*/
private String userId="";
/**
* 连接建立成功调用的方法
* */
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
//加入set中
} else {
webSocketMap.put(userId, this);
}
}
/**
* 服务器主动推送到客户端
*/
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 收到客户端消息后 --- 自动调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:"+userId+",报文:"+message);
}
/**
* 客户端关闭 -- 连接关闭自动回调的方法
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
//从set中删除
//subOnlineCount();
}
log.info("客户端关闭");
}
}
向前端发送消息调用其sendMessage方法就可以了
WebSocketService webSocketService = WebSocketService.webSocketMap.get(owner);
if (webSocketService != null){
webSocketService.sendMessage("Registration successful!");
}
成功!!!