溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

WebSocket 整合 Springboot

發(fā)布時(shí)間:2020-07-21 08:33:18 來源:網(wǎng)絡(luò) 閱讀:116 作者:千鋒IJava 欄目:編程語言

WebSocket+Springboot

1.1 pom 文件的依賴和插件

?<parent>
??????? <groupId>org.springframework.boot</groupId>
??????? <artifactId>spring-boot-starter-parent</artifactId>
??????? <version>1.5.9.RELEASE</version>
??? </parent>

??? <dependencies>
??????? <dependency>
??????????? <groupId>junit</groupId>
??????????? <artifactId>junit</artifactId>
??????????? <version>3.8.1</version>
??????????? <scope>test</scope>
??????? </dependency>
??????? <!--servlet3.1規(guī)范-->
??????? <dependency>
??????????? <groupId>javax.servlet</groupId>
??????????? <artifactId>javax.servlet-api</artifactId>
??????????? <version>3.1.0</version>
??????? </dependency>
??????? <dependency>
??????????? <groupId>org.glassfish.web</groupId>
??????????? <artifactId>jsp</artifactId>
???????? ???<version>2.2</version>
??????? </dependency>
??????? <!-- https://mvnrepository.com/artifact/javax.websocket/javax.websocket-api
???????? websocket 依賴
???????? -->
??????? <dependency>
??????????? <groupId>javax.websocket</groupId>
??????????? <artifactId>javax.websocket-api</artifactId>
??????????? <version>1.1</version>
??????????? <scope>provided</scope>
??????? </dependency>
??????? <!--用于處理json 數(shù)據(jù)的-->
??????? <dependency>
??????????? <groupId>net.sf.json-lib</groupId>
????????? ??<artifactId>json-lib</artifactId>
??????????? <version>2.4</version>
??????? </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>
??????? <!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket
?????? spring 整合websocket
?????? -->
??????? <dependency>
??????????? <groupId>org.springframework</groupId>
??????????? <artifactId>spring-websocket</artifactId>
??????? </dependency>
?? ???<!--springboot 需要的依賴包-->
??????? <dependency>
??????????? <groupId>ch.qos.logback</groupId>
??????????? <artifactId>logback-core</artifactId>
??????? </dependency>
??????? <dependency>
??????????? <groupId>ch.qos.logback</groupId>
??????????? <artifactId>logback-classic</artifactId>
??????? </dependency>
??? </dependencies>
??? <build>
??????? <finalName>websocketspring</finalName>

??????? <plugins>
??????????? <plugin>
??????????????? <groupId>org.springframework.boot</groupId>
??????????????? <artifactId>spring-boot-maven-plugin</artifactId>
??????????? </plugin>
??????? </plugins>
??? </build>

1.2 WebSocket 的配置文件

用于啟動(dòng) websocket,注入處理器和攔截器

/**
?* Created by jackiechan on 2018/2/5/下午4:05
?*/
@Configuration //聲明為配置文件
@EnableWebSocket//啟用 websocket
public class WebSocketConfig implements WebSocketConfigurer {
??? @Override
??? public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
??????? System.out.println("初始化路徑攔截");//指定所有/websocket開頭的路徑會(huì)被 websocket 攔截,設(shè)置處理器和攔截器
??????? webSocketHandlerRegistry.addHandler(chatMessageHandler(),"/websocket/*").addInterceptors(new ChatHandshakeInterceptor());
??? }

??? /**
???? * 創(chuàng)建處理器
???? * @return
???? */
??? @Bean
??? public TextWebSocketHandler chatMessageHandler(){
??????? System.out.println("創(chuàng)建 handler");
??????? return new ChatMessageHandler();
??? }
}


1.3 ChatHandshakeInterceptor攔截器

用于每次 websocket 在握手之前進(jìn)行攔截,可以在內(nèi)部進(jìn)行校驗(yàn)


/**
?* Created by jackiechan on 2018/2/5/下午4:16
?*
?* WebSocket握手請(qǐng)求的攔截器. 檢查握手請(qǐng)求和響應(yīng), 對(duì)WebSocketHandler傳遞屬性
?*/
public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
??? /**
???? * 在握手之前執(zhí)行該方法, 繼續(xù)握手返回true, 中斷握手返回false. 通過attributes參數(shù)設(shè)置WebSocketSession的屬性
???? * @param request
???? * @param response
???? * @param wsHandler
???? * @param attributes
???? * @return
???? * @throws Exception
???? */
??? @Override
??? public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
?????????????????????????????????? Map<String, Object> attributes) throws Exception {
??????? //為了方便區(qū)分來源,在此以用戶的名字來區(qū)分,名字我們通過要求用輸入進(jìn)行傳遞,所以在這里先從請(qǐng)求中獲取到用戶輸入的名字,因?yàn)槭鞘褂玫膔est 風(fēng)格,所以規(guī)定路徑的最后一個(gè)字符串是名字
??????? System.out.println("握手之前");
??????? String s = request.getURI().toString();
??????? String s1 = s.substring(s.lastIndexOf("/") + 1);
??????? attributes.put(Constants.WEBSOCKET_USERNAME, s1);//給當(dāng)前連接設(shè)置屬性

??????? return super.beforeHandshake(request, response, wsHandler, attributes);
??? }

??? /**
???? * 在握手之后執(zhí)行該方法. 無論是否握手成功都指明了響應(yīng)狀態(tài)碼和相應(yīng)頭.
???? * @param request
???? * @param response
???? * @param wsHandler
???? * @param ex
???? */
??? @Override
??? public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
?????????????????????????????? Exception ex) {
??????? System.out.println("After Handshake");
??????? super.afterHandshake(request, response, wsHandler, ex);
??? }

}



1.4 ChatMessageHandler消息處理器

用于收到消息的時(shí)候處理消息


/**
?* Created by jackiechan on 2018/2/5/下午4:11
?* 文本消息的處理器
?*/
public class ChatMessageHandler extends TextWebSocketHandler {

??? private static final Map<String,WebSocketSession> allClients;//用于緩存所有的用戶和連接之間的關(guān)系
??? private static Logger logger = Logger.getLogger(ChatMessageHandler.class);

??? static {
??????? allClients = new ConcurrentHashMap();//初始化連接
??? }

??? /**
???? * 當(dāng)和用戶成功建立連接的時(shí)候會(huì)調(diào)用此方法,在此方法內(nèi)部應(yīng)該保存連接
???? */
??? @Override
??? public void afterConnectionEstablished(WebSocketSession session) throws Exception {
??????? System.out.println("建立連接成功");
??????? String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//將在攔截器中保存的用戶的名字取出來,然后作為 key 存到 map
??????? if (name != null) {
??????????? allClients.put(name, session);//保存當(dāng)前的連接和用戶之間的關(guān)系
??????? }
??????? // 這塊會(huì)實(shí)現(xiàn)自己業(yè)務(wù),比如,當(dāng)用戶登錄后,會(huì)把離線消息推送給用戶

??? }

??? /**
???? * 收到消息的時(shí)候會(huì)觸發(fā)該方法
???? * @param session 發(fā)送消息的用戶的 session
???? * @param message ?發(fā)送的內(nèi)容
???? * @throws Exception
???? */
??? @Override
??? protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
??????? //此處請(qǐng)根據(jù)自己的具體業(yè)務(wù)邏輯做處理
??????? JSONObject jsonObject= JSONObject.fromObject(new String(message.asBytes()));//將用戶發(fā)送的消息轉(zhuǎn)換為 json,實(shí)際開發(fā)中請(qǐng)根據(jù)自己的需求處理
??????? String toName = jsonObject.getString("toName");//獲取數(shù)據(jù)中的收消息人的名字
??????? String content = jsonObject.getString("content");//獲取到發(fā)送的內(nèi)容
??????? String fromName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//獲取當(dāng)前發(fā)送消息的人的名字
??????? content = "收到來自:" +fromName+ "的消息,內(nèi)容是:" + content;
??????? //拼接內(nèi)容轉(zhuǎn)發(fā)給接收者,實(shí)際開發(fā)中請(qǐng)參考自己的需求做處理
??????? TextMessage textMessage = new TextMessage(content);//將內(nèi)容轉(zhuǎn)換為 TextMessage
??????? sendMessageToUser(toName,textMessage);// 發(fā)送給指定的用戶
??????? //sendMessageToUsers(message);//給所有人發(fā)送
??????? //super.handleTextMessage(session, message);
??? }

??? /**
???? * 給某個(gè)用戶發(fā)送消息
???? *
???? * @param userName
???? * @param message
???? */
??? public void sendMessageToUser(String userName, TextMessage message) {
??????? WebSocketSession webSocketSession = allClients.get(userName);//根據(jù)接收方的名字找到對(duì)應(yīng)的連接
??????? if (webSocketSession != null&& webSocketSession.isOpen()) {//如果沒有離線,如果離線,請(qǐng)根據(jù)實(shí)際業(yè)務(wù)需求來處理,可能會(huì)需要保存離線消息
?? ?????????try {
??????????????? webSocketSession.sendMessage(message);//發(fā)送消息
??????????? } catch (IOException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??? }

??? /**
???? * 給所有在線用戶發(fā)送消息,此處以文本消息為例子
???? *
???? * @param message
???? */
??? public void sendMessageToUsers(TextMessage message) {
??????? for (Map.Entry<String, WebSocketSession> webSocketSessionEntry : allClients.entrySet()) {//獲取所有的連接

??????????? WebSocketSession session = webSocketSessionEntry.getValue();//找到每個(gè)連接
??????????? if (session != null&& session.isOpen()) {
??????????????? try {
??????????????????? session.sendMessage(message);
??????????????? } catch (IOException e) {
??????????????????? e.printStackTrace();
??????????????? }
??????????? }
??????? }
??? }

??? /**
???? * 出現(xiàn)異常的時(shí)候
???? * @param session
???? * @param exception
???? * @throws Exception
???? */
??? @Override
??? public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
??????? String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
??????? if (session.isOpen()) {
??????????? session.close();
??????? }
??????? logger.debug("連接關(guān)閉");
??????? allClients.remove(name);//移除連接
??? }

??? /**
???? * 連接關(guān)閉后
???? * @param session
???? * @param closeStatus
???? * @throws Exception
???? */
??? @Override
??? public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
??????? logger.debug("連接關(guān)閉");
??????? String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//找到用戶對(duì)應(yīng)的連接
??????? allClients.remove(name);//移除
??? }

??? @Override
??? public boolean supportsPartialMessages() {
??????? return false;
??? }

}

1.5 springboot 啟動(dòng)類

注意此類最好放在根包下


/**
?* Created by jackiechan on 2018/2/5/下午4:34
?*/
@SpringBootApplication
@Configuration
public class App {
??? public static void main(String[] args) {
??????? SpringApplication.run(App.class, args);//?? spingboot??? }
??? }
}


1.6 web 方式啟動(dòng)項(xiàng)的配置類


/**
?* Created by jackiechan on 2018/2/5/下午4:34
?用于將項(xiàng)目打包成 war 包后發(fā)布
?*/
public class SpringBootStartApplication extends SpringBootServletInitializer {
??? @Override
??? protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
??? {
??????? return builder.sources(App.class);
??? }
}


1.7 html

與非 springboot 的方式內(nèi)容一致

<!DOCTYPE html>
<html lang="en">
<head>
??? <meta charset="UTF-8">
??? <title>Title</title>
??? <script type="text/javascript">
??????? var websocket = null;
??????? function abc() {

??????????? //var username = localStorage.getItem("name");
??????????? var username=document.getElementById("me").value;
??????????? //判斷當(dāng)前瀏覽器是否支持WebSocket
??????????? if ('WebSocket' in window) {
??????????????? websocket = new WebSocket("ws://" + document.location.host + "/websocket/"+username);
??????????? } else {
??????????????? alert('當(dāng)前瀏覽器 Not support websocket')
??????????? }

??????????? //連接發(fā)生錯(cuò)誤的回調(diào)方法
??????????? websocket.onerror = function() {
??????????????? setMessageInnerHTML("WebSocket連接發(fā)生錯(cuò)誤");
??????????? };

??????????? //連接成功建立的回調(diào)方法
??????????? websocket.onopen = function() {
??????????????? setMessageInnerHTML("WebSocket連接成功");
??????????? }

??????????? //接收到消息的回調(diào)方法
??????????? websocket.onmessage = function(event) {
??????????????? setMessageInnerHTML(event.data);
??????????? }

??????????? //連接關(guān)閉的回調(diào)方法
??????????? websocket.onclose = function() {
??????????????? setMessageInnerHTML("WebSocket連接關(guān)閉");
??????????? }

??????????? //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。
??????????? window.onbeforeunload = function() {
??????????????? closeWebSocket();
??????????? }
??????? }

??????? /**
???????? * 發(fā)送消息
???????? */
??????? function sendmessage() {
??????????? var toName=document.getElementById("to").value;
??????????? if (websocket!=null) {
??????????????? var content=document.getElementById("content").value;

??????????????? var message='{"toName":"'+toName+'","content":"'+content+'"}';//將發(fā)送的內(nèi)容拼接為 json 字符串,服務(wù)端用于解析好處理
??????????????? websocket.send(message);
??????????? }
??????? }

??????? //關(guān)閉WebSocket連接
??????? function closeWebSocket() {
??????????? if (websocket!=null) {

??????????????? websocket.close();
??????????? }
??????? }
?? ?????function setMessageInnerHTML(data) {
??????????? document.getElementById("neirong").innerHTML = data;
??????? }
??? </script>
</head>
<body>
用戶名:<input type="text" id="me" /> <button onclick="abc()"> 連接</button><br>
<!--實(shí)際接收者應(yīng)該由用戶選擇,或者由系統(tǒng)安排,比如客服的話,應(yīng)該是服務(wù)端已經(jīng)存儲(chǔ)了所有在線的客服,用戶只需要發(fā)送消息即可,如果是兩個(gè)用戶聊天,則應(yīng)該有用戶列表,選擇后指定目標(biāo)-->
接收者:<input type="text" id="to" /><br>
內(nèi)容:<input type="text" id="content" /><br>
<button onclick="sendmessage()">發(fā)送</button><br>
<br>
<br>
<br>
<span id="neirong"></span>
</body>
</html>


1.8 啟動(dòng)測(cè)試

WebSocket 整合 Springboot


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI