首先 pom.xml
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
|
< parent > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-parent</ artifactId > < version >1.5.8.RELEASE</ version > </ parent > < dependency > < groupId >org.apache.commons</ groupId > < artifactId >commons-io</ artifactId > </ dependency > < dependency > < groupId >javax.websocket</ groupId > < artifactId >javax.websocket-api</ artifactId > < version >1.0</ version > < scope >provided</ scope > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-websocket</ artifactId > </ 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-undertow</ artifactId > </ dependency > |
接收消息后的處理類 GameHandler :
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
|
import java.net.URI; import org.springframework.web.socket.BinaryMessage; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.PongMessage; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler; public class GameHandler extends AbstractWebSocketHandler { /** * 處理字符串類的信息 * * @param session * @param message * @throws Exception */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { session.sendMessage(new TextMessage(message.asBytes())); } /** * 處理二進制類的信息 * * @param session * @param message * @throws Exception */ @Override protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception { session.sendMessage(new BinaryMessage(message.getPayload())); } /** * ping-pong * * @param session * @param message * @throws Exception */ @Override protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception { } /** * 傳出錯誤的處理 * * @param session * @param exception * @throws Exception */ @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { } /** * 連接關(guān)閉的處理 * * @param session * @param status * @throws Exception */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { } /** * 連接建立后的處理 * * @param session * @throws Exception */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { } } |
握手信息攔截器 WebSocketHandshakeInterceptor :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.util.Map; import javax.servlet.http.Cookie; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse shr1, WebSocketHandler wsh, Map< String , Object> attributes) throws Exception { // 此處可以做一些權(quán)限認證的事情或者其他 return true; } @Override public void afterHandshake(ServerHttpRequest shr, ServerHttpResponse shr1, WebSocketHandler wsh, Exception excptn) { } } |
使用WebSocket的配置類 WebSocketConfig :
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
|
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // 允許連接的域,只能以http或https開頭 String[] allowsOrigins = {"http://127.0.0.1:1213", "http://localhost:1213"}; registry.addHandler(gameHandler(),"/game").addInterceptors(handshakeInterceptor()).setAllowedOrigins(allowsOrigins); } @Bean public GameHandler gameHandler() { return new GameHandler(); } @Bean public WebSocketHandshakeInterceptor handshakeInterceptor() { return new WebSocketHandshakeInterceptor(); } } |
啟動類 Launcher :
1
2
3
4
5
6
|
@SpringBootApplication public class Launcher { public static void main(String[] params) { SpringApplication.run(Launcher.class, params); } } |
配置文件 main/resources/application.properties:
1
2
3
4
5
6
7
|
server.port=1213 server.session-timeout=1800 server.undertow.io-threads=4 server.undertow.worker-threads=20 server.undertow.buffer-size=1024 server.undertow.buffers-per-region=1024 server.undertow.direct-buffers=true |
前端的測試頁面 main\resources\static\index.html
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
<!DOCTYPE html> < html lang = "zh-CN" > < head > < meta charset = "utf-8" > < meta http-equiv = "X-UA-Compatible" content = "IE=edge" > < meta name = "viewport" content = "width=device-width, initial-scale=1" > < title >Platform Gateway</ title > < link href = "https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel = "external nofollow" rel = "stylesheet" > <!--<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" rel="external nofollow" rel="stylesheet">--> < script src = "https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js" ></ script > < script src = "https://cdn.bootcss.com/jquery-scrollTo/2.1.2/jquery.scrollTo.min.js" ></ script > < script src = "https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.6/pako.min.js" ></ script > <!--[if lt IE 9]> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> < style > #message{ height: 600px; overflow-y:auto; } </ style > </ head > < body > < div class = "container" > < h1 >WebSocket Test Page</ h1 > < hr /> < div class = "form-inline" > < div class = "form-group" > < label for = "wsAddr" >WebSocket Address: </ label > < div class = "input-group" > < span class = "input-group-addon" id = "basic-ws" >ws://127.0.0.1:1213/</ span > < input type = "text" class = "form-control" id = "basic-ws-addr" aria-describedby = "basic-ws" placeholder = "game" data-container = "body" data-placement = "top" data-content = "鏈接地址不能為空,請?zhí)顚?quot; > </ div > </ div > < button type = "button" id = "btnConnect" class = "btn btn-primary" onclick = "connect();" > < span class = "glyphicon glyphicon-resize-small" aria-hidden = "true" ></ span > 連接 </ button > < button type = "button" id = "btnClose" class = "btn btn-danger" disabled = "disabled" onclick = "closeWebSocket();" > < span class = "glyphicon glyphicon-remove" aria-hidden = "true" ></ span > 斷開 </ button > < button type = "button" id = "btnSend" class = "btn btn-info" disabled = "disabled" style = "margin-left: 50px;" onclick = "send();" > < span class = "glyphicon glyphicon-transfer" aria-hidden = "true" ></ span > 發(fā)送消息 </ button > </ div >< br /> < textarea class = "form-control" id = "inMsg" rows = "5" placeholder = "在這里輸入需要發(fā)送的信息..." ></ textarea > < hr /> < div id = "message" ></ div > </ div > < script src = "https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" ></ script > < script type = "text/javascript" > function zip(str) { var binaryString = pako.gzip(str, {to: 'string'}); return btoa(binaryString); } function unzip(b64Data) { var strData = atob(b64Data); var charData = strData.split('').map(function (x) { return x.charCodeAt(0); }); var binData = new Uint8Array(charData); var data = pako.inflate(binData); strData = String.fromCharCode.apply(null, new Uint16Array(data)); return strData; } var websocket = null; var wsBaseUrl = null; var wsUrl = null; function init() { wsBaseUrl = "ws://" + window.location.host + "/"; $("#basic-ws").text(wsBaseUrl); $(function () { $('[data-toggle="popover"]').popover(); }); return false; } //關(guān)閉WebSocket連接 function closeWebSocket() { if (websocket) { websocket.close(); } return false; } //將消息顯示在網(wǎng)頁上 function setMessageInnerHTML(who, msg) { var message = null; if (who === 1) { message = '< div class = "alert alert-success" role = "alert" >本地: ' + msg + '</ div >'; } else { message = '< div class = "alert alert-info" role = "alert" >服務(wù)器: ' + msg + '</ div >'; } document.getElementById('message').innerHTML = (document.getElementById('message').innerHTML + message); $("#message").scrollTo('100%'); return false; } //發(fā)送消息 function send() { if (websocket) { var message = $("#inMsg").val(); websocket.send(zip(message)); setMessageInnerHTML(1, message); } return false; } function connect() { var url = $("#basic-ws-addr").val(); if (url.length <= 0) { $('#basic-ws-addr').popover('show'); setTimeout(function () { $('#basic-ws-addr').popover('hide'); }, 3000); } else { wsUrl = wsBaseUrl + url; if ('WebSocket' in window) { websocket = new WebSocket(wsUrl); //連接發(fā)生錯誤的回調(diào)方法 websocket.onerror = function () { setMessageInnerHTML(0, "WebSocket連接發(fā)生錯誤 -> " + wsUrl); $("#btnConnect").removeAttr("disabled"); $("#btnClose").attr("disabled", "disabled"); $("#btnSend").attr("disabled", "disabled"); }; //連接成功建立的回調(diào)方法 websocket.onopen = function () { setMessageInnerHTML(0, "WebSocket連接成功 -> " + wsUrl); $("#btnConnect").attr("disabled", "disabled"); $("#btnClose").removeAttr("disabled"); $("#btnSend").removeAttr("disabled"); }; //接收到消息的回調(diào)方法 websocket.onmessage = function (event) { setMessageInnerHTML(0, unzip(event.data)); }; //連接關(guān)閉的回調(diào)方法 websocket.onclose = function () { setMessageInnerHTML(0, "WebSocket連接關(guān)閉 -> " + wsUrl); $("#btnConnect").removeAttr("disabled"); $("#btnClose").attr("disabled", "disabled"); $("#btnSend").attr("disabled", "disabled"); }; //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時,主動去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會拋異常。 window.onbeforeunload = function () { closeWebSocket(); }; } else { alert('Not support websocket'); } } return false; } window.onload = init(); </ script > </ body > </ html > |
到此就可以使用 WebSocket 進行前后端的通信了,如果大家還有不明白的或者有更好的方法,可以在下方的留言區(qū)討論。
原文鏈接:https://my.oschina.net/Kxvz/blog/1591764