您好,登錄后才能下訂單哦!
?<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規范-->
??????? <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 數據的-->
??????? <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>
用于啟動 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開頭的路徑會被 websocket 攔截,設置處理器和攔截器
??????? webSocketHandlerRegistry.addHandler(chatMessageHandler(),"/websocket/*").addInterceptors(new ChatHandshakeInterceptor());
??? }
??? /**
???? * 創建處理器
???? * @return
???? */
??? @Bean
??? public TextWebSocketHandler chatMessageHandler(){
??????? System.out.println("創建 handler");
??????? return new ChatMessageHandler();
??? }
}
用于每次 websocket 在握手之前進行攔截,可以在內部進行校驗
/**
?* Created by jackiechan on 2018/2/5/下午4:16
?*
?* WebSocket握手請求的攔截器. 檢查握手請求和響應, 對WebSocketHandler傳遞屬性
?*/
public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
??? /**
???? * 在握手之前執行該方法, 繼續握手返回true, 中斷握手返回false. 通過attributes參數設置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 {
??????? //為了方便區分來源,在此以用戶的名字來區分,名字我們通過要求用輸入進行傳遞,所以在這里先從請求中獲取到用戶輸入的名字,因為是使用的rest 風格,所以規定路徑的最后一個字符串是名字
??????? System.out.println("握手之前");
??????? String s = request.getURI().toString();
??????? String s1 = s.substring(s.lastIndexOf("/") + 1);
??????? attributes.put(Constants.WEBSOCKET_USERNAME, s1);//給當前連接設置屬性
??????? return super.beforeHandshake(request, response, wsHandler, attributes);
??? }
??? /**
???? * 在握手之后執行該方法. 無論是否握手成功都指明了響應狀態碼和相應頭.
???? * @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);
??? }
}
用于收到消息的時候處理消息
/**
?* Created by jackiechan on 2018/2/5/下午4:11
?* 文本消息的處理器
?*/
public class ChatMessageHandler extends TextWebSocketHandler {
??? private static final Map<String,WebSocketSession> allClients;//用于緩存所有的用戶和連接之間的關系
??? private static Logger logger = Logger.getLogger(ChatMessageHandler.class);
??? static {
??????? allClients = new ConcurrentHashMap();//初始化連接
??? }
??? /**
???? * 當和用戶成功建立連接的時候會調用此方法,在此方法內部應該保存連接
???? */
??? @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);//保存當前的連接和用戶之間的關系
??????? }
??????? // 這塊會實現自己業務,比如,當用戶登錄后,會把離線消息推送給用戶
??? }
??? /**
???? * 收到消息的時候會觸發該方法
???? * @param session 發送消息的用戶的 session
???? * @param message ?發送的內容
???? * @throws Exception
???? */
??? @Override
??? protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
??????? //此處請根據自己的具體業務邏輯做處理
??????? JSONObject jsonObject= JSONObject.fromObject(new String(message.asBytes()));//將用戶發送的消息轉換為 json,實際開發中請根據自己的需求處理
??????? String toName = jsonObject.getString("toName");//獲取數據中的收消息人的名字
??????? String content = jsonObject.getString("content");//獲取到發送的內容
??????? String fromName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//獲取當前發送消息的人的名字
??????? content = "收到來自:" +fromName+ "的消息,內容是:" + content;
??????? //拼接內容轉發給接收者,實際開發中請參考自己的需求做處理
??????? TextMessage textMessage = new TextMessage(content);//將內容轉換為 TextMessage
??????? sendMessageToUser(toName,textMessage);// 發送給指定的用戶
??????? //sendMessageToUsers(message);//給所有人發送
??????? //super.handleTextMessage(session, message);
??? }
??? /**
???? * 給某個用戶發送消息
???? *
???? * @param userName
???? * @param message
???? */
??? public void sendMessageToUser(String userName, TextMessage message) {
??????? WebSocketSession webSocketSession = allClients.get(userName);//根據接收方的名字找到對應的連接
??????? if (webSocketSession != null&& webSocketSession.isOpen()) {//如果沒有離線,如果離線,請根據實際業務需求來處理,可能會需要保存離線消息
?? ?????????try {
??????????????? webSocketSession.sendMessage(message);//發送消息
??????????? } catch (IOException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
??? }
??? /**
???? * 給所有在線用戶發送消息,此處以文本消息為例子
???? *
???? * @param message
???? */
??? public void sendMessageToUsers(TextMessage message) {
??????? for (Map.Entry<String, WebSocketSession> webSocketSessionEntry : allClients.entrySet()) {//獲取所有的連接
??????????? WebSocketSession session = webSocketSessionEntry.getValue();//找到每個連接
??????????? if (session != null&& session.isOpen()) {
??????????????? try {
??????????????????? session.sendMessage(message);
??????????????? } catch (IOException e) {
??????????????????? e.printStackTrace();
??????????????? }
??????????? }
??????? }
??? }
??? /**
???? * 出現異常的時候
???? * @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("連接關閉");
??????? allClients.remove(name);//移除連接
??? }
??? /**
???? * 連接關閉后
???? * @param session
???? * @param closeStatus
???? * @throws Exception
???? */
??? @Override
??? public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
??????? logger.debug("連接關閉");
??????? String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//找到用戶對應的連接
??????? allClients.remove(name);//移除
??? }
??? @Override
??? public boolean supportsPartialMessages() {
??????? return false;
??? }
}
注意此類最好放在根包下
/**
?* 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??? }
??? }
}
/**
?* Created by jackiechan on 2018/2/5/下午4:34
?用于將項目打包成 war 包后發布
?*/
public class SpringBootStartApplication extends SpringBootServletInitializer {
??? @Override
??? protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
??? {
??????? return builder.sources(App.class);
??? }
}
與非 springboot 的方式內容一致
<!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;
??????????? //判斷當前瀏覽器是否支持WebSocket
??????????? if ('WebSocket' in window) {
??????????????? websocket = new WebSocket("ws://" + document.location.host + "/websocket/"+username);
??????????? } else {
??????????????? alert('當前瀏覽器 Not support websocket')
??????????? }
??????????? //連接發生錯誤的回調方法
??????????? websocket.onerror = function() {
??????????????? setMessageInnerHTML("WebSocket連接發生錯誤");
??????????? };
??????????? //連接成功建立的回調方法
??????????? websocket.onopen = function() {
??????????????? setMessageInnerHTML("WebSocket連接成功");
??????????? }
??????????? //接收到消息的回調方法
??????????? websocket.onmessage = function(event) {
??????????????? setMessageInnerHTML(event.data);
??????????? }
??????????? //連接關閉的回調方法
??????????? websocket.onclose = function() {
??????????????? setMessageInnerHTML("WebSocket連接關閉");
??????????? }
??????????? //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
??????????? window.onbeforeunload = function() {
??????????????? closeWebSocket();
??????????? }
??????? }
??????? /**
???????? * 發送消息
???????? */
??????? function sendmessage() {
??????????? var toName=document.getElementById("to").value;
??????????? if (websocket!=null) {
??????????????? var content=document.getElementById("content").value;
??????????????? var message='{"toName":"'+toName+'","content":"'+content+'"}';//將發送的內容拼接為 json 字符串,服務端用于解析好處理
??????????????? websocket.send(message);
??????????? }
??????? }
??????? //關閉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>
<!--實際接收者應該由用戶選擇,或者由系統安排,比如客服的話,應該是服務端已經存儲了所有在線的客服,用戶只需要發送消息即可,如果是兩個用戶聊天,則應該有用戶列表,選擇后指定目標-->
接收者:<input type="text" id="to" /><br>
內容:<input type="text" id="content" /><br>
<button onclick="sendmessage()">發送</button><br>
<br>
<br>
<br>
<span id="neirong"></span>
</body>
</html>
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。