Bootstrap

Java Web数据可视化(五)通过WebSocket对推送的数据进行更新页面

之前用的轮询方法有些缺点,发出读取请求的频率是固定的,在数据更新频率较慢的时候会占用过多的资源做无用功,在数据更新频率较快的时候读取的数据可能是已经更新过多次的,遗漏了部分数据或读到的是伪实时数据。

而使用WebSocket方法获取数据,是当数据更新时会推送过来,无论数据更新的频率是快还是慢都能很好的展示数据

下面贴代码:
首先是websocket的

package scoket;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/web")
public class WebSocket_machine1 {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static CopyOnWriteArraySet<WebSocket_machine1> webSocketSet = new CopyOnWriteArraySet<WebSocket_machine1>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("当前在线人数:" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        System.out.println("当前在线人数:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        //群发消息
        for(WebSocket_machine1 item: webSocketSet){
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }

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

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket_machine1.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket_machine1.onlineCount--;
    }
}

页面,具体的页面就没放完了,只截了部分

<%--
  Created by IntelliJ IDEA.
  User: Jigubigu
  Date: 2018/12/10
  Time: 16:47
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>数据监控</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">>
    <script src="http://cdn.bootcss.com/jquery/1.11.2/jquery.min.js"></script>
    <script type="text/javascript" src="js/echarts.js"></script>
    <script type="text/javascript" src="js/realTimeData.js"></script>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.css">
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default navbar-static-top">
<div class="container-fluid">
    <div class="navbar-header">
        <a class="navbar-brand" href="#">智能制造</a>
    </div>
    <div>
        <ul class="nav navbar-nav">
            <li class="active"><a href="login.jsp">首页</a></li>
            <li><a href="machinList.jsp">机器选择</a></li>
            <li><a href="/refrash">刷新页面</a>
            </li>
        </ul>
    </div>
</div>
</nav>
<div class="jumbotron" id="realTime" name="realTimeData" style="padding:0px;height: 30%">
                <div id="realTimeData" name="realTimeData" style="height: 120%;width: 120%; padding: 0%;right:7%"></div>
                <%
                    String machineId = (String)request.getParameter("machineId");
                    System.out.println("machineId is: " + machineId);
                    session.setAttribute("machineId", machineId);
                %>
</div>
</body>

js代码:realTimeData.js

    var machine = ${machineId};//上一页面传来的机器ID
               var myChart2 = echarts.init(document.getElementById('realTimeData'));
               var option2 = {
                   tooltip : {
                       formatter: "{a} <br/>{b} : {c}w"
                   },
                   toolbox: {
                       feature: {
                           restore: {},
                           saveAsImage: {}
                       }
                   },
                   series: [
                       {
                           min:0,
                           max:400,
                           splitNumber:5,
                           name: '机器能耗',
                           type: 'gauge',
                           detail: {formatter:'{value}w'},
                           data: [{value: 50, name: ''}]
                       }
                   ]
               };



               //将消息显示在网页上
               function setMessageInnerHTML(data) {
                   option2.series[0].data[0].value = data;
                   myChart2.setOption(option2, true);
                   console.log("data from WebSocket::" + data);
               }

               //关闭WebSocket连接
               function closeWebSocket() {
                   websocket.close();
               }
               $(document).ready(function start() {
                   var websocket = null;
                   //判断当前浏览器是否支持WebSocket
                   if ('WebSocket' in window) {
                       //这里的machine是我读到的机器号,使用时需要和WebSocket.java文件里的@ServerEndpoint("/创建的websocket要和这里的参数相同")
                       websocket = new WebSocket("ws://192.168.1.116:8080/" + machine);
                   }
                   else {
                       alert('当前浏览器 Not support websocket')
                   }

                   //连接发生错误的回调方法
                   websocket.onerror = function () {
                       setMessageInnerHTML("WebSocket连接发生错误");
                   };

                   //连接成功建立的回调方法
                   websocket.onopen = function () {
                       setMessageInnerHTML("WebSocket连接成功");
                   }

                   //接收到消息的回调方法
                   websocket.onmessage = function (event) {
                       setMessageInnerHTML(event.data);
                   }

                   //连接关闭的回调方法
                   websocket.onclose = function () {
                       setMessageInnerHTML("WebSocket连接关闭");
                   }

                   //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
                   window.onbeforeunload = function () {
                       closeWebSocket();
                   }
               })

测试用页面

<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
    Welcome<br/><input id="text" type="text"/>
    <button onclick="send()">发送消息</button>
    <hr/>
    <button onclick="closeWebSocket()">关闭WebSocket连接</button>
    <hr/>
    <div id="message"></div>
</body>

<script type="text/javascript">
    var websocket = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://192.168.1.116:8080/1");
    }
    else {
        alert('当前浏览器 Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("WebSocket连接发生错误");
    };

    //连接成功建立的回调方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket连接关闭");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }

    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

WebSoket页面和测试用页面参考二部websocket聊天室的建立

;