第四部分-WebSocket后端轮询代替Ajax轮询

WebSocket后端轮询代替Ajax轮询

Websocket服务端可以主动推送信息给客户端,解决了http轮询延迟的问题
同时解决服务器上消耗资源的问题
由于Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求
目前唯一的问题是:不兼容低版本的IE

后端轮询逻辑

    @Scheduled(cron = "*/5 * * * * ?")//五秒轮询
    public void TimeStampsSearch() {
        try {
            //第一次没有取到值时
            if (currentTimeList == null) {
                currentTimeList = webSocketService.getAllTimeStamps();

            } else {
                //当不是第一次,取到了值
                List<WeiBoNewModel> newTimeList = webSocketService.getAllTimeStamps();
                    //循环判断时间是否修改了
                    for (int i = 0; i < currentTimeList.size(); i++) {
                        if (currentTimeList.size()!=newTimeList.size()) {
                            System.out.println("list长度不相等");
                            System.out.println("数据更新了");
                            socket.sendInfo("10", "1");
                            break;
                        }
                        if (!currentTimeList.get(i).getOnboardTime().equals(newTimeList.get(i).getOnboardTime())) {
                            System.out.println("数据时间不一致");
                            System.out.println("数据更新了");
                            socket.sendInfo("10", "1");
                            break;
                        }
                    }
                    currentTimeList = newTimeList;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

全部代码

注:本部分内容需要上部分的SpringBoot程序
https://blog.csdn.net/weixin_43596589/article/details/115655246

第一步

在service下创建WebSocketService .java

public interface WebSocketService {
    List<WeiBoNewModel> getAllTimeStamps();
}

第二步

在mapper下创建WebSocketMapper.java

@Mapper
public interface WebSocketMapper {
    List<WeiBoNewModel> getAllTimeStamps();
}

第三步

在serviceImpl下创建WebSocketServiceImpl .java

@Service("webSocketService")
public class WebSocketServiceImpl implements WebSocketService {
    @Autowired
    private WebSocketMapper webSocketMapper;
    @Override
    public List<WeiBoNewModel> getAllTimeStamps() {
        return webSocketMapper.getAllTimeStamps();
    }
}

第四步

在resources/mapper下创建WeiboMapper.xml

<mapper namespace="bx.springChart.demoProject.mapper.WebSocketMapper">
    <resultMap id="WebSocketMap" type="bx.springChart.demoProject.model.WeiBoNewModel">
        <result column="id" jdbcType="INTEGER" property="id"/>
        <result column="onboard_time" jdbcType="BIGINT" property="onboardTime"/>
    </resultMap>
    <select id="getAllTimeStamps" resultMap="WebSocketMap">
    SELECT * FROM db_weibo_content
    </select>
</mapper>

第五步

新建socket文件夹,在其下创建WebSocketServer.java

package bx.springChart.demoProject.socket;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint("/webSocket/{sid}")
@Component
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static AtomicInteger onlineNum = new AtomicInteger();

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }
    //给指定用户发送信息
    public void sendInfo(String userName, String message){
        Session session = sessionPools.get(userName);
        try {
            sendMessage(session, message);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "sid") String userName){
        sessionPools.put(userName, session);
        addOnlineCount();
        System.out.println(userName + "加入webSocket!当前人数为" + onlineNum);
        try {
            sendMessage(session, "欢迎" + userName + "加入连接!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "sid") String userName){
        sessionPools.remove(userName);
        subOnlineCount();
        System.out.println(userName + "断开webSocket连接!当前人数为" + onlineNum);
    }

    //收到客户端信息
    @OnMessage
    public void onMessage(String message) throws IOException{
        message = "客户端:" + message + ",已收到";
        System.out.println(message);
        for (Session session: sessionPools.values()) {
            try {
                sendMessage(session, message);
            } catch(Exception e){
                e.printStackTrace();
                continue;
            }
        }
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable){
        System.out.println("发生错误");
        throwable.printStackTrace();
    }

    public static void addOnlineCount(){
        onlineNum.incrementAndGet();
    }

    public static void subOnlineCount() {
        onlineNum.decrementAndGet();
    }

}

第六步

新建repository文件夹,在其下创建WebSocketConfig.java

package bx.springChart.demoProject.repository;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    /**
     * ServerEndpointExporter 作用
     *
     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

第七步

新建schedule文件夹,在其下创建WeiBoCheckSchedule .java

package bx.springChart.demoProject.schedule;

import bx.springChart.demoProject.model.WeiBoNewModel;
import bx.springChart.demoProject.service.WebSocketService;
import bx.springChart.demoProject.socket.WebSocketServer;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;


/**
 * 警情定时器,通知websocket
 * author:robert
 */
@Component
public class WeiBoCheckSchedule {

    @Resource
    private WebSocketService webSocketService;
    private List<WeiBoNewModel> currentTimeList = null;
    private WebSocketServer socket = new WebSocketServer();

    /**
     *
     */
    @Scheduled(cron = "*/5 * * * * ?")//五秒轮询
    public void TimeStampsSearch() {
        try {
            if (currentTimeList == null) {
                currentTimeList = webSocketService.getAllTimeStamps();

            } else {
                List<WeiBoNewModel> newTimeList = webSocketService.getAllTimeStamps();

                    for (int i = 0; i < currentTimeList.size(); i++) {
                        if (currentTimeList.size()!=newTimeList.size()) {
                            System.out.println("list长度不相等");
                            System.out.println("数据更新了");
                            socket.sendInfo("10", "1");
                            break;
                        }
                        if (!currentTimeList.get(i).getOnboardTime().equals(newTimeList.get(i).getOnboardTime())) {
                            System.out.println("数据时间不一致");
                            System.out.println("数据更新了");
                            socket.sendInfo("10", "1");
                            break;
                        }
                    }
                    currentTimeList = newTimeList;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

第八步

在echartApplication.java中添加@EnableScheduling注解

第九步

将weiBoTopReDraw.html中87行的定时轮询方法注释

    //设定每30秒执行一次ajax
    //setInterval(function () {
    //    aJax();
    //    run();
    //}, 30000);

添加以下script

<script>
    let websocket = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //建立连接,这里的/websocket ,是ManagerServlet中开头注解中的那个值
        websocket = new WebSocket("ws://localhost:8081/webSocket/10");
    }
    else {
        alert('当前浏览器不支持websocket')
    }
    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("WebSocket连接发生错误");
    };
    //连接成功建立的回调方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket连接成功");
    }
    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
        if(event.data=="1"){
            // location.reload();
            aJax();
            run();
            //console.log("接到了响应,调用了AJAX");
        }
    }
    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket连接关闭");
    }
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        // document.getElementById('message').innerHTML += innerHTML + '<br/>';
        console.log(innerHTML);
    }
    //关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }
</script>

目录结构

如下
在这里插入图片描述

运行效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值