Springboot整合Websocket實(shí)現(xiàn)后端向前端主動(dòng)推送消息案例
在手機(jī)上相信都有來(lái)自服務(wù)器的推送消息,比如一些及時(shí)的新聞信息,這篇文章主要就是實(shí)現(xiàn)這個(gè)功能,只演示一個(gè)基本的案例。使用的是websocket技術(shù)。
一、什么是websocke
tWebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。它實(shí)現(xiàn)了客戶端與服務(wù)器全雙工通信,學(xué)過(guò)計(jì)算機(jī)網(wǎng)絡(luò)都知道,既然是全雙工,就說(shuō)明了服務(wù)器可以主動(dòng)發(fā)送信息給客戶端。這與我們的推送技術(shù)或者是多人在線聊天的功能不謀而合。
為什么不使用HTTP 協(xié)議呢?這是因?yàn)镠TTP是單工通信,通信只能由客戶端發(fā)起,客戶端請(qǐng)求一下,服務(wù)器處理一下,這就太麻煩了。于是websocket應(yīng)運(yùn)而生。
下面我們就直接開始使用Springboot開始整合。以下案例都在我自己的電腦上測(cè)試成功,你可以根據(jù)自己的功能進(jìn)行修改即可。
二、整合websocket
1、環(huán)境配置
Idea 2018專業(yè)版(已破解)
Maven 4.0.0
SpringBoot 2.2.2
websocket 2.1.3
jdk 1.8
下面我們新建一個(gè)普通的Springboot項(xiàng)目。
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文件修改端口號(hào)
一句話:server.port=8081
4、新建config包,創(chuàng)建WebSocketConfig類
- 1@Configuration
 - 2public class WebSocketConfig {
 - 3 @Bean
 - 4 public ServerEndpointExporter serverEndpointExporter() {
 - 5 return new ServerEndpointExporter();
 - 6 }
 - 7}
 
5、新建service包,創(chuàng)建WebSocketServer類
- @ServerEndpoint("/websocket/{sid}")
 - @Component
 - public class WebSocketServer {
 - static Log log= LogFactory.getLog(WebSocketServer.class);
 - //靜態(tài)變量,用來(lái)記錄當(dāng)前在線連接數(shù)。應(yīng)該把它設(shè)計(jì)成線程安全的。
 - private static int onlineCount = 0;
 - //concurrent包的線程安全Set,用來(lái)存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象。
 - private static CopyOnWriteArraySet<WebSocketServer> webSocketSet
 - = new CopyOnWriteArraySet<WebSocketServer>();
 - //與某個(gè)客戶端的連接會(huì)話,需要通過(guò)它來(lái)給客戶端發(fā)送數(shù)據(jù)
 - private Session session;
 - //接收sid
 - private String sid="";
 - /**
 - * 連接建立成功調(diào)用的方法
 - */
 - @OnOpen
 - public void onOpen(Session session,@PathParam("sid") String sid) {
 - this.session = session;
 - webSocketSet.add(this); //加入set中
 - addOnlineCount(); //在線數(shù)加1
 - log.info("有新窗口開始監(jiān)聽:"+sid+",當(dāng)前在線人數(shù)為" + getOnlineCount());
 - this.sid=sid;
 - try {
 - sendMessage("連接成功");
 - } catch (IOException e) {
 - log.error("websocket IO異常");
 - }
 - }
 - /**
 - * 連接關(guān)閉調(diào)用的方法
 - */
 - @OnClose
 - public void onClose() {
 - webSocketSet.remove(this); //從set中刪除
 - subOnlineCount(); //在線數(shù)減1
 - log.info("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount());
 - }
 - /**
 - * 收到客戶端消息后調(diào)用的方法
 - * @param message 客戶端發(fā)送過(guò)來(lái)的消息
 - */
 - @OnMessage
 - public void onMessage(String message, Session session) {
 - log.info("收到來(lái)自窗口"+sid+"的信息:"+message);
 - //群發(fā)消息
 - for (WebSocketServer item : webSocketSet) {
 - try {
 - item.sendMessage(message);
 - } catch (IOException e) {
 - e.printStackTrace();
 - }
 - }
 - }
 - @OnError
 - public void onError(Session session, Throwable error) {
 - log.error("發(fā)生錯(cuò)誤");
 - error.printStackTrace();
 - }
 - //實(shí)現(xiàn)服務(wù)器主動(dòng)推送
 - public void sendMessage(String message) throws IOException {
 - this.session.getBasicRemote().sendText(message);
 - }
 - //群發(fā)自定義消息
 - public static void sendInfo(String message,@PathParam("sid") String sid)
 - throws IOException {
 - log.info("推送消息到窗口"+sid+",推送內(nèi)容:"+message);
 - for (WebSocketServer item : webSocketSet) {
 - try {
 - //這里可以設(shè)定只推送給這個(gè)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包,創(chuàng)建Mycontroller類
- @Controller
 - public class MyController {
 - //頁(yè)面請(qǐng)求
 - @GetMapping("/socket/{cid}")
 - public ModelAndView socket(@PathVariable String cid) {
 - ModelAndView mav=new ModelAndView("/socket");
 - mav.addObject("cid", cid);
 - return mav;
 - }
 - //推送數(shù)據(jù)接口
 - @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 "發(fā)送成功";
 - }
 - }}
 
7、新建一個(gè)websocket.html頁(yè)面
- <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");
 - //實(shí)現(xiàn)化WebSocket對(duì)象,指定要連接的服務(wù)器地址與端口 建立連接
 - socket = new WebSocket("ws://localhost:8081/websocket/1");
 - //打開事件
 - socket.onopen = function () {
 - console.log("Socket 已打開");
 - socket.send("這是來(lái)自客戶端的消息" + location.href + new Date());
 - };
 - //獲得消息事件
 - socket.onmessage = function (msg) {
 - console.log(msg.data);
 - };
 - //關(guān)閉事件
 - socket.onclose = function () {
 - console.log("Socket已關(guān)閉");
 - };
 - //發(fā)生了錯(cuò)誤事件
 - socket.onerror = function () {
 - alert("Socket發(fā)生了錯(cuò)誤");
 - }
 - }
 - </script>
 - </head>
 - </html>
 
現(xiàn)在開發(fā)服務(wù)器和網(wǎng)頁(yè)就可以看到效果了。一般情況下Springboot2+Netty+Websocket的組合方式更加的常用一下。這個(gè)只是給出了一個(gè)基本的案例,你可以根據(jù)自己的需求進(jìn)行更改。
本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。
















 
 
 















 
 
 
 