美文网首页
springMVC+websockt实现

springMVC+websockt实现

作者: 请让我想一想 | 来源:发表于2018-11-21 21:17 被阅读0次

    场景还原:即时通讯,类似微信qq这种效果

    代码实现:

    环境:

    1. Tomcat 7+
    2. Maven+SpringMVC+Mybatis

    代码实现:

    流程梳理:前端请求后端,建立socket连接,成功后保持连接状态,
    前端代码:

     $(document).ready(function () {
            // 指定websocket路径
            var websocket;
            if ('WebSocket' in window) {
            // Spring-websocket 自己项目名称
                websocket = new WebSocket("ws://localhost:8080/Spring-websocket/ws?uid=" +${sessionScope.uid});
            } else if ('MozWebSocket' in window) {
                websocket = new MozWebSocket("ws://localhost:8080/Spring-websocket/ws" +${sessionScope.uid});
            } else {
                websocket = new SockJS("http://localhost:8080/Spring-websocket/ws/sockjs" +${sessionScope.uid});
            }
          // 上面执行完成,就已经与后端建立好了socket连接
    
          
            // 后端有消息通知会触发这个事件
            websocket.onmessage = function (event) {
                var data = JSON.parse(event.data);
                if (data.from > 0 || data.from == -1) {//用户或者群消息
                    // 接收服务端的实时消息并添加到HTML页面中
                    $("#log-container").append("<div class='bg-info'><label class='text-danger'>" + data.fromName + "&nbsp;" + data.date + "</label><div class='text-success'>" + data.text + "</div></div><br>");
                    // 滚动条滚动到最低部
                    scrollToBottom();
                } else if (data.from == 0) {//上线消息
                    if (data.text != "${sessionScope.username}") {
                        $("#users").append('<a href="#" onclick="talk(this)" class="list-group-item">' + data.text + '</a>');
                        alert(data.text + "上线了");
                    }
                } else if (data.from == -2) {//下线消息
                    if (data.text != "${sessionScope.username}") {
                        $("#users > a").remove(":contains('" + data.text + "')");
                        alert(data.text + "下线了");
                    }
                }
            };
          
            $("#send").click(function () {
                $.post("getuid", {"username": $("body").data("to")}, function (d) {
                    var v = $("#myinfo").val();
    
                    if (v == "") {
                        return;
                    } else {
                        var data = {};
                        data["from"] = "${sessionScope.uid}";
                        data["fromName"] = "${sessionScope.username}";
                        data["to"] = d.uid;
                        data["text"] = v;
                        // 发送socket信息,首先会被socket核心类拦截,在里面会根据参数获取指定通知的用户,发送通知
                        websocket.send(JSON.stringify(data));
                        $("#log-container").append("<div class='bg-success'><label class='text-info'>我&nbsp;" + new Date() + "</label><div class='text-info'>" + v + "</div></div><br>");
                        scrollToBottom();
                        $("#myinfo").val("");
                    }
                });
    
            });
    
        });
    

    后端代码:3个核心类

    
    
    
    
    /**
     * Socket建立连接(握手)和断开
     */
    public class HandShake implements HandshakeInterceptor {
    
        public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
            System.out.println("Websocket:用户[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已经建立连接");
            if (request instanceof ServletServerHttpRequest) {
                ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                HttpSession session = servletRequest.getServletRequest().getSession(false);
                // 标记用户
                Long uid = (Long) session.getAttribute("uid");
                if(uid!=null){
                    attributes.put("uid", uid);
                }else{
                    return false;
                }
            }
            return true;
        }
    
        public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("after hand");
        
        }
    
    }
    
    
    
    
    /**
     * Socket处理器
     */
    @Component
    public class MyWebSocketHandler implements WebSocketHandler {
        //用于保存HttpSession与WebSocketSession的映射关系
        public static final Map<Long, WebSocketSession> userSocketSessionMap;
    
        @Autowired
        LoginService loginservice;
        
        static {
            userSocketSessionMap = new ConcurrentHashMap<Long, WebSocketSession>();
        }
        
        /**
         * 建立连接后,把登录用户的id写入WebSocketSession
         */
        public void afterConnectionEstablished(WebSocketSession session)
                throws Exception {
            Long uid = (Long) session.getAttributes().get("uid");
            String username=loginservice.getnamebyid(uid);
            if (userSocketSessionMap.get(uid) == null) {
                userSocketSessionMap.put(uid, session);
                Message msg = new Message();
                msg.setFrom(0L);//0表示上线消息
                msg.setText(username);
                this.broadcast(new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
            }
        }
    
        /**
         * 消息处理,在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理
         */
        public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
                if(message.getPayloadLength()==0)
                    return;
                Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);
                msg.setDate(new Date());
                sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
        }
    
        /**
         * 消息传输错误处理
         */
        public void handleTransportError(WebSocketSession session,
                Throwable exception) throws Exception {
            if (session.isOpen()) {
                session.close();
            }
            Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();
            // 移除当前抛出异常用户的Socket会话
            while (it.hasNext()) {
                Entry<Long, WebSocketSession> entry = it.next();
                if (entry.getValue().getId().equals(session.getId())) {
                    userSocketSessionMap.remove(entry.getKey());
                    System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
                    String username=loginservice.getnamebyid(entry.getKey());
                    Message msg = new Message();
                    msg.setFrom(-2L);
                    msg.setText(username);
                    this.broadcast(new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
                    break;
                }
            }
        }
    
        /**
         * 关闭连接后
         */
        public void afterConnectionClosed(WebSocketSession session,CloseStatus closeStatus) throws Exception {
            System.out.println("Websocket:" + session.getId() + "已经关闭");
            Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();
            // 移除当前用户的Socket会话
            while (it.hasNext()) {
                Entry<Long, WebSocketSession> entry = it.next();
                if (entry.getValue().getId().equals(session.getId())) {
                    userSocketSessionMap.remove(entry.getKey());
                    System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
                    String username=loginservice.getnamebyid(entry.getKey());
                    Message msg = new Message();
                    msg.setFrom(-2L);//下线消息,用-2表示
                    msg.setText(username);
                    this.broadcast(new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
                    break;
                }
            }
        }
    
        public boolean supportsPartialMessages() {
            return false;
        }
    
        /**
         * 给所有在线用户发送消息
         * @param message
         * @throws IOException
         */
        public void broadcast(final TextMessage message) throws IOException {
            Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator();
    
            //多线程群发
            while (it.hasNext()) {
    
                final Entry<Long, WebSocketSession> entry = it.next();
    
                if (entry.getValue().isOpen()) {
                    // entry.getValue().sendMessage(message);
                    new Thread(new Runnable() {
    
                        public void run() {
                            try {
                                if (entry.getValue().isOpen()) {
                                    entry.getValue().sendMessage(message);
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
    
                    }).start();
                }
    
            }
        }
    
        /**
         * 给某个用户发送消息
         * 
         * @param userName
         * @param message
         * @throws IOException
         */
        public void sendMessageToUser(Long uid, TextMessage message) throws IOException {
            WebSocketSession session = userSocketSessionMap.get(uid);
            if (session != null && session.isOpen()) {
                session.sendMessage(message);
            }
        }
    
    }
    
    
    /**
     * WebScoket配置处理器
     */
    @Component
    @EnableWebSocket
    public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    
        @Resource
        MyWebSocketHandler handler;
    
        public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
            registry.addHandler(handler, "/ws").addInterceptors(new HandShake());
    
            registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();
        }
    
    }
    
    
    

    spring-mvc.xml配置

    // 配置websocket 3个核心配置类的包,其他配置按自己项目定义即可
    <context:component-scan base-package="controller,service.impl,websocket" />
    

    结束:这只是部分socket代码抽取,参考了码云项目

    源码可直接跳转:https://gitee.com/shenzhanwang/Spring-websocket.git
    感谢这个作者的无私奉献.

    相关文章

      网友评论

          本文标题:springMVC+websockt实现

          本文链接:https://www.haomeiwen.com/subject/rwehqqtx.html