首页 > 代码库 > 消息推送二 之webSocket

消息推送二 之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="width: 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, 然后在某一窗口发送消息的时候,其他窗口都能接收到:

 技术分享

消息推送二 之webSocket