引入依赖
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
其中,spring-boot-starter-websocket就是实现websocket的关键依赖
配置
配置类
这里主要是注入一个ServerEndpointExporter对象,它主要用来管理ServerEndpoint,也就是进行websocket长连接的节点。当然,后续我们的节点都是设置在controller上。controller来接受请求,并且将请求绑定在一个长连接上。
@EnableWebSocket则是开启websocket服务,打开这个功能
@Configuration
@EnableWebSocket
public class WebSocketConfig {
/**
* 注入ServerEndpointExporter;
* 该Bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
Controller
Controller(@ServerEndpoint)
Controller根据@ServerEndpoint也声明为了一个节点,里面有对应的方法注解,对应连接打开,收到消息等情况时应该执行的方法。并且前端要连接到这个controller应该用websocket协议(ws://xxxx)。
/**
* 说明:
* 1、@ServerEndpoint注解中指定WebSocket协议的地址;
* 2、@OnOpen、@OnMessage、@OnClose、@OnError注解与WebSocket中监听事件对应
* @author sec
* @version 1.0
* @date 2020/2/19 10:17 AM
**/
@Slf4j
@RestController
@ServerEndpoint("/helper/{username}")
public class AssistantServerEndpoint {
/**
* 连接建立时触发
*/
@OnOpen
public void openSession(@PathParam("username") String username, Session session) {
log.info("用户{}登录", username);
String message = "欢迎用户[" + username + "] 已进入!";
// 发送登录消息给其他人
sendMessageAll(message);
// 获取当前在线人数,发给自己
String onlineInfo = WebSocketUtils.getOnlineInfo();
WebSocketUtils.sendMessage(session, onlineInfo);
// 添加自己到map中
CLIENTS.put(username, session);
}
/**
* 客户端接收服务端数据时触发
*/
@OnMessage
public void onMessage(@PathParam("username") String username, String message) {
log.info("发送消息:{}", message);
sendMessageAll("[" + username + "] : " + message);
}
/**
* 连接关闭时触发
*/
@OnClose
public void onClose(@PathParam("username") String username, Session session) {
//当前的Session移除
CLIENTS.remove(username);
// 离开消息通知所有人
sendMessageAll("[" + username + "] 已离开!");
try {
session.close();
} catch (IOException e) {
log.error("onClose error", e);
}
}
/**
* 通信发生错误时触发
*/
@OnError
public void onError(Session session, Throwable throwable) {
try {
session.close();
} catch (IOException e) {
log.error("onError Exception", e);
}
log.info("Throwable msg " + throwable.getMessage());
}
}
工具类WebSocketUtils
上述的controller发送信息主要用工具来实现,具体代码如下:
package com.secbro.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author sec
* @version 1.0
* @date 2020/2/26 9:10 AM
**/
public final class WebSocketUtils {
private static final Logger logger = LoggerFactory.getLogger(WebSocketUtils.class);
/**
* 存储WebSocket session;<br/>
* 以用户的姓名为key,WebSocket为对象为value;
*/
public static final Map<String, Session> CLIENTS = new ConcurrentHashMap<>();
/**
* 使用连接发送数据
* @param session 用户session
* @param message 发送内容
*/
public static void sendMessage(Session session, String message) {
if (session == null) {
return;
}
final RemoteEndpoint.Basic basic = session.getBasicRemote();
if (basic == null) {
return;
}
try {
basic.sendText(message);
} catch (IOException e) {
logger.error("sendMessage IOException ", e);
}
}
public static void sendMessageAll(String message) {
CLIENTS.forEach((sessionId, session) -> sendMessage(session, message));
}
/**
* 获取所有在线用户
*/
public static String getOnlineInfo(){
Set<String> userNames = CLIENTS.keySet();
if(userNames.size() ==0){
return "当前无人在线...";
}
return CLIENTS.keySet().toString() + "在线";
}
}
小结
小结
综上,为了实现SpringBoot的websocket功能,首先应该引入spring-boot-starter-websocket依赖;再配置好管理节点的对象ServerEndpointExporter;接着声明好节点ServerEndpoint,同时为了SpringBoot可以把接收到的请求分配给该节点,还要在这个节点上用上@Controller注解;最后在这个节点类上声明各种开启连接、收到消息的方法并注解。
但是,这种形式是可以实现简单的SpringBoot上的websocket功能,不过SpringBoot推荐的实现方式其实是基于STOMP协议的,大家有兴趣可以看看下一篇博客。
评论区