WebSocket简介
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
SpringBoot整合WebSocket的相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
添加WebSocket的配置类在SpringBoot中启用WebSocket
/**
* 开启WebSocket支持
* @author zhengkai.blog.csdn.net
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSokcet工具类记录当前的在线连接对链接进行操作
public class WebsocketUtil {
/**
* 记录当前在线的Session
*/
private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
/**
* 添加session
* @param userId
* @param session
*/
public static void addSession(String userId, Session session){
// 此处只允许一个用户的session链接。一个用户的多个连接,我们视为无效。
ONLINE_SESSION.putIfAbsent ( userId, session );
}
/**
* 关闭session
* @param userId
*/
public static void removeSession(String userId){
ONLINE_SESSION.remove ( userId );
}
/**
* 给单个用户推送消息
* @param session
* @param message
*/
public static void sendMessage(Session session, String message){
if(session == null){
return;
}
// 同步
RemoteEndpoint.Async async = session.getAsyncRemote ();
async.sendText ( message );
}
/**
* 向所有在线人发送消息
* @param message
*/
public static void sendMessageForAll(String message) {
//jdk8 新方法
ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
}
}
WebSocket接口处理类
/**
* websocket接口处理类
*/
@Component
@ServerEndpoint(value = "/chat/{userId}")
public class WebsocketController {
/**
* 连接事件,加入注解
* @param userId
* @param session
*/
@OnOpen
public void onOpen(@PathParam(value = "userId") String userId, Session session) {
String message = "[" + userId + "]加入聊天室!!";
// 添加到session的映射关系中
WebsocketUtil.addSession(userId, session);
// 广播通知,某用户上线了
// WebsocketUtil.sendMessageForAll(message);
}
/**
* 连接事件,加入注解
* 用户断开链接
*
* @param userId
* @param session
*/
@OnClose
public void onClose(@PathParam(value = "userId") String userId, Session session) {
String message = "[" + userId + "]退出了聊天室...";
// 删除映射关系
WebsocketUtil.removeSession(userId);
// 广播通知,用户下线了
WebsocketUtil.sendMessageForAll(message);
}
/**
* 当接收到用户上传的消息
*
* @param userId
* @param session
*/
@OnMessage
public void onMessage(@PathParam(value = "userId") String userId, Session session, String message) {
String msg = "[" + userId + "]:" + message;
System.out.println("接收到信息:" + msg);
// 直接广播
WebsocketUtil.sendMessageForAll(msg);
}
/**
* 处理用户活连接异常
*
* @param session
* @param throwable
*/
@OnError
public void onError(Session session, Throwable throwable) {
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
throwable.printStackTrace();
}
}
服务器端单个用户推送消息
@PostMapping("/send")
public void send(@RequestParam("id") String id,@RequestParam("message")String message) {
Session session = ONLINE_SESSION.get(id);
WebsocketUtil.sendMessage(session,message);
System.out.println("发送成功");
}
使用Apifox进行测试
添加连接服务端的WebSocket接口
连接成功:
服务端推送消息
客户端收到的消息
WebSocket工具类里面有群发的方法,大家想用可以直接调用,这里就不进行演示了
问题一:如何在上面WebSocket接口处理类中注入其他的Bean?
我也是在一次工作中遇到这样的问题,今天正好和大家讲一下如何解决
查阅资料才知道WebSocket接口处理类使用@ServerEndPoint注解表明他是一个WebSocket端点,因此Spring不会将其纳入Spring容器的管理范围,WebSocket的生命周期和Spring Bean 的生命周期并不一致,所以通过@Autowired 注解注入得到的都是空的Bean 无法使用
我们自定义一个工具类手动获取Bean在 WebSocket接口处理类中使用:
/**
*AppUtils类
*
* @author qiancj
* @since 2020-06-30 13:02
*/
@Component("appUtils")
public class AppUtils {
/**
* 应用上下文
*/
private static ApplicationContext context;
@Resource
public void setApplicationContext(ApplicationContext c) {
context = c;
}
/**
* 获取配置参数
*
* @param property 配置参数名
* @return 配置参数值
*/
public static String getProperty(String property) {
return context.getEnvironment().getProperty(property);
}
/**
* 获取bean对象
*
* @param requiredType Class
* @param <T> T
* @return bean对象
*/
public static <T> T getBean(Class<T> requiredType) {
return context.getBean(requiredType);
}
/**
* 获取bean对象
*
* @param name bean name
* @param requiredType Class
* @param <T> T
* @return bean对象
*/
public static <T> T getBean(String name, Class<T> requiredType) {
return context.getBean(requiredType);
}
}
使用:
MessageService messageService = AppUtils.getBean(MessageService.class);
然后我们就可以使用messageService调用Service层相关的方法了。
问题解决。