Spring WebSocket实现消息推送

来源:互联网 发布:大型网络枪战游戏 编辑:程序博客网 时间:2024/05/16 13:56

第一步: 添加Spring WebSocket的依赖jar包

(注:这里使用maven方式添加 手动添加的同学请自行下载相应jar包放到lib目录)

复制代码
        <!-- 使用spring websocket依赖的jar包 -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-websocket</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-messaging</artifactId>            <version>${spring.version}</version>        </dependency>            
复制代码

第二步:建立一个类实现WebSocketConfigurer接口

复制代码
package com.quicksand.push;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.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@EnableWebMvc@EnableWebSocketpublic class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {    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();    }}
复制代码

 第三步:继承WebSocketHandler对象。该对象提供了客户端连接,关闭,错误,发送等方法,重写这几个方法即可实现自定义业务逻辑

复制代码
package com.quicksand.push;import java.io.IOException;import java.util.ArrayList;import org.apache.log4j.Logger;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 ArrayList<WebSocketSession> users;//这个会出现性能问题,最好用Map来存储,key用userid    private static Logger logger = Logger.getLogger(SpringWebSocketHandler.class);    static {        users = new ArrayList<WebSocketSession>();    }        public SpringWebSocketHandler() {        // TODO Auto-generated constructor stub    }    /**     * 连接成功时候,会触发页面上onopen方法     */    public void afterConnectionEstablished(WebSocketSession session) throws Exception {        // TODO Auto-generated method stub        System.out.println("connect to the websocket success......当前数量:"+users.size());        users.add(session);        //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户        //TextMessage returnMessage = new TextMessage("你将收到的离线");        //session.sendMessage(returnMessage);    }        /**     * 关闭连接时触发     */    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {        logger.debug("websocket connection closed......");        String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");        System.out.println("用户"+username+"已退出!");        users.remove(session);        System.out.println("剩余在线用户"+users.size());    }    /**     * js调用websocket.send时候,会调用该方法     */    @Override        protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {        super.handleTextMessage(session, message);    }    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {        if(session.isOpen()){session.close();}        logger.debug("websocket connection closed......");        users.remove(session);    }    public boolean supportsPartialMessages() {        return false;    }            /**     * 给某个用户发送消息     *     * @param userName     * @param message     */    public void sendMessageToUser(String userName, TextMessage message) {        for (WebSocketSession user : users) {            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) {            try {                if (user.isOpen()) {                    user.sendMessage(message);                }            } catch (IOException e) {                e.printStackTrace();            }        }    }}
复制代码

第四步:继承HttpSessionHandshakeInterceptor对象。该对象作为页面连接websocket服务的拦截器,代码如下:

复制代码
package com.quicksand.push;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;/** * WebSocket拦截器 * @author WANG * */public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {    @Override    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,            Map<String, Object> attributes) throws Exception {        // TODO Auto-generated method stub        System.out.println("Before Handshake");        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) {        // TODO Auto-generated method stub        super.afterHandshake(request, response, wsHandler, ex);    }}
复制代码

第5步 让SpringWebSocketConfig配置类随spring容器启动 spring文件中加入如下代码:

<!-- websocket相关扫描,主要扫描:WebSocketConfig  如果前面配置能扫描到此类则可以不加 --><context:component-scan base-package="com.quicksand.push"/>

 

 

-------------------------------------------------------------------------到这里就算完成啦 下面准备测试-------------------------------------------------------------

1.定义一个控制器用来做连接标识和发送消息

复制代码
package com.quicksand.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.context.annotation.Bean;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.socket.TextMessage;import com.quicksand.push.SpringWebSocketHandler;@Controllerpublic class WebsocketController {    @Bean//这个注解会从Spring容器拿出Bean    public SpringWebSocketHandler infoHandler() {        return new SpringWebSocketHandler();    }    @RequestMapping("/websocket/login")    public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception {        String username = request.getParameter("username");        System.out.println(username+"登录");        HttpSession session = request.getSession(false);        session.setAttribute("SESSION_USERNAME", username);        //response.sendRedirect("/quicksand/jsp/websocket.jsp");        return new ModelAndView("websocket");    }    @RequestMapping("/websocket/send")    @ResponseBody    public String send(HttpServletRequest request) {        String username = request.getParameter("username");        infoHandler().sendMessageToUser(username, new TextMessage("你好,测试!!!!"));        return null;    }}
复制代码

 

2.建立登录页面

复制代码
<%@ 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><body><h2>Hello World!</h2><body>    <!-- ship是我的项目名-->    <form action="websocket/login.do">        登录名:<input type="text" name="username"/>        <input type="submit" value="登录"/>    </form></body></body></html>
复制代码

 

3.建立发消息页面

复制代码
<%@ 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>Insert title here</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 websocket = null;    if ('WebSocket' in window) {        websocket = new WebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do");    }     else if ('MozWebSocket' in window) {        websocket = new MozWebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do");    }     else {        websocket = new SockJS("http://localhost:8080/quicksand/sockjs/socketServer.do");    }    websocket.onopen = onOpen;    websocket.onmessage = onMessage;    websocket.onerror = onError;    websocket.onclose = onClose;                  function onOpen(openEvt) {        //alert(openEvt.Data);    }        function onMessage(evt) {        alert(evt.data);    }    function onError() {}    function onClose() {}        function doSend() {        if (websocket.readyState == websocket.OPEN) {                      var msg = document.getElementById("inputMsg").value;              websocket.send(msg);//调用后台handleTextMessage方法            alert("发送成功!");          } else {              alert("连接失败!");          }      }

   window.close=function()
   {
     websocket.onclose();
   }

</script>请输入:<textarea rows="5" cols="10" id="inputMsg" name="inputMsg"></textarea><button onclick="doSend();">发送</button></body></html>
复制代码

 

测试结果如下图:

原创粉丝点击