目录
  1. 1. 前言
  2. 2. 集成说明
  3. 3. 集成步骤
springboot集成websocket

前言

服务端一般都是被动接收请求,不主动向客户端发送信息。在某些场景情况下,客户需要及时获取更新的数据,有两种方法解决,一是由前端轮询定时调用接口,二是采用websocket服务端与客户端保持实时通信。

集成说明

采用tomcat自带的websocket实现,其中内置tomcat和外置tomcat集成稍有差别,外置tomcat不需要注入ServerEndpointExporter,因为它由容器自己提供和管理,websocket接收类不需要加@Component注解。如果涉及用户权限的问题,需要定义websocket拦截器,本文不再赘述。

集成步骤

1、pom.xml引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、定义配置类注入ServerEndpointExporter

1
2
3
4
5
6
7
8
9
@Configuration
public class WebSocketConfig {

@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}

}

3、定义websocket接收类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
@ServerEndpoint("/websocket/{uuid}")
public class WebSocketServer {

private WebSocketService webSocketService = SpringUtil.getBean(WebSocketService.class);

private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
/**
* 记录当前在线连接数
*/
private static int onlineCount = 0;
/**
* 存放每个客户端对应Session对象
*/
private static ConcurrentHashMap<String, Session> webSocketMap = new ConcurrentHashMap<>();

@OnOpen
public void onOpen(Session session, @PathParam("uuid") String uuid) throws InterruptedException {
if (webSocketMap.containsKey(uuid)) {
webSocketMap.remove(uuid);
webSocketMap.put(uuid, session);
} else {
webSocketMap.put(uuid, session);
addOnlineCount();
}
log.info("用户连接:{},当前在线人数为:{}", uuid, getOnlineCount());
sendMessageToSingle(WebSocketResult.success("connect", "连接成功"), uuid);
webSocketService.sendAllData(uuid);
}

/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("uuid") String uuid) {
if (webSocketMap.containsKey(uuid)) {
webSocketMap.remove(uuid);
subOnlineCount();
}
log.info("用户退出:{},当前在线人数为:{}", uuid, getOnlineCount());
}

/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session, @PathParam("uuid") String uuid) {
log.info("用户:{},发送消息:{}", uuid, message);
if (StringUtils.isNotBlank(message)) {
try {
//解析发送的报文
// JSONObject jsonObject = JSON.parseObject(message);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error, @PathParam("uuid") String uuid) {
log.info("用户:{}连接错误,错误原因{}", uuid, error.getMessage());
if(webSocketMap.containsKey(uuid)){
webSocketMap.remove(uuid);
subOnlineCount();
}
}

/**
* @Author yuxk
* @Description 向单个用户发送消息
* @Date 2020/11/6 15:23
* @Param message
* @Param uuid
* @Return void
**/
public static void sendMessageToSingle(WebSocketResult message, String uuid) {
if (webSocketMap.containsKey(uuid)) {
try {
webSocketMap.get(uuid).getBasicRemote().sendText(JSON.toJSONString(message));
} catch (IOException e) {
log.error("发送消息异常:{}", e.getMessage());
}
} else {
log.error("用户:{}不在线", uuid);
}
}

/**
* @Author yuxk
* @Description 向所有用户发送消息
* @Date 2020/11/6 15:24
* @Param message
* @Return void
**/
public static void sendMessageToAll(WebSocketResult message) {
for (Map.Entry<String, Session> map : webSocketMap.entrySet()) {
sendMessageToSingle(message, map.getKey());
}
}

public static synchronized int getOnlineCount() {
return onlineCount;
}

public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}

public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}

4、定义SpringUtil工具类,用于获取bean,因为WebSocketServer是多例对象,不能通过直接使用@Autowired注入bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
public class SpringUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}

public ApplicationContext getApplicationContext(){
return applicationContext;
}

public static Object getBean(String beanName){
return applicationContext.getBean(beanName);
}

public static <T> T getBean(Class<T> clazz){
return (T)applicationContext.getBean(clazz);
}

}

5、定义WebSocketResult结果集,转换成json返回给前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WebSocketResult implements Serializable {
/**
* 状态码
*/
private int code;
/**
* 类型
*/
private String type;
/**
* 数据
*/
private Object data;

public static WebSocketResult success(String type, Object data) {
return new WebSocketResult(200, type, data);
}

public static WebSocketResult fail(String type, Object data) {
return new WebSocketResult(500, type, data);
}

}

格式为

1
2
3
4
5
6
7
8
{
    "code"200,
    "data": {
        "org_id""30004",
        "uuid""1ebf7693-dc68-4093-aa6f-3fe31260e3fd"
    },
    "type""KbsActualData"
}

code为状态码,data为数据,type为类型标识

文章作者: 微光
文章链接: http://www.guduke.cn/2020/11/29/websocket/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 微光
打赏
  • 微信
  • 支付宝

评论