Springboot整合Websocket实现后端向前端主动推送消息案例

开发 架构
在手机上相信都有来自服务器的推送消息,比如一些及时的新闻信息,这篇文章主要就是实现这个功能,只演示一个基本的案例。使用的是websocket技术。

[[389702]]

在手机上相信都有来自服务器的推送消息,比如一些及时的新闻信息,这篇文章主要就是实现这个功能,只演示一个基本的案例。使用的是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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

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} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 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--; 
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.

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 "发送成功"
    } 
}} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

 

现在开发服务器和网页就可以看到效果了。一般情况下Springboot2+Netty+Websocket的组合方式更加的常用一下。这个只是给出了一个基本的案例,你可以根据自己的需求进行更改。

本文转载自微信公众号「愚公要移山」,可以通过以下二维码关注。转载本文请联系愚公要移山公众号。

 

责任编辑:武晓燕 来源: 愚公要移山
相关推荐

2021-02-05 07:28:11

SpringbootNettyWebsocke

2023-08-09 08:01:00

WebSockett服务器web

2021-03-25 08:29:33

SpringBootWebSocket即时消息

2023-08-14 08:01:12

websocket8g用户

2024-09-11 08:35:54

2024-09-02 09:31:19

2024-08-02 09:00:17

NettyWebSocketNIO

2023-01-05 09:17:58

2023-01-13 00:02:41

2023-09-04 08:00:53

提交事务消息

2023-10-12 08:00:48

2024-11-14 12:22:37

SpringMail邮件

2021-04-15 09:17:01

SpringBootRocketMQ

2017-05-09 10:07:34

SpringbootDubboZooKeeper

2024-09-12 14:50:08

2022-06-28 08:37:07

分布式服务器WebSocket

2024-11-14 11:56:45

2022-01-10 11:58:51

SpringBootPulsar分布式

2013-05-17 15:34:45

2023-07-26 07:28:55

WebSocket服务器方案
点赞
收藏

51CTO技术栈公众号