美文网首页
spring boot websocket 实时消息推送和数据展

spring boot websocket 实时消息推送和数据展

作者: 王乐城愚人云端 | 来源:发表于2019-07-10 11:07 被阅读0次

    一、实现目标

    • 1、在线聊天,客服聊天,聊天室
    • 2、业务数据实时展示,自动更新

    二、实践步骤

    以下是为了实现:业务数据实时展示,自动更新

    1. Maven引入

    <dependency>  
       <groupId>org.springframework.boot</groupId>  
       <artifactId>spring-boot-starter-websocket</artifactId>  
    </dependency> 
    

    2. 创建配置文件

    WebSocketConfig

    /**
     * 开启WebSocket支持
     * @author zhengkai
     */
    @Configuration
    public class WebSocketConfig {
    
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    
    

    3. 创建服务端

    @ServerEndpoint(value = "/websocket")
    @Component
    public class WebSocketServer {
    
        private final Logger log = LoggerFactory.getLogger(this.getClass());
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
        private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
    
        //与某个客户端的连接会话,需要通过它来给客户端发送数据
        private Session session;
    
        /**
         * 连接建立成功调用的方法
         */
        @OnOpen
        public void onOpen(Session session) {
            this.session = session;
            webSocketSet.add(this);
            sendMessage("连接成功");
        }
    
        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose() {
            webSocketSet.remove(this);
            log.info("有一连接关闭!");
        }
    
        /**
         * 收到客户端消息后调用的方法
         *
         * @param queryType 客户端发送过来的消息
         */
        @OnMessage
        public void onMessage(String queryType) {
            log.info("收到信息:" + queryType);
    
            //群发消息
            for (WebSocketServer item : webSocketSet) {
                item.sendMessage("hello");
            }
        }
    
        /**
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error) {
            log.error("发生错误");
            error.printStackTrace();
        }
    
        /**
         * 实现服务器主动推送
         */
        public void sendMessage(Object message) {
            try {
                this.session.getBasicRemote().sendText(JSON.toJSONString(message));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 实现服务器主动群发消息
         */
        public static void sendInfo(Object message) {
            for (WebSocketServer item : webSocketSet) {
                item.sendMessage(message);
            }
        }
    }
    
    

    4. 前端发起websocket请求

      <script> 
        var socket;  
        if(typeof(WebSocket) == "undefined") {  
            console.log("您的浏览器不支持WebSocket");  
        }else{  
            console.log("您的浏览器支持WebSocket");  
                //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接  
                socket = new WebSocket("ws://localhost:8080/webscoket");
                //打开事件  
                socket.onopen = function() {  
                    console.log("Socket 已打开");  
                    //socket.send("这是来自客户端的消息" + location.href + new Date());  
                };  
                //获得消息事件  
                socket.onmessage = function(msg) {  
                    console.log(msg.data);  
                    //发现消息进入    开始处理前端触发逻辑
                };  
                //关闭事件  
                socket.onclose = function() {  
                    console.log("Socket已关闭");  
                };  
                //发生了错误事件  
                socket.onerror = function() {  
                    alert("Socket发生了错误");  
                    //此时可以尝试刷新页面
                } 
        }
        </script> 
    

    三、实践中会遇到的问题

    1. 前端发起websocket请求, 却无法连接websocket

    • 错误一:被权限拦截,例如spring security
      解决方式:放开权限或允许访问
    // spring security
    .antMatchers(
        "/websocket"
        )
    .permitAll()
    
    
    • 错误二:请求的websocket地址错误
    @ServerEndpoint(value = "/websocket")
    
    对应的地址是:ws://localhost:8080/webscoket
    
    • 错误三:被AOP拦截
    @Pointcut("execution(public * com.xxx.xxx.controller..*(..))")
    public void webLog() {
    }
    

    解决办法

    // 排除拦截
    @Pointcut("execution(public * com.xxx.xxx.controller..*(..)) && !execution(public * com.xxx.xxx.controller.xxx*(..))")
    public void webLog() {
    }
    

    2. 在WebSocketServer中,无法注入Bean,无法使用@Autowired

    即你按如下方式直接使用@Autowired,会报错

    @ServerEndpoint(value = "/websocket")
    @Component
    public class WebSocketServer {
        @Autowired
        ChartDataService chartDataService;
    }
    

    在WebSocket中, 因 SpringBoot+WebSocket 对每个客户端连接都会创建一个 WebSocketServer(@ServerEndpoint 注解对应的) 对象,Bean 注入操作会被直接略过,因而手动注入一个全局变量(即你需要注入的bean)

    @Configuration
    public class WebSocketConfig {
    
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    
        // 在这里注入你需要的bean
        @Autowired
        public void setMessageService(ChartDataService chartDataService) {
            WebSocketServer.chartDataService = chartDataService;
            // ...
        }
    }
    
    

    使用你注入的bean

    @ServerEndpoint(value = "/websocket")
    @Component
    public class WebSocketServer {
    
        public static ChartDataService chartDataService;
    
    

    此方式经实践,有效

    其他解决方式: https://stackoverflow.com/questions/29306854/serverendpoint-and-autowired

    • 1.使用@Inject
    @ServerEndpoint("/ws")
    public class MyWebSocket {   
        @Inject
        private ObjectMapper objectMapper;
    }
    
    • 2.使用SpringConfigurator
    @ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)
    
    • 3.使用@PostConstruct
    @PostConstruct
    public void init(){
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }
    

    经过实践,上述三种方式,对于我而言,均无效

    参考链接:https://blog.csdn.net/moshowgame/article/details/80275084

    相关文章

      网友评论

          本文标题:spring boot websocket 实时消息推送和数据展

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