Springboot整合Websocket實現后端向前端主動推送消息案例
在手機上相信都有來自服務器的推送消息,比如一些及時的新聞信息,這篇文章主要就是實現這個功能,只演示一個基本的案例。使用的是websocket技術。
一、什么是websocke
tWebSocket協議是基于TCP的一種新的網絡協議。它實現了客戶端與服務器全雙工通信,學過計算機網絡都知道,既然是全雙工,就說明了服務器可以主動發送信息給客戶端。這與我們的推送技術或者是多人在線聊天的功能不謀而合。
為什么不使用HTTP 協議呢?這是因為HTTP是單工通信,通信只能由客戶端發起,客戶端請求一下,服務器處理一下,這就太麻煩了。于是websocket應運而生。
下面我們就直接開始使用Springboot開始整合。以下案例都在我自己的電腦上測試成功,你可以根據自己的功能進行修改即可。
二、整合websocket
1、環境配置
Idea 2018專業版(已破解)
Maven 4.0.0
SpringBoot 2.2.2
websocket 2.1.3
jdk 1.8
下面我們新建一個普通的Springboot項目。
2、添加依賴
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-websocket</artifactId>
- <version>2.1.3.RELEASE</version>
- </dependency>
- </dependencies>
3、在application.properties文件修改端口號
一句話:server.port=8081
4、新建config包,創建WebSocketConfig類
- 1@Configuration
- 2public class WebSocketConfig {
- 3 @Bean
- 4 public ServerEndpointExporter serverEndpointExporter() {
- 5 return new ServerEndpointExporter();
- 6 }
- 7}
5、新建service包,創建WebSocketServer類
- @ServerEndpoint("/websocket/{sid}")
- @Component
- public class WebSocketServer {
- static Log log= LogFactory.getLog(WebSocketServer.class);
- //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。
- private static int onlineCount = 0;
- //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。
- private static CopyOnWriteArraySet<WebSocketServer> webSocketSet
- = new CopyOnWriteArraySet<WebSocketServer>();
- //與某個客戶端的連接會話,需要通過它來給客戶端發送數據
- private Session session;
- //接收sid
- private String sid="";
- /**
- * 連接建立成功調用的方法
- */
- @OnOpen
- public void onOpen(Session session,@PathParam("sid") String sid) {
- this.session = session;
- webSocketSet.add(this); //加入set中
- addOnlineCount(); //在線數加1
- log.info("有新窗口開始監聽:"+sid+",當前在線人數為" + getOnlineCount());
- this.sid=sid;
- try {
- sendMessage("連接成功");
- } catch (IOException e) {
- log.error("websocket IO異常");
- }
- }
- /**
- * 連接關閉調用的方法
- */
- @OnClose
- public void onClose() {
- webSocketSet.remove(this); //從set中刪除
- subOnlineCount(); //在線數減1
- log.info("有一連接關閉!當前在線人數為" + getOnlineCount());
- }
- /**
- * 收到客戶端消息后調用的方法
- * @param message 客戶端發送過來的消息
- */
- @OnMessage
- public void onMessage(String message, Session session) {
- log.info("收到來自窗口"+sid+"的信息:"+message);
- //群發消息
- for (WebSocketServer item : webSocketSet) {
- try {
- item.sendMessage(message);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- @OnError
- public void onError(Session session, Throwable error) {
- log.error("發生錯誤");
- error.printStackTrace();
- }
- //實現服務器主動推送
- public void sendMessage(String message) throws IOException {
- this.session.getBasicRemote().sendText(message);
- }
- //群發自定義消息
- public static void sendInfo(String message,@PathParam("sid") String sid)
- throws IOException {
- log.info("推送消息到窗口"+sid+",推送內容:"+message);
- for (WebSocketServer item : webSocketSet) {
- try {
- //這里可以設定只推送給這個sid的,為null則全部推送
- if(sid==null) {
- item.sendMessage(message);
- }else if(item.sid.equals(sid)){
- item.sendMessage(message);
- }
- } catch (IOException e) {
- continue;
- }
- }
- }
- public static synchronized int getOnlineCount() {
- return onlineCount;
- }
- public static synchronized void addOnlineCount() {
- WebSocketServer.onlineCount++;
- }
- public static synchronized void subOnlineCount() {
- WebSocketServer.onlineCount--;
- }
6、新建controller包,創建Mycontroller類
- @Controller
- public class MyController {
- //頁面請求
- @GetMapping("/socket/{cid}")
- public ModelAndView socket(@PathVariable String cid) {
- ModelAndView mav=new ModelAndView("/socket");
- mav.addObject("cid", cid);
- return mav;
- }
- //推送數據接口
- @ResponseBody
- @RequestMapping("/socket/push/{cid}")
- public String pushToWeb(@PathVariable String cid,String message) {
- try {
- WebSocketServer.sendInfo(message,cid);
- } catch (IOException e) {
- e.printStackTrace();
- return "推送失敗";
- }
- return "發送成功";
- }
- }}
7、新建一個websocket.html頁面
- <html>
- <head>
- <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
- <script type="text/javascript">
- var socket;
- if (typeof (WebSocket) == "undefined") {
- console.log("您的瀏覽器不支持WebSocket");
- } else {
- console.log("您的瀏覽器支持WebSocket");
- //實現化WebSocket對象,指定要連接的服務器地址與端口 建立連接
- socket = new WebSocket("ws://localhost:8081/websocket/1");
- //打開事件
- socket.onopen = function () {
- console.log("Socket 已打開");
- socket.send("這是來自客戶端的消息" + location.href + new Date());
- };
- //獲得消息事件
- socket.onmessage = function (msg) {
- console.log(msg.data);
- };
- //關閉事件
- socket.onclose = function () {
- console.log("Socket已關閉");
- };
- //發生了錯誤事件
- socket.onerror = function () {
- alert("Socket發生了錯誤");
- }
- }
- </script>
- </head>
- </html>
現在開發服務器和網頁就可以看到效果了。一般情況下Springboot2+Netty+Websocket的組合方式更加的常用一下。這個只是給出了一個基本的案例,你可以根據自己的需求進行更改。
本文轉載自微信公眾號「愚公要移山」,可以通過以下二維碼關注。轉載本文請聯系愚公要移山公眾號。