1. 程式人生 > >消息推送二 之webSocket

消息推送二 之webSocket

還需 由於 else har 頁面 try window class logs

友情提示: 消息推送的介紹可以參考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