一:maven依赖

<!-- websocket -->

            <dependency>

                  <groupId>org.springframework</groupId>

                  <artifactId>spring-websocket</artifactId>

                  <version>4.0.3.RELEASE</version>

            </dependency>

            <dependency>

                  <groupId>org.springframework</groupId>

                  <artifactId>spring-messaging</artifactId>

                  <version>4.3.2.RELEASE</version>

            </dependency>

            <dependency>

                  <groupId>javax.websocket</groupId>

                  <artifactId>javax.websocket-api</artifactId>

                  <version>1.0</version>

                  <scope>provided</scope>

            </dependency>

            <dependency>

                  <groupId>org.eclipse.jetty.websocket</groupId>

                  <artifactId>websocket-server</artifactId>

                  <version>9.3.3.v20150827</version>

                  <scope>provided</scope>

            </dependency>

            <dependency>

                  <groupId>org.apache.tomcat.embed</groupId>

                  <artifactId>tomcat-embed-websocket</artifactId>

                  <version>8.0.23</version>

                  <scope>provided</scope>

            </dependency>

二:配置WebSocket的入口,编写WebSocketConfig类实现WebSocketConfigurer 接口

package com.hiwei.demo.webSocket;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.socket.config.annotation.EnableWebSocket;

import org.springframework.web.socket.config.annotation.WebSocketConfigurer;

import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import org.springframework.web.socket.handler.TextWebSocketHandler;

@Configuration

@EnableWebSocket

@EnableWebMvc

public class SpringWebSocketConfig implements WebSocketConfigurer {

    @Override

    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

        registry.addHandler(webSocketHandler(),"/websocket/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor());

        registry.addHandler(webSocketHandler(), "/sockjs/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor()).withSockJS();      

    }

    @Bean

    public TextWebSocketHandler webSocketHandler(){

        return new SpringWebSocketHandler();

    }

}

三:定义一个SpringWebSocketHandler类继承TextWebSocketHandler,这个类是用来处理Websocket连接建立、断开,消息发送的逻辑的,这个是消息处理的核心代码

package com.hiwei.demo.webSocket;

import java.io.IOException;

import java.util.HashMap;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

public class SpringWebSocketHandler extends TextWebSocketHandler {



    private static final HashMap<String,WebSocketSession> users;

    static {

        users = new HashMap<String,WebSocketSession>();

    }

   

    public SpringWebSocketHandler() {

    }

   

    /**

     * 连接成功触发

     */

    @Override

    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        users.put((String) session.getAttributes().get("SESSION_USERID"), session);

        System.out.println("connect to the websocket success......当前数量:"+users.size());

        //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户

      TextMessage returnMessage = new TextMessage("连接成功");

       session.sendMessage(returnMessage);

    }

    /**

     * 关闭连接时触发

     */

    @Override

    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {

        String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");

        System.out.println("用户"+username+"已退出!");

        users.remove(session.getAttributes().get("SESSION_USERID"));

        System.out.println("剩余在线用户"+users.size());

    }

    /**

     * js调用websocket.send时候,会调用该方法

     */

    @Override   

    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        super.handleTextMessage(session, message);

        TextMessage returnMessage = new TextMessage(message.getPayload().toString());

        sendMessageToUsers(returnMessage);

    }

    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

        if(session.isOpen()){session.close();}

        users.remove(session.getAttributes().get("SESSION_USERID"));

    }

    public boolean supportsPartialMessages() {

        return false;

    }

    /**

     * 给某个用户发送消息

     *

     * @param userName

     * @param message

     */

    public void sendMessageToUser(String userName, TextMessage message) {

      for (WebSocketSession user: users.values()) {

            if (user.getAttributes().get("WEBSOCKET_USERNAME").equals(userName)) {

                try {

                    if (user.isOpen()) {

                        user.sendMessage(message);

                    }

                } catch (IOException e) {

                    e.printStackTrace();

                }

                break;

            }

            }

    }

    /**

     * 给所有在线用户发送消息

     *

     * @param message

     */

    public void sendMessageToUsers(TextMessage message) {

        for (WebSocketSession user : users.values()) {

            try {

                if (user.isOpen()) {

                    user.sendMessage(message);

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    } 

   

}

四:拦截器配置

从WebSocketConfig中可以看到在注册WebSocket通道时,不仅设置了入口地址,还配置了拦截器,拦截器可以实现握手之前和之后的逻辑操作,这里配置的拦截器主要用于保存用户名以便于在Handler中定向发送消息。

package com.hiwei.demo.webSocket;

import java.util.Map;

import javax.servlet.http.HttpSession;

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.support.HttpSessionHandshakeInterceptor;

public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {

    @Override

    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

            Map<String, Object> attributes) throws Exception {

        if (request instanceof ServletServerHttpRequest) {

            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;

            HttpSession session = servletRequest.getServletRequest().getSession(false);

            if (session != null) {

                //使用userName区分WebSocketHandler,以便定向发送消息

                String userName = (String) session.getAttribute("SESSION_USERNAME");

                if (userName==null) {

                    userName="default-system";

                }

                attributes.put("WEBSOCKET_USERNAME",userName);

            }

        }

        return super.beforeHandshake(request, response, wsHandler, attributes);

    }

    @Override

    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

            Exception ex) {

        super.afterHandshake(request, response, wsHandler, ex);

    }

}

五:配置Websocket连接前台页面

网页端连接Websocket和推送消息的界面就是这里

<%@ page language="java" contentType="text/html; charset=utf-8"

    pageEncoding="utf-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>消息</title>

</head>

<body>

<script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>

<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>

<script type="text/javascript">

    var msgDiv = document.getElementById("#msgDiv");

    var websocket = null;

    if ('WebSocket' in window) {

        websocket = new WebSocket("ws://172.30.99.37:8080/springmvcMybatis/websocket/socketServer.do");

    }

    else if ('MozWebSocket' in window) {

        websocket = new MozWebSocket("ws://172.30.99.37:8080/springmvcMybatis/websocket/socketServer.do");

    }

    else {

        websocket = new SockJS("http://172.30.99.37:8080/springmvcMybatis/sockjs/socketServer.do");

    }

    websocket.onopen = onOpen;     

    websocket.onmessage = onMessage;

    websocket.onerror = onError;

    websocket.onclose = onClose;

    function onOpen(openEvt) {

        //alert(openEvt.Data+"onOpen");

    }

    function onMessage(evt) {

            $('#msgDiv').val(evt.data)

       

            

    }

    function onError() {

        alert("出错"+"onError");

    }

    function onClose() {

        alert("关闭"+"onClose");

    }

    function doSend() {

        if (websocket.readyState == websocket.OPEN) {         

            var msg = document.getElementById("inputMsg").value; 

            websocket.send(msg);

        } else { 

            alert("连接失败!"); 

        } 

    }

    window.close=function(){

        websocket.onclose();

    }

</script>

<body align="center">

    <h3>消息推送</h3>

    请输入:<textarea rows="8" cols="50" id="inputMsg" name="inputMsg"></textarea>

    <button onclick="doSend();">发送</button>

    <hr/>

    <textarea rows="10" cols="70" id="msgDiv"></textarea>

</body>

</html>

另:web.xml中的servlet和filter中添加异步支持

<async-supported>true</async-supported>