websocket:因爲http協議時基於 請求-響應模型 服務端的每次響應都必須有客戶端發起(瀏覽器)的請求。若是服務端想主動推送消息到客戶端是很難知足的。java
若是必定想使用http來作服務端主動推進,只能客戶端不停的發起輪詢請求,若是訪問量很很大,這種模式會拖垮服務器。形成很大的通訊開銷和服務端流量壓力。
使用websocket能夠完成要求實時性的應用:股票的變更、天氣、彩票、即時通信、通知。git
WebSocket 是web客戶端和服務器之間新的通信方式, 依然架構在HTTP協議之上。使用WebSocket鏈接, web應用程序能夠執行實時的交互, 而不是之前的poll方式。github
WebSocket是HTML5開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議,能夠用來建立快速的更大規模的健壯的高性能實時的web應用程序。WebSocket通訊協議於2011年被IETF定爲標準RFC 6455,WebSocketAPI被W3C定爲標準。
在WebSocket API中,瀏覽器和服務器只須要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。web
如今大概瞭解了websocket的概念和應用,如今咱們來看看如何在springBoot中集成websocket。spring
建立一個配置類:
使用@Configuration註解 聲明這個類爲配置類。
使用@EnableWebSocket註解代表這是一個websocket配置類,咱們會在這個類配置一些websocket的參數和地址。
咱們的配置類實現WebSocketConfigurer接口。json
重寫registerWebSocketHandlers方法,瀏覽器
//配置指定地址:/demo的處理器,及通訊容許的域名,這裏使用*,表示匹配全部。 webSocketHandlerRegistry.addHandler(new WebSocketDemoHanlder(),"/demo").setAllowedOrigins("*"); /** * @author xuelongjiang */ @Configuration @EnableWebSocket public class WebsocketConfig implements WebSocketConfigurer{ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { webSocketHandlerRegistry.addHandler(new WebSocketDemoHanlder(),"/demo").setAllowedOrigins("*"); } }
這裏咱們主要綁定WebSocketSession和咱們的推送目標。安全
若是是聊天室,則根據約定的規則,進行用戶與用戶,用戶與聊天室的綁定。springboot
若是是彩票,推送消息到全部的WebSocketSession。服務器
package com.xuelongjiang.websocketdemo.websocket; import com.alibaba.fastjson.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author xuelongjiang */ public class WebSocketDemoHanlder extends TextWebSocketHandler { private Logger logger = LoggerFactory.getLogger(WebSocketDemoHanlder.class); private static Map<String,WebSocketSession> userIdSessionMap = new ConcurrentHashMap(); private static Map<WebSocketSession,String> sessionUserIdMap = new ConcurrentHashMap<>(); @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String payload = message.getPayload(); logger.info("websocket請求參數payload:{}",payload); JSONObject jsonObject = JSONObject.parseObject(payload); String action = jsonObject.getString("action"); if("register".equals(action)){ logger.info("註冊websocket鏈接"); String userId = jsonObject.getString("userId"); logger.info("userId:{}註冊session:{}",userId,session.getId()); userIdSessionMap.put(userId,session); sessionUserIdMap.put(session,userId); } } //定時任務獲取session public static Map<String,WebSocketSession> getUserIdSessionMap(){ return userIdSessionMap; } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { //鏈接關閉後移除 String userId = sessionUserIdMap.get(session); userIdSessionMap.remove(userId); logger.info("websocket session:{}關閉緣由:{}",session,status); } }
到這裏咱們測試一下是否能夠鏈接。
從上面能夠看到咱們已經和服務端創建了鏈接。
websocketSession:能夠理解爲http的一個會話。會話記錄了這一次的通信對象,咱們可使用seesion發送消息給客戶端。
在上面咱們用一個線程安全的map,存儲了userId和websocketSession的關係。如今咱們用定時任務來發送消息給鏈接。
在springboot啓動類增長註解@EnableScheduling
因爲websocket和定時任務啓動的時候會報錯。的時候會報錯。增長taskScheduler()方法。
@SpringBootApplication @EnableScheduling public class WebsocketdemoApplication { public static void main(String[] args) { SpringApplication.run(WebsocketdemoApplication.class, args); } /** * 使用 websockt註解的時候,使用@EnableScheduling註解 * 啓動的時候一直報錯,增長這個bean 則報錯解決。 * 報錯信息: Unexpected use of scheduler. *https://stackoverflow.com/questions/49343692/websocketconfigurer-and-scheduled-are-not-work-well-in-an-application * * @return */ @Bean public TaskScheduler taskScheduler(){ ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); return taskScheduler; } }
package com.xuelongjiang.websocketdemo.schedule; import com.xuelongjiang.websocketdemo.websocket.WebSocketDemoHanlder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import java.util.Map; /** * 定時任務 * @author xuelongjiang */ @Service public class ScheduleTask { private Logger logger = LoggerFactory.getLogger(ScheduleTask.class); @Scheduled(cron = "* * 0/1 * * ?") public void sendMessage(){ String message = "你好"; Map<String,WebSocketSession> map = WebSocketDemoHanlder.getUserIdSessionMap(); WebSocketSession session = map.get("xuelongjiang");//這裏用戶ID的獲取能夠根據具體業務,這裏爲了更簡單的演示。 if(session != null){ try { session.sendMessage(new TextMessage(message)); }catch (Exception e){ logger.error("定時任務異常:{}",e); } } } }
websocket測試地址:http://www.blue-zero.com/WebS...
源碼地址:https://github.com/longjiangx...
關注個人公衆號第一時間閱讀有趣的技術故事
掃碼關注:
也能夠在微信搜索公衆號便可關注我:codexiulian 渴望與你一塊兒成長進步!