spring boot 实现webSocket

2018-07-07  本文已影响106人  liangxifeng833

一.使用H5的websocket协议

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

实现步骤

       <!--加载websocket-->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-websocket</artifactId>
           <version>1.3.5.RELEASE</version>
       </dependency>
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--;
       }
   }
}
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();
    }
}
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() { }
}
 <!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>

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

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不兼容,所以放弃使用;

上一篇下一篇

猜你喜欢

热点阅读