java消息推送怎么实现_SpringBoot整合WebSocket实现消息推送

最近想起之前项目里面的一个实现,是关于订阅推送的,当粉丝订阅了大V或者说作者发布的内容被评论和点赞之后,对应的用户会受到通知,当然,本身系统用户并不多,所以直接采用的是轮训的方式,由前端这边定时向后端发起接口请求,获取消息推送,无疑呢,此种方式也可以解决问题,但是大部分请求基本无用,白白浪费带宽和网络资源。

今天难得媳妇儿带孩子回娘家了,下班到家也无事,便想着整理下前后端通过websocket实现消息推送的方式。当然,前端这块,主要采用原始的js通过websocket的方式获取消息,在微信公众号和支付宝小程序开发中都有相应的onWebSocekt方式,有兴趣的同学可以自行学习。

废话不多说,开始啃代码。

1、pom.xml

        <dependency>            <groupId>org.springframework.bootgroupId>            <artifactId>spring-boot-starter-websocketartifactId>        dependency>                <dependency>            <groupId>org.springframework.bootgroupId>            <artifactId>spring-boot-starter-thymeleafartifactId>        dependency>

2、application.yml

server:  port: 8080spring:  thymeleaf:    cache: false # 开发时关闭缓存,不然没法看到实时页面    mode: HTML # 用非严格的 HTML    encoding: UTF-8    servlet:      content-type: text/html

3、WebSocketServer,实现前后端的长连接

package com.cookie.server;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;/** * @Author : cxq * @Date : 2020/8/31 15:50 */// 前端通过该连接与后端保持交互@ServerEndpoint(value = "/server")@Componentpublic class WebSocketServer {    @PostConstruct    public void init() {        System.out.println("websocket 加载");    }    private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);    private static final AtomicInteger OnlineCount = new AtomicInteger(0);    // concurrent包的线程安全Set,用来存放每个客户端对应的Session对象。    private static CopyOnWriteArraySet SessionSet = new CopyOnWriteArraySet();    /**     * 连接建立成功调用的方法     */    @OnOpen    public void onOpen(Session session) {        SessionSet.add(session);        int cnt = OnlineCount.incrementAndGet(); // 在线数加1        log.info("有连接加入,当前连接数为:{}", cnt);        SendMessage(session, "连接成功");    }    /**     * 连接关闭调用的方法     */    @OnClose    public void onClose(Session session) {        SessionSet.remove(session);        int cnt = OnlineCount.decrementAndGet();        log.info("有连接关闭,当前连接数为:{}", cnt);    }    /**     * 收到客户端消息后调用的方法     *     * @param message     *            客户端发送过来的消息     */    @OnMessage    public void onMessage(String message, Session session) {        log.info("来自客户端的消息:{}",message);        SendMessage(session, "收到消息,消息内容:"+message);    }    /**     * 出现错误     * @param session     * @param error     */    @OnError    public void onError(Session session, Throwable error) {        log.error("发生错误:{},Session ID:{}",error.getMessage(),session.getId());        error.printStackTrace();    }    /**     * 发送消息,实践表明,每次浏览器刷新,session会发生变化。     * @param session     * @param message     */    public static void SendMessage(Session session, String message) {        try {//            session.getBasicRemote().sendText(String.format("%s (From Server,Session ID=%s)",message,session.getId()));            session.getBasicRemote().sendText(message);        } catch (IOException e) {            log.error("发送消息出错:{}", e.getMessage());            e.printStackTrace();        }    }    /**     * 群发消息     * @param message     * @throws IOException     */    public static void BroadCastInfo(String message) throws IOException {        for (Session session : SessionSet) {            if(session.isOpen()){                SendMessage(session, message);            }        }    }    /**     * 指定Session发送消息     * @param sessionId     * @param message     * @throws IOException     */    public static void SendMessage(String message,String sessionId) throws IOException {        Session session = null;        for (Session s : SessionSet) {            if(s.getId().equals(sessionId)){                session = s;                break;            }        }        if(session!=null){            SendMessage(session, message);        }        else{            log.warn("没有找到你指定ID的会话:{}",sessionId);        }    }}

4、WebSocketController,主要实现消息群发和一对一发送

package com.cookie.controller;import com.cookie.server.WebSocketServer;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import java.io.IOException;/** * @Author : cxq * @Date : 2020/8/31 16:19 */@RestController@RequestMapping("/webSocket")public class WebSocketController {    /**     * 群发消息内容     *     * @param message     * @return     */    @RequestMapping(value = "/sendAll", method = RequestMethod.GET)    public String sendAllMessage(@RequestParam(required = true) String message) {        try {            WebSocketServer.BroadCastInfo(message);        } catch (IOException e) {            e.printStackTrace();        }        return "ok";    }    /**     * 指定会话ID发消息     *     * @param message 消息内容     * @param id      连接会话ID     * @return     */    @RequestMapping(value = "/sendOne", method = RequestMethod.GET)    public String sendOneMessage(@RequestParam(required = true) String message,                                 @RequestParam(required = true) String id) {        try {            WebSocketServer.SendMessage(message, id);        } catch (IOException e) {            e.printStackTrace();        }        return "ok";    }}

5、index.html接收后端发送的消息及展示

<html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>websocket测试title>    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">script>    <style type="text/css">        h3,h4{            text-align:center;        }style>head><body><h3>WebSocket测试,客户端接收到的消息如下:h3><textarea id = "messageId" readonly="readonly" cols="150" rows="30" >textarea><script type="text/javascript">    var socket;    if (typeof (WebSocket) == "undefined") {        console.log("遗憾:您的浏览器不支持WebSocket");    } else {        console.log("恭喜:您的浏览器支持WebSocket");        //实现化WebSocket对象        //指定要连接的服务器地址与端口建立连接        //注意ws、wss使用不同的端口。我使用自签名的证书测试,        //无法使用wss,浏览器打开WebSocket时报错        //ws对应http、wss对应https。        socket = new WebSocket("ws://localhost:8080/server");        //连接打开事件        socket.onopen = function() {            console.log("Socket 已打开");            socket.send("消息发送测试(From Client)");        };        //收到消息事件        socket.onmessage = function(msg) {            $("#messageId").append(msg.data+ "\n");            console.log(msg.data  );        };        //连接关闭事件        socket.onclose = function() {            console.log("Socket已关闭");        };        //发生了错误事件        socket.onerror = function() {            alert("Socket发生了错误");        }        //窗口关闭时,关闭连接        window.unload=function() {            socket.close();        };    }script>body>html>

6、启动项目,访问页面看效果

  访问 localhost:8080,网页展示如下

ba57e18c8c43a0f543500dce55d717c8.png

多看几个页面,页面展示内容都一样,同时后端控制台打印消息如下

3a86c1635f877cc0ac2a2939f9bf6084.png

接下来,使用postman,依次调用一对一消息推送和群发消息

一对一:http://localhost:8080/webSocket/sendOne?message="这是一条单个消息"&id=1

页面展示如下:

9c5346eb4278cd839930b223e21c90f0.png

群发消息:http://localhost:8080/webSocket/sendAll?message="这是一条群发消息"

页面展示如下:

bff3c1bdf56421162002715db43d4493.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值