zoukankan      html  css  js  c++  java
  • 消息推送二 之webSocket

    友情提示: 消息推送的介绍可以参考http://www.cnblogs.com/dahuandan/p/6816173.html

    什么是webSocket

     webSocket是为解决客户端与服务端实时通信而产生的技术,其本质是使用一个TCP连接进行双向通讯,可以用来Web服务端的消息推送,被IETF定义为标准协议。

    优点

     相对于传统的HTTP轮询技术而言,webSocket是建立一次TCP连接进行客户端与服务端的双向通讯,减少了传统轮询技术频繁地向服务器发起请求,另外webSocket的Header相比HTTP的非常小。

    helloWord

    环境准备


     Spring4.0版本以上

    tomcat8

    Constants.java


    package demo;
    
    
    /**
     * webSocket常量
     */
    public class Constants {
    
        /**
         * http session 中 用户名的key值
         */
        public static String SESSION_USERNAME = "session_username";
        
        /**
         * websocket session 中 用户名的key值
         */
        public static String WEBSOCKET_USERNAME = "websocket_username";
    }
    View Code

    WebSocketConfig.java


    package demo;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.config.annotation.EnableWebSocket;
    import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
    import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
    
    
    /**
     * 注册websocket
     */
    @Configuration
    @EnableWebMvc
    @EnableWebSocket
    public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{
    
        public void registerWebSocketHandlers(WebSocketHandlerRegistry reg) {
            String websocket_url = "/webSocketServer";                     //设置websocket的地址
            reg.addHandler(systemWebSocketHandler(), websocket_url)        //注册到Handler
               .addInterceptors(new WebSocketInterceptor());               //注册到Interceptor
            
            //提供SockJS支持(主要是兼容ie8)
            String sockjs_url    = "/sockjs/webSocketServer";           //设置sockjs的地址
            reg.addHandler(systemWebSocketHandler(),sockjs_url )        //注册到Handler
               .addInterceptors(new WebSocketInterceptor())                //注册到Interceptor
               .withSockJS();                                              //支持sockjs协议 
            
        }
        
        @Bean
        public WebSocketHandler systemWebSocketHandler(){
            return new MyWebSocketHandler();
        }
    
    }
    View Code

    WebSocketInterceptor.java


    package demo;
    import java.util.Map;
    
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.http.server.ServletServerHttpRequest;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.server.HandshakeInterceptor;
    
    /**
     * WebSocket握手拦截器
     */
    public class WebSocketInterceptor implements HandshakeInterceptor {
    
        //握手前
        public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler,
                Map<String, Object> attr) throws Exception {
            
            if (request instanceof ServletServerHttpRequest) {
                
                ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                
                String user = servletRequest.getServletRequest().getParameter("user");
                attr.put(Constants.WEBSOCKET_USERNAME, user);
            }
            return true;
        }
        
        //握手后
        public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
                WebSocketHandler handler, Exception e) {
        }
    }
    View Code

    MyWebSocketHandler.java


    package demo;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.web.socket.CloseStatus;
    import org.springframework.web.socket.TextMessage;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.WebSocketMessage;
    import org.springframework.web.socket.WebSocketSession;
    
    /**
     * WebSocket处理器
     */
    public class MyWebSocketHandler implements WebSocketHandler {
        
        /**
         * WebSocketSession容器
         */
        private static final List<WebSocketSession> users = new ArrayList<WebSocketSession>();
    
    
        //建立连接后的函数
        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            users.add(session);
        }
        
        //消息处理
        @Override
        public void handleMessage(WebSocketSession session, WebSocketMessage<?> ws_msg) throws Exception {
    //        String user = (String)session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
            
            sendMessageToUsers(new TextMessage("received at server: " + ws_msg.getPayload()));
        }
        
        //关闭连接后的函数
        public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
            users.remove(session);
        }
    
        
        //异常处理
        @Override
        public void handleTransportError(WebSocketSession session, Throwable e) throws Exception {
            
            if(session.isOpen()) 
                session.close();
            
            users.remove(session);
        }
        
        @Override
        public boolean supportsPartialMessages() {
            return false;
        }
        
        
        /**
         * 给所有在线用户发送消息
         * @param message
         * @throws IOException 
         */
        public void sendMessageToUsers(TextMessage message) throws IOException {
            for (WebSocketSession user : users) {
                if (user.isOpen()) 
                    user.sendMessage(message);
            }
        }
        
        
        /**
         * 给某个用户发送消息
         * @param userName
         * @param message
         * @throws IOException 
         */
        public void sendMessageToUser(String userName, TextMessage message) throws IOException {
            for (WebSocketSession user : users) {
                if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {
                   if (user.isOpen()) {
                       user.sendMessage(message);
                   }
                }
            }
        }
    
    }
    View Code

    index.jsp


    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>websocket</title>
    
    <script src="jquery-1.10.2.js"></script>
    <script src="sockjs-0.3.min.js"></script>
    <script>
    
    $(function(){
        var webSocket = newWebSocket();
        
        sendMessage(webSocket);
    });
    
    
    /**
     * 创建webSocket
     */
    function newWebSocket(){
        var webSocket;
        
        if ('WebSocket' in window) 
            webSocket = new WebSocket("ws://localhost:8080/websocket/webSocketServer?user=123");
        
        else if ('MozWebSocket' in window) 
            webSocket = new MozWebSocket("ws://localhost:8080/websocket/webSocketServer");
        
        else 
            webSocket = new SockJS("http://localhost:8080/websocket/sockjs/webSocketServer");
        
         
        //打开webSocket连接
        webSocket.onopen = function (evnt) {
        };
        
        //接收信息
        webSocket.onmessage = function (evnt) {
            $("#console").append("(<font color='red'>"+evnt.data+"</font>)</br>")
        };
        
        //错误处理
        webSocket.onerror = function (evnt) {
        };
        
        //关闭webSocket
        webSocket.onclose = function (evnt) {
        }
        
        return webSocket;
    }
    
    
    /**
     * 发送信息
     */
    function sendMessage(webSocket){
        
        $("#send").click(function(){
            webSocket.send($("#message").val());
        });
    }
    </script>
    </head>
    
    
    <body>
        <div>
            <textarea id="message" style=" 350px">send message!</textarea>
        </div>
        
        </br>
        
        <div>
            <button id="send">send</button>
        </div>
        
        <div id="console"></div>
    </body>
    </html>
    View Code

    spring.xml


    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context-4.1.xsd">
            
          <context:annotation-config /> 
    </beans>
    View Code

    springmvc.xml


    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
               http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.1.xsd
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
            
        <mvc:annotation-driven/>
        <context:component-scan base-package="demo*"/>
        
        <!-- 静态资源解析 包括 :js、css、img、..
             location: 资源所在的本地路径,建议不要放在webInf下
             mapping :url的访问路径, **代表包含resource/路径后的所有子目录
         -->
         <mvc:resources location="/" mapping="/**"/>
    </beans>
    View Code

    web.xml


    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" 
        xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
        
        <display-name>websocketDemo</display-name>    
    
    
        <!-- 加载spring容器 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/spring/spring.xml</param-value>
        </context-param>
        
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        
        <!-- springmvc前端控制器,rest配置 -->
        <servlet>
            <servlet-name>springmvc_rest</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等) 如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml) -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring/springmvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>springmvc_rest</servlet-name>
            <!-- 第一种:*.action,访问以.action结尾 由DispatcherServlet进行解析 
                   第二种:/,所以访问的地址都由DispatcherServlet进行解析, 使用此种方式可以实现 RESTful风格的url(对于静态文件的解析需要配置不让DispatcherServlet进行解析)
                   第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时, 仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。 -->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        
    
    
        <!-- post乱码过虑器 -->
        <!-- 除了加过滤器,由于tomcat默认编码ISO-8859-1,还需要修改 %tomcat%/conf/server.xml Connector 标签加属性 URIEncoding="UTF-8" -->
        <filter>
            <filter-name>CharacterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>utf-8</param-value>
            </init-param>
        </filter>
        
        <filter-mapping>
            <filter-name>CharacterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        
    </web-app>
    View Code

    测试

     打开多个窗口,分别输入http://localhost:8080/websocket/index.jsp, 然后在某一窗口发送消息的时候,其他窗口都能接收到:

     

  • 相关阅读:
    自己动手用Javascript写一个无刷新分页控件
    自己动手写一个通用的分页存储过程(适用于多表查询)
    Towards Accurate Multiperson Pose Estimation in the Wild 论文阅读
    统计学习方法c++实现之一 感知机
    2018百度之星开发者大赛-paddlepaddle学习(二)将数据保存为recordio文件并读取
    2018百度之星开发者大赛-paddlepaddle学习
    [转载]C#_Path类常用操作
    安装SQL2K是的文件挂起错误
    相见恨晚MySQL 多表查询
    php截取字符串,出现乱码
  • 原文地址:https://www.cnblogs.com/dahuandan/p/6816709.html
Copyright © 2011-2022 走看看