苏铭客

导航

webSocket 使用

一.什么是webSocket?

     众所周知,浏览器支持无状态的http协议,用户在浏览器端发送一个请求,服务端返回一个响应。这种响应是基于用户不断的请求才能返回。在html5之前,要实现一个实时获取业务数据的功能,或许还只能用轮询的方式,每次去发送一个请求获取服务器响应的数据。那html5到来之时,带来了一个便利的技术 webSocket.它不像http请求那样,每次要获取数据,就建立一次连接,获取完后连接就断开。webSocket 只建立一次和客户端的长连接,以后的每次活动,都无需再和浏览器客户端建立连接,提高了这种频繁请求的效率,减少了网络带宽的损耗。

二.webSocket 在项目中的运用

    最近项目上有个需求,要获取电源设备的实时电流值,并以可视化的折线图展示出来。基于这块业务需求,我用webSocket实现了该功能,废话不多说了,直接贴上干货!

  (1)准备webSocket所需的jar包。

     这里我需要说明下,该jar包与 tomcat 自身的jar有冲突,建议不要在本项目内引用,可外置放在其他项目中引用过来。

  (2)前端js代码块

            //========== WebScoket 通信地址
            var webScoket_url = "ws://"+location.host+"/PowerDemo/websocket_login";
            var webSocket = new WebSocket(webScoket_url);
            //js 客户端初始化WebSocket自身事件方法
            function initWebSocket(){
                //接受服务端返回的消息
                webSocket.onerror = function(event) {
                  console.log("webSocket异常",event);
                };
                 
                 //我们创建一个连接到服务器的连接时将会调用此方法。
                webSocket.onopen = function(event) {
                  //onOpen(event)
                  console.log("创建连接打开",event);
                };
                 
                 //接收消息事件。
                webSocket.onmessage = function(event) {
                  onMessage(event)
                };
                
                webSocket.onclose = function(event){
                    console.log("页面的关闭",event);
                    webSocket = null;
                }
            }
            
             
            function onMessage(event) {
               // document.getElementById('messages').innerHTML +=event.data+'<br />';
               // console.log(event+"==="+event.data);
                commonService.publishNotify("getMessageEvent", event.data);
            }
View Code

  webScoket_url 是请求Java后台的地址,访问方式是"ws://"开头+服务IP和端口,在加上后台的请求配置地址。 最终拼接的效果 :"ws://"+location.host+"/PowerDemo/websocket_login"

      前端websocekt 自带四个监听事件,onerror,onopen,onmessage,onclose 这四个事件方法。

     1.onerror: webSocket连接请求出现异常时,自动触发onerror方法。
     2.onopen:初始化打开webSocket时.调用onopern方法。
     3.onmessage: 浏览器客户端与后台通讯连接过程中,如有数据响应,则触发onmessage方法。
     4.onclose: webSocket关闭方法,这个方法目前我运用的时候,是通过销毁webSocket对象,才触发了此方法。  
                      /**
              * webSocket.readyState 状态值
                     CONNECTING    0    连接还没开启。
                OPEN    1    连接已开启并准备好进行通信。
                CLOSING    2    连接正在关闭的过程中。
                CLOSED    3    连接已经关闭,或者连接无法建立。
              */
             vm.testScoket = function(obj){
                 var json_str = {"type":obj.NUMPLATE};
                 if(webSocket == null){
                    webSocket = new WebSocket(webScoket_url);
                    $timeout(function(){
                        initWebSocket();
                        if(webSocket.readyState == 1){
                               webSocket.send(JSON.stringify(json_str));
                        }
                    },1000)
                }
                else if(webSocket != null && webSocket.readyState == 1){
                    initWebSocket();
                       webSocket.send(JSON.stringify(json_str));
                }
                else if(webSocket.readyState == 2 || webSocket.readyState == 3){
                   webSocket = new WebSocket(webScoket_url);
                   $timeout(function(){
                        initWebSocket();
                        if(webSocket.readyState == 1){
                               webSocket.send(JSON.stringify(json_str));
                        }
                    },1000)
                }
                
                
                //QuestionService.initModal("views/power/failure/msgModal.html","ModalController",null);
             }
View Code

   这段代码是webSocket调用的入口,其中根据webSocket所处的不同状态,做了对应的业务处理。

   (3)后台java端webSocket

package com.zdwl.scoket;

import java.io.IOException;
import java.util.Date;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import com.zdwl.comm.JqgridPage;
import com.zdwl.comm.util.JsonDateValueProcessor;
import com.zdwl.comm.util.SpringUtil;
import com.zdwl.model.vo.power.PowerEvent;
import com.zdwl.service.power.PowerEventQueryServiceImpl;

@Configuration
@EnableWebMvc
@ServerEndpoint(value = "/websocket") 
public class BusPowerWebScoket extends SpringUtil{
    
     @OnMessage
      public void onMessage(String message, Session session)
        throws IOException, InterruptedException {
        PowerEventQueryServiceImpl eventQueryService=(PowerEventQueryServiceImpl)super.getBean("powerEventQueryService");
        //接受前端的web 消息
        System.out.println("接收: " + message);
        JSONObject jo=null;
        try {
            jo = new  JSONObject().fromObject(message);
            System.out.println("==="+jo.get("rows")+"======"+jo.toString());
            PowerEvent event=new PowerEvent();
            String beginTime =jo.get("beginDate")+"";
            String date = null;//shoveFrontSecondForGetDate(5*60);
            event.setBeginDate(date);
            JqgridPage page = new JqgridPage();
            String pageSize = jo.get("rows")+"";
            String curPageNo =jo.get("page")+"";
            if (curPageNo != null) {
                page.setCurPageNo(new Integer(curPageNo));
            }
            if (pageSize != null) {
                page.setPageSize(new Integer(pageSize));
            }
        int sentMessages = 0;
        while(true){
              Thread.sleep(3000);
              eventQueryService.queryRealTimeCurrentInfo(page, event, null);
              JsonConfig jsonConfig = new JsonConfig();
              jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
              JSONObject json = JSONObject.fromObject(page,jsonConfig);
              String str = json.toString();
              //发送文本消息
              session.getBasicRemote().sendText(str);
              sentMessages++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
      }
       
      @OnOpen
      public void onOpen() {
        System.out.println("客户端链接。。。");
      }
     
      @OnClose
      public void onClose() {
        System.out.println("链接关闭。。。。");
      }
      
    /*public static void main(String[] args) {
        shoveFrontSecondForGetDate(120);
    }*/

    /*public static String shoveFrontSecondForGetDate(int secs){
        Date date = new Date();
        Long ll = date.getTime() - secs*1000L;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //    System.out.println("当前时间:"+sdf.format(date));
        date= new Date(ll);
        System.out.println("推前"+secs+"秒的时间:"+sdf.format(date));
        return sdf.format(date);
    }*/
}
View Code

     代码中的message参数,是前端首次建立webSocket对象传送过来的消息,仅且只传送一回。

     接着在后台跑一个死循环的获取消息数据业务,此处我用Spring ApplicationContext容器获取了service类,贴上代码如下:

package com.zdwl.comm.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringUtil implements ApplicationContextAware{

    private static ApplicationContext appContext;
    
    @Override
    public void setApplicationContext(ApplicationContext paramApplicationContext)
            throws BeansException {
        appContext = paramApplicationContext;
    }
    
    public static Object getBean(String paramString){
        return appContext.getBean(paramString);
    }
}
View Code

    在循环体中,运用session对象的方法,发送数据消息  session.getBasicRemote().sendText(str);

    然后前端不断接受数据消息,实现了实时获取数据的功能。

三.存在的问题

  如何终止这个webSocket的请求呢?目前我还没有找到好的方法去终止,用了最暴力的关闭当前浏览器选项卡,终止了webSocket的长连接。

    如果有好的解决方案的小伙伴,欢迎留言,万分感谢!

四.参考资源

     http://qiita.com/tnakagawa/items/f7c764d044ba56d9e0fd (赞)

     http://www.oschina.net/translate/java-ee-html5-websocket-example

     https://www.tutorialspoint.com/websockets/websockets_closing_connection.htm

posted on 2017-01-17 20:27  苏铭客  阅读(597)  评论(0编辑  收藏  举报