本文系本人原创,首先发布在我的个人博客上,SpringBoot + websocket 实现模拟设备上下线,转载请注明出处。
之前有做过车联网项目,gps设备都会有上下线检测的功能,但有的时候没有真实设备测试,如何模拟设备上下线呢?可以使用websocket实现,因为它是长连接,性能开销小且通信高效。
下面就直接上代码
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
</dependencies>
|
DemoApplication.java
1
2
3
4
5
6
|
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
|
WebSocketServer.java
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
118
119
120
121
122
123
124
125
126
127
128
|
package com.example.demo.websocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/{deviceId}")
@Component
public class WebSocketServer {
private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
/**
* 存放每个客户端对应的MyWebSocket对象
*/
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 连接建立成功调用的方法
* */
@OnOpen
public void onOpen(Session session,@PathParam(value = "deviceId") String deviceId) {
this.session = session;
//判断当前设备是否已有web socket连接,有则删除
deleteWebsocketExisted(deviceId);
//保存当前websocket连接
webSocketMap.put(deviceId, this);
// 通知客户端建立连接成功
sendMessage(deviceId + "connected success");
//设备状态变化(设备连接成功通知)
statusChange(deviceId, true);
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* */
@OnMessage
public void onMessage(String message) {
if("ping".equals(message)){
// 心跳
sendMessage(message);
}else{
// 省略业务消息处理步骤
// 返回消息给客户端
sendMessage("some message");
}
}
/**
* 连接关闭调用的方法
* */
@OnClose
public void onClose() {
String deviceId = getKey(webSocketMap, this);
// 从set中删除
webSocketMap.remove(deviceId);
//设备下线
statusChange(deviceId, false);
}
/**
* 发生错误时调用
* */
@OnError
public void onError(Throwable error) {
logger.error("Error:"+error.getMessage());
}
private void statusChange(String deviceId, boolean status) {
if (status) {
logger.info("设备{}上线", deviceId);
}else{
logger.info("设备{}下线", deviceId);
}
// 省略操作数据库步骤
}
private void deleteWebsocketExisted(String deviceId) {
WebSocketServer oldConnection = webSocketMap.get(deviceId);
if(null != oldConnection){
try {
oldConnection.getSession().close();
} catch (IOException e) {
logger.error("IOException:{}"+e.getMessage());
}
}
}
/**
* 根据map的value获取map的key
* @param map
* @param myWebSocket
* @return
*/
private static String getKey(Map<String,WebSocketServer> map,WebSocketServer myWebSocket){
String key="";
for (Entry<String, WebSocketServer> entry : map.entrySet()) {
if(myWebSocket.equals(entry.getValue())){
key=entry.getKey();
}
}
return key;
}
public void sendMessage(String message) {
this.session.getAsyncRemote().sendText(message);
}
public Session getSession() {
return session;
}
}
|
WebSocketConfig.java
1
2
3
4
5
6
7
8
9
10
11
|
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
|
application.properties
1
|
server.port=5656
|
启动springboot,这时就可以在客户端模拟调用了,就是这个地址
1
|
ws://localhost:5656/123456789
|
123456789是设备id
问题总结
1.WebSocketServer里是无法通过@autowired或者@resource注入bean的
2.如果是打包成war到外部tomcat运行,则不需要WebSocketConfig.java这个配置类