• websocket实现数据库更新时前端页面实时刷新


    如题,实现以上功能,我知道主要有两大种思路:
    
    轮询:轮询的原理是隔一段时间向服务器发送一个请求,这里不累述。这里主要谈一下第二种思路。
    websocket进行前后端通讯:websocket是html5的新协议,基于TCP,在一次握手后,建立http连接,实现客户端与服务端全双工通信。相比较轮询机制,节约资源,不需要频繁的请求。
    下面通过最精简的javaweb+mysql实例说明,只贴出关键代码。(原码放在github中,里面有本例需要的websocket-api.jar,.sql文件以及README.doc,方便理解本例)。
    
    user.jsp:
    <%@ page import="model.UserBean" %>
    <%@ page import="java.util.List" %>
    <%@ page import="fun.Client" %>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>$Title$</title>
      </head>
      <body>
        <table  id="table" border="1">
          <tr>
            <th >id</th>
            <th >name</th>
          </tr>
          <%
            //的到数据库信息,放在list中
            Client client=new Client();
            List<UserBean> list= client.list();
            if(list != null){
              for(UserBean user : list){
          %>
          <tr >
            <td ><%=user.getId()%></td>
            <td ><%=user.getName()%></td>
          </tr>
          <%
              }
            }
          %>
        </table>
        <div id="message"></div>
    
      <script>
          var websocket = null;
          //判断当前浏览器是否支持WebSocket
          if ('WebSocket' in window) {
        //建立连接,这里的/websocket ,是ManagerServlet中开头注解中的那个值
              websocket = new WebSocket("ws://localhost:8080/websocket");
          }
          else {
              alert('当前浏览器 Not support websocket')
          }
          //连接发生错误的回调方法
          websocket.onerror = function () {
              setMessageInnerHTML("WebSocket连接发生错误");
          };
          //连接成功建立的回调方法
          websocket.onopen = function () {
              setMessageInnerHTML("WebSocket连接成功");
          }
          //接收到消息的回调方法
          websocket.onmessage = function (event) {
              setMessageInnerHTML(event.data);
              if(event.data=="1"){
                  location.reload();
              }
          }
          //连接关闭的回调方法
          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();
          }
      </script>
      </body>
    </html>
    
    前面插入的java代码得到数据库中的信息,后面的js代码实现websocket通讯。
    
    ManagerServlet.java:
    package fun;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.sql.PreparedStatement;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    /**
     * 这个类即实现了进行数据库操作的Servlet类,又实现了Websocket的功能.
     */
    
    //该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket,类似Servlet的注解mapping;
    // servlet的注册放在了web.xml中。
    @ServerEndpoint(value = "/websocket")
    public class ManagerServlet extends HttpServlet {
        //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
        private static CopyOnWriteArraySet<ManagerServlet> webSocketSet = new CopyOnWriteArraySet<ManagerServlet>();
        //这个session不是Httpsession,相当于用户的唯一标识,用它进行与指定用户通讯
        private  javax.websocket.Session session=null;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {
            String msg;
            String name=request.getParameter("name");
            //这里submit是数据库操作的方法,如果插入数据成功,则发送更新信号
            if(submit(name)){
                //发送更新信号
                sendMessage();
                msg="ok!";
            }else {
                msg="error!";
            }
            response.sendRedirect("manager.jsp?msg="+msg);
        }
        public void doPost(HttpServletRequest request,HttpServletResponse reponse) throws ServletException, IOException {
            doGet(request,reponse);
        }
    
        /**
         * 向数据库插入一个name
         * @param name
         * @return
         */
        public boolean submit(String name){
            DB db=new DB();
            String sql="insert into users(name) values(?)";
            try{
                PreparedStatement pstmt=db.con.prepareStatement(sql);
                pstmt.setString(1,name);
                pstmt.executeUpdate();
                return true;
            }catch (Exception e){
                e.printStackTrace();
                return false;
            }finally {
                db.close();
            }
        }
    
        /**
         * @OnOpen allows us to intercept the creation of a new session.
         * The session class allows us to send data to the user.
         * In the method onOpen, we'll let the user know that the handshake was
         * successful.
         * 建立websocket连接时调用
         */
        @OnOpen
        public void onOpen(Session session){
            System.out.println("Session " + session.getId() + " has opened a connection");
            try {
                this.session=session;
                webSocketSet.add(this);     //加入set中
                session.getBasicRemote().sendText("Connection Established");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    
        /**
         * When a user sends a message to the server, this method will intercept the message
         * and allow us to react to it. For now the message is read as a String.
         * 接收到客户端消息时使用,这个例子里没用
         */
        @OnMessage
        public void onMessage(String message, Session session){
            System.out.println("Message from " + session.getId() + ": " + message);
        }
    
        /**
         * The user closes the connection.
         *
         * Note: you can't send messages to the client from this method
         * 关闭连接时调用
         */
        @OnClose
        public void onClose(Session session){
            webSocketSet.remove(this);  //从set中删除
            System.out.println("Session " +session.getId()+" has closed!");
        }
    
        /**
         * 注意: OnError() 只能出现一次.   其中的参数都是可选的。
         * @param session
         * @param t
         */
        @OnError
        public void onError(Session session, Throwable t) {
            t.printStackTrace();
        }
    
        /**
         * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
         * @throws IOException
         * 发送自定义信号,“1”表示告诉前台,数据库发生改变了,需要刷新
         */
        public void sendMessage() throws IOException{
            //群发消息
            for(ManagerServlet item: webSocketSet){
                try {
                    item.session.getBasicRemote().sendText("1");
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            }
    
        }
    }
    
    这个类首先继承了HttpServlet,目的是接收表单数据完成数据库的修改。其次,这个类实现了websocket的功能。在doGet()方法中,可以看到,一旦数据库发生改变,就会向前台发送“1”,前台收到“1”后即可刷新页面。
    

      

  • 相关阅读:
    第六周作业----测试自动化工具
    第六周作业----内聚耦合
    HTML 滚动条实现
    mysql练习(一)
    flume本地调试
    -Dmaven.multiModuleProjectDirectory system propery is not set
    Cannot read property 'substring' of undefined
    JVM的几个介绍
    storm(二)消息的可靠处理
    storm(一)
  • 原文地址:https://www.cnblogs.com/xianz666/p/14428339.html
Copyright © 2020-2023  润新知