本文系本人原創,首先發布在我的個人博客上,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這個配置類