Websocket --(2)实现

首先声明,本篇博文参考文章

https://blog.csdn.net/jack_eusong/article/details/79064081

主要在于理解和自己动手搭建环境,自己搭建的过程中会发生很多意想不到的错误。

1.环境

Eclipse Mars + jdk1.7 + tomcat8

2.使用的jar包,spring 的核心jar包就不写了,只写和websocket相关的。

<dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-websocket</artifactId>
         <version>4.0.2.RELEASE</version>
</dependency>

<dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-messaging</artifactId>
         <version>4.0.2.RELEASE</version>
</dependency>
        
<dependency>
     <groupId>javax.websocket</groupId>
     <artifactId>javax.websocket-api</artifactId>
     <version>1.1</version>
</dependency>

其实我感觉只用 javax.websocket-api 这一个包就够了,可能是我本地环境有问题,如果取消前面两个包Tomcat 无法启动,所以就只能留着了

搭建完的项目结构如下图

主要的代码注意一个类,通过@ServerEndpoint注解将类声明为服务端

package com.lzl.ws;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.apache.log4j.Logger;
import org.springframework.web.socket.server.standard.SpringConfigurator;

@ServerEndpoint(value="/chat/{userId}",configurator = SpringConfigurator.class)
public class websocketchat{
    public static Logger logger = Logger.getLogger(websocketchat.class);
    
    //在线人数
    public static int onlineCount = 0;
    
     //记录每个用户下多个终端的连接
    private static Map<String, Set<websocketchat>> userSocket = new HashMap<>();
 
    //需要session来对用户发送数据, 获取连接特征userId
    private Session session;
    private String userId;
    
    
    @OnOpen
    public void onOpen(@PathParam("userId") String userId,Session session) throws IOException{
        this.session = session;
        this.userId = userId;
        onlineCount++;
        //根据该用户当前是否已经在别的终端登录进行添加操作
        if (userSocket.containsKey(this.userId)) {
            logger.info("当前用户id:{"+this.userId+"}已有其他终端登录");
            userSocket.get(this.userId).add(this); //增加该用户set中的连接实例
        }else {
            logger.info("当前用户id:{"+this.userId+"}第一个终端登录");
            Set<websocketchat> addUserSet = new HashSet<>();
            addUserSet.add(this);
            userSocket.put(this.userId, addUserSet);
        }
        logger.info("用户{"+userId+"}登录的终端个数是为{"+userSocket.get(this.userId).size()+"}");
        logger.info("当前在线用户数为:{"+userSocket.size()+"},所有终端个数为:{"+onlineCount+"}");
    }

    @OnClose
    public void onClose(){
        //移除当前用户终端登录的websocket信息,如果该用户的所有终端都下线了,则删除该用户的记录
        if (userSocket.get(this.userId).size() == 0) {
            userSocket.remove(this.userId);
        }else{
            userSocket.get(this.userId).remove(this);
        }
        logger.info("用户{"+this.userId+"}登录的终端个数是为{"+userSocket.get(this.userId).size()+"}");
        logger.info("当前在线用户数为:{"+userSocket.size()+"},所有终端个数为:{"+onlineCount+"}");
    }
   
    /**
     * @Title: onMessage
     * @Description: 收到消息后的操作
     * @param @param message 收到的消息
     * @param @param session 该连接的session属性
     */
    @OnMessage
    public void onMessage(String message, Session session) {    
        logger.info("收到来自用户id为:{"+this.userId+"}的消息:{"+message+"}");
        if(session ==null)  logger.info("session null");
        //测试向客户端发送消息发送
        logger.info("开始将消息以广播形式发送至所有终端.......");
        sendMessageToUser( this.userId+"说:"+message);
        logger.info("广播结束.......");
    }
   
    /**
     * @Title: onError
     * @Description: 连接发生错误时候的操作
     * @param @param session 该连接的session
     * @param @param error 发生的错误
     */
    @OnError
    public void onError(Session session, Throwable error){
        logger.info("用户id为:{"+this.userId+"}的连接发送错误");
        error.printStackTrace();
    }
   
  /**
   * @Title: sendMessageToUser
   * @Description: 发送消息给用户下的所有终端
   * @param @param userId 用户id
   * @param @param message 发送的消息
   * @param @return 发送成功返回true,反则返回false
   */
    public Boolean sendMessageToUser(String message){
        for(Entry<String, Set<websocketchat>> entry:userSocket.entrySet()){
            logger.info(" 给用户id为:{"+entry.getKey()+"}的所有终端发送消息:{"+message+"}");
            for(websocketchat ws:entry.getValue()){
                 try {
                     ws.session.getBasicRemote().sendText(message);
                 } catch (IOException e) {
                     e.printStackTrace();
                     logger.info(" 给用户id为:{"+userId+"}发送消息失败");
                     return false;
                 }
            }
        }
        return true;
        
    }

}

前端界面

<%@ 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">
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript">
            $(function() {
                var websocket;
                if('WebSocket' in window) {
                                        console.log("此浏览器支持websocket");
                    websocket = new WebSocket("ws://127.0.0.1:8080/websocket/chat/tom");
                } else if('MozWebSocket' in window) {
                    alert("此浏览器只支持MozWebSocket");
                } else {
                    alert("此浏览器只支持SockJS");
                }
                websocket.onopen = function(evnt) {
                    $("#tou").html("链接服务器成功!")
                };
                websocket.onmessage = function(evnt) {
                    $("#msg").html($("#msg").html() + "<br/>" + evnt.data);
                };
                websocket.onerror = function(evnt) {};
                websocket.onclose = function(evnt) {
                    $("#tou").html("与服务器断开了链接!")
                }
                
                
                
                
                $('#send').click(function(){
                    send();
                });
 
                function send() {
                    if(websocket != null) {
                        var message = document.getElementById('message').value;
                        websocket.send(message);
                    } else {
                        alert('未与服务器链接.');
                    }
                }
            });
        </script>

<title>chat</title>
</head>
<body>
<div  >
    <div class="page-header" id="tou" style = "text-align:center">
            webSocket多终端聊天测试
        </div>
        <div class="well" id="msg" style = "width:800px;margin:0 auto"></div>
        &nbsp;
        <div class="col-lg">
            <div class="input-group" style = "width:800px;margin:0 auto">
                <input type="text" class="form-control" placeholder="发送信息..." id="message">
                <span class="input-group-btn">
                    <button class="btn btn-default" type="button" id="send" >发送</button>
                </span>
            </div>
        </div>
 </div>
</body>
</html>

 

在参考文章的基础上将发送消息改为群发形式,即一个人发送所有在线终端均可接收。chat.jsp,chat2.jsp,chat3.jsp用来模拟三个用户的登录。

 websocket = new WebSocket("ws://127.0.0.1:8080/websocket/chat/tom") 中websocket是我的工程名字,chat是服务端路径,tom是服务端参数,定义为用户ID。其实只用写一个界面即可,通过其他方式动态获取用户ID。这里为了方便测试,后续会增加一个登陆功能,然后将用户ID放到session中,获取用户ID后创建websocket对象,类似一个简易的聊天室功能。chat2和chat3 和chat 一模一样,只是更改了路径中的用户ID。这三个用户ID分别是tom jone jack,实现效果如下图。

 

posted @ 2018-07-24 17:47  脆皮香蕉  阅读(414)  评论(0编辑  收藏  举报