美文网首页
spring boot 实现webSocket

spring boot 实现webSocket

作者: liangxifeng833 | 来源:发表于2018-07-07 18:15 被阅读106次

    一.使用H5的websocket协议

    参考:https://www.cnblogs.com/bianzy/p/5822426.html
    接收onOpen接收参数:https://blog.csdn.net/u014175572/article/details/46693121

    实现步骤

    • 修改pom.xml
           <!--加载websocket-->
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-websocket</artifactId>
               <version>1.3.5.RELEASE</version>
           </dependency>
    
    • 建立websocket服务端 PayWebSocket
    package domain.websocket;
    
    import domain.domain.DomainResponse;
    import lombok.extern.slf4j.Slf4j;
    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.CopyOnWriteArraySet;
    
    /**
    * 收银系统websocket服务端
    * @author liangxifeng 2018-07-04
    */
    @ServerEndpoint(value = "/websocket/pay/{mac}/{contractNum}",encoders = { ServerEncoder.class })
    @Component
    @Slf4j
    public class PayWebSocket {
       //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
       private static int payOnlineCount = 0;
       //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
       //private static CopyOnWriteArraySet<PayWebSocket> payWebSocketSet = new CopyOnWriteArraySet<PayWebSocket>();
       //线程安全的map,key=mac地址,value=PayWebSocket对象
       public static ConcurrentHashMap<String,PayWebSocket> payWebSocketMap = new ConcurrentHashMap<String, PayWebSocket>();
       //与某个客户端的连接会话,需要通过它来给客户端发送数据
       private Session session;
       private String flag = "收银系统websocket=>";
    
       /**
        * 连接建立成功调用的方法
        * @param mac mac地址
        * @param contractNum 合同号
        * @param session websocket会话
        */
       @OnOpen
       public void onOpen(@PathParam("mac") String mac,
                          @PathParam("contractNum") String contractNum, Session session) throws Exception{
           logInfo("合同号 contractNum="+contractNum);
           //验证参数
           if(mac == null || mac.trim().isEmpty() || contractNum == null || contractNum.trim().isEmpty()){
               sendMessage(new DomainResponse(0,"mac地址或收款合同号不可为空",0));
           }
           this.session = session;
           //将PayWebSocket对象加入map中
           payWebSocketMap.put(mac.trim(),this);
           addOnlineCount();           //在线数加1
           log.info("有新连接加入!当前在线人数为" + getOnlineCount());
       }
    
       /**
        * 连接关闭调用的方法
        */
       @OnClose
       public void onClose() {
           //payWebSocketSet.remove(this);  //从set中删除
           subOnlineCount();           //在线数减1
           System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
       }
    
       /**
        * 收到客户端消息后调用的方法
        *
        * @param message 客户端发送过来的消息*/
       @OnMessage
       public void onMessage(String message, Session session) throws Exception{
           System.out.println("来自客户端的消息:" + message);
    
    //        //群发消息
    //        for (PayWebSocket item : payWebSocketSet) {
    //            try {
    //                item.sendMessage(message);
    //            } catch (IOException e) {
    //                e.printStackTrace();
    //            }
    //        }
       }
    
       /**
        * 打印日志信息
        * @param msg
        */
       public void logInfo(String msg){
           log.info(this.flag+msg);
       }
    
       /**
        * 发生错误时调用
        */
        @OnError
        public void onError(Session session, Throwable error) {
            log.info("发生错误");
            error.printStackTrace();
        }
    
       public void sendMessage(Object message) throws Exception {
           this.session.getBasicRemote().sendObject(message);
           //this.session.getAsyncRemote().sendText(message);
       }
       /**
        * 群发自定义消息
        */
       public static void sendInfo(Object message) throws Exception {
    //        for (PayWebSocket item : payWebSocketSet) {
    //            try {
    //                item.sendMessage(message);
    //            } catch (IOException e) {
    //                continue;
    //            }
    //        }
       }
    
       public static synchronized int getOnlineCount() {
           return payOnlineCount;
       }
    
       /**
        * 连接数+1
        */
       public static synchronized void addOnlineCount() {
           PayWebSocket.payOnlineCount++;
       }
       /**
        * 连接数-1
        */
       public static synchronized void subOnlineCount() {
           if(payOnlineCount!=0){
               PayWebSocket.payOnlineCount--;
           }
       }
    }
    
    • 创建配置文件,启动websocket服务 WebSocketConfig
    package domain.util;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    /**
     * 注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     * @author liangxifeng 2018-07-04
     */
    @Configuration
    public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    
    • 为了在websocket服务器使用sendObject给客户端发送object,需要实现如下ServerEncoder类
    package domain.websocket;
    
    import domain.domain.DomainResponse;
    import net.sf.json.JSONObject;
    
    import javax.websocket.EncodeException;
    import javax.websocket.Encoder;
    import javax.websocket.EndpointConfig;
    
    /**
     * ServerEncoder为了防止在websocket向客户端发送sendObject方法的时候提示如下错误:
     * javax.websocket.EncodeException: No encoder specified for object of class [class org.ywzn.po.Messagepojo]
     */
    
    public class ServerEncoder implements Encoder.Text<DomainResponse>  {
        //代表websocket调用sendObject方法返回客户端的时候,必须返回的是DomainResponse对象
        @Override
        public String encode(DomainResponse domainResponse) {
            //将java对象转换为json字符串
            return JSONObject.fromObject(domainResponse).toString();
        }
        @Override
        public void init(EndpointConfig endpointConfig) { }
    
        @Override
        public void destroy() { }
    }
    
    • 目录结构

        websocket.jpg
    • html内容 websocket-java.html

     <!doctype html>
    <html lang="en">
     <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
      <title>websocket-java</title>
      <script src="/static/js/WebSocket.js"></script></script>
     </head>
    <body>
    Welcome<br/>
    <input id="text" type="text" /><button onclick="send()">Send</button>    <button onclick="closeWebSocket()">Close</button>
    <div id="message">
    </div>
    </body>
    
    <script type="text/javascript">
        WEB_SOCKET_SWF_LOCATION="/static/js/WebSocket.swf"; 
        WEB_SOCKET_DEBUG=true; 
        var websocket = null;
    
        //判断当前浏览器是否支持WebSocket
        if('WebSocket' in window){
            websocket = new WebSocket("ws://localhost:8082/websocket");
        }
        else{
            alert('Not support websocket')
        }
        var websocketPay = null; 
        if('WebSocket' in window){
            websocketPay = new WebSocket("ws://localhost:8082/websocket/pay/2/151200234");
        }
        //连接成功建立的回调方法
        websocketPay.onopen = function(event){
            setMessageInnerHTML("pay-open");
        }
        //接收到消息的回调方法
        websocketPay.onmessage = function(event){
            console.log('pay =='+event.data)
            var data = eval("(" + event.data + ")"); //解析对象
            setMessageInnerHTML('pay message ==='+event.data);
        }
    
    
        //连接发生错误的回调方法
        websocket.onerror = function(){
            setMessageInnerHTML("error");
        };
    
        //连接成功建立的回调方法
        websocket.onopen = function(event){
            setMessageInnerHTML("open");
        }
    
        //接收到消息的回调方法
        websocket.onmessage = function(event){
            console.log(event.data)
            var data = eval("(" + event.data + ")"); //解析对象
            //console.log(typeof(JSON.parse(event.data))); 
            //var data = JSON.parse(event.data); 
            setMessageInnerHTML(typeof(data));
        }
    
        //连接关闭的回调方法
        websocket.onclose = function(){
            setMessageInnerHTML("close");
        }
    
        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function(){
            websocket.close();
        }
    
        //将消息显示在网页上
        function setMessageInnerHTML(innerHTML){
            document.getElementById('message').innerHTML += innerHTML + '<br/>';
        }
    
        //关闭连接
        function closeWebSocket(){
            websocket.close();
        }
    
        //发送消息
        function send(){
            var message = document.getElementById('text').value;
            websocket.send(message);
        }
    </script>
    </html>
    
    • 访问效果


      image.png

    服务器可以给指定的用户发消息

    package domain.controller;
    
    import domain.domain.DomainResponse;
    import domain.domain.Exhibition;
    import domain.websocket.PayWebSocket;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping(value = "/exhibiton")
    public class ExhibitonController {
        @Autowired
        private InsertExhibitionService insertExhibitionService;
        @GetMapping(value = "/sendMsg/{mac}")
        /**
         * 指定某个websocket发送从服务器发送到浏览器,服务器主动推送
         */
        private DomainResponse testSendMsg(@PathVariable("mac") String mac ) throws  Exception{
            DomainResponse msg = new DomainResponse(Integer.parseInt(mac),mac,"指定给"+mac+"用户发消息");
            PayWebSocket payWebSocket = PayWebSocket.payWebSocketMap.get(mac);
            if(payWebSocket == null)
            {
                return new DomainResponse(0,"没有该用户",0);
            }
            payWebSocket.sendMessage(msg);
            return msg;
        }
    }
    

    访问地址:http://192.168.9.209:8082/exhibiton/sendMsg/2

    注意:以上方式IE8不兼容,所以放弃使用;

    相关文章

      网友评论

          本文标题:spring boot 实现webSocket

          本文链接:https://www.haomeiwen.com/subject/wnhvbxtx.html