zoukankan      html  css  js  c++  java
  • websocket(二):SSM+websocket的聊天室

    在github上面找了一个看起来还不错的网页版聊天室,基于ssm加websocket实现的,特此分享一下,github地址放在文章末尾,大家可以自行下载跑起来玩玩,项目如何跑起来我写在readme里面了。接下来简单的看一下项目和核心代码的实现。

    登录页面:

    首页:可以实现单人聊天和群聊,还有机器人自动回复功能,还有一些个人设置,系统设置功,日志统计功能...

     接下来看看核心代码websocket的实现:

    首页jsp关于websocket的代码:

     var wsServer = null;
        var ws = null;
        wsServer = "ws://" + location.host+"${pageContext.request.contextPath}" + "/chatServer/${userid}";
        ws = new WebSocket(wsServer); //创建WebSocket对象
        ws.onopen = function (evt) {
            layer.msg("已经建立连接", { offset: 0});
        };
        ws.onmessage = function (evt) {
            analysisMessage(evt.data);  //解析后台传回的消息,并予以展示
        };
        ws.onerror = function (evt) {
            layer.msg("产生异常", { offset: 0});
        };
        ws.onclose = function (evt) {
            layer.msg("已经关闭连接," + evt.reason, { offset: 0});
        };

    websocket server的实现;

    package com.ccq.webSocket;
    
    import com.ccq.pojo.User;
    import com.ccq.utils.CommonDate;
    import net.sf.json.JSONObject;
    import org.apache.log4j.Logger;
    
    import javax.servlet.http.HttpSession;
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @author ccq
     * @Description webSocket服务
     * @date 2017/12/16 17:31
     */
    @ServerEndpoint(value="/chatServer/{userid}", configurator = HttpSessionConfigurator.class)
    public class ChatServer {
    
        private static Logger logger = Logger.getLogger(ChatServer.class);
        private static int onlineCount = 0; // 记录连接数目
        // Map<用户id,用户信息>
        private static Map<String, OnlineUser> onlineUserMap = new ConcurrentHashMap<String, OnlineUser>(); // 在线用户
    
        /**
         * 连接成功调用的方法
         */
        @OnOpen
        public void onOpen(@PathParam("userid") String userid , Session session, EndpointConfig config){
    
            logger.info("[ChatServer] connection : userid = " + userid + " , sessionId = " + session.getId());
    
            // 增加用户数量
            addOnlineCount();
    
            // 获取当前用户的session
            HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
            User user  = (User) httpSession.getAttribute("user"); // 获得当前用户信息
    
            // 将当前用户存到在线用户列表中
            OnlineUser onlineUser = new OnlineUser(user.getUserid(),user.getNickname(),session);
            onlineUserMap.put(user.getUserid(),onlineUser);
    
            // 通知所有在线用户,当前用户上线
            String content = "[" + CommonDate.getTime24() + " : " + user.getNickname() + "加入聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]";
            JSONObject msg = new JSONObject();
            msg.put("content",content);
            String message = Message.getMessage(msg.toString(),Message.NOTICE,onlineUserMap.values());
            Message.broadcast(message,onlineUserMap.values());
    
        }
    
        /**
         * 连接关闭方法
         */
        @OnClose
        public void onClose(@PathParam("userid") String userid,Session session,CloseReason closeReason){
    
            logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +
                    " , closeCode = " + closeReason.getCloseCode().getCode() + " , closeReason = " +closeReason.getReasonPhrase());
    
            // 减少当前用户
            subOnlienCount();
    
            // 移除的用户信息
            OnlineUser removeUser = onlineUserMap.remove(userid);
            onlineUserMap.remove(userid);
    
            // 通知所有在线用户,当前用户下线
            String content = "["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]";
            JSONObject msg = new JSONObject();
            msg.put("content",content);
            if(onlineUserMap.size() > 0){
                String message = Message.getMessage(msg.toString(), Message.NOTICE, onlineUserMap.values());
                Message.broadcast(message,onlineUserMap.values());
            }else{
                logger.info("content : ["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]");
            }
    
        }
    
        /**
         * 接收客户端的message,判断是否有接收人而选择进行广播还是指定发送
         * @param data 客户端发来的消息
         */
        @OnMessage
        public void onMessage(@PathParam("userid") String userid,String data){
            logger.info("[ChatServer] onMessage : userid = " + userid + " , data = " + data);
    
            JSONObject messageJson = JSONObject.fromObject(data);
            JSONObject message = messageJson.optJSONObject("message");
            String to = message.optString("to");
            String from = message.optString("from");
            // 将用户id转换为名称
            to = this.userIdCastNickName(to);
    
            OnlineUser fromUser = onlineUserMap.get(from);
            String sendMessage = Message.getContent(fromUser,to,message.optString("content"),message.optString("time"));
            String returnData = Message.getMessage(sendMessage, messageJson.optString("type"),null);
    
            if(to == null || to.equals("")){ // 进行广播
                Message.broadcast(returnData.toString(),onlineUserMap.values());
            }else{
                Message.singleSend(returnData.toString(), onlineUserMap.get(from));   // 发送给自己
                String[] useridList = message.optString("to").split(",");
                for(String id : useridList){
                    if(!id.equals(from)){
                        Message.singleSend(returnData.toString(), onlineUserMap.get(id)); // 分别发送给指定的用户
                    }
                }
            }
        }
    
        /**
         * 发生错误
         * @param throwable
         */
        @OnError
        public void onError(@PathParam("userid") String userid,Session session,Throwable throwable){
            logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +" , throwable = " + throwable.getMessage() );
        }
    
    
        public static int getOnlineCount() {
            return onlineCount;
        }
    
        public synchronized void addOnlineCount(){
            onlineCount++;
        }
    
        public synchronized void subOnlienCount(){
            onlineCount--;
        }
    
        /**
         * 将用户id转换为名称
         * @param userIds
         * @return
         */
        private String userIdCastNickName(String userIds){
            String niceNames = "";
            if(userIds != null && !userIds.equals("")){
                String[] useridList = userIds.split(",");
                String toName = "";
                for (String id : useridList){
                    toName = toName + onlineUserMap.get(id).getNickname() + ",";
                }
                niceNames = toName.substring(0,toName.length() - 1);
            }
            return niceNames;
        }
    }

    私聊和群聊的发送代码:

     /**
         * 广播消息
         * @param message 消息
         * @param onlineUsers 在线用户
         */
        public static void broadcast(String message,Collection<OnlineUser> onlineUsers){
            /***************************在线用户***************************/
            StringBuffer userStr = new StringBuffer();
            for(OnlineUser user : onlineUsers){
                userStr.append(user.getNickname() + ",");
            }
            userStr.deleteCharAt(userStr.length()-1);
            logger.info("[broadcast] message = " + message + ", onlineUsers = " + userStr.toString());
            /***************************在线用户***************************/
            for(OnlineUser user : onlineUsers){
                    try {
                        user.getSession().getBasicRemote().sendText(message);
                    } catch (IOException e) {
                        e.printStackTrace();
                        logger.info("消息发送失败!" + e.getMessage());
                        continue;
                    }
            }
        }
    
        /**
         * 对特定用户发送消息
         * @param message
         * @param onlineUser
         */
        public static void singleSend(String message, OnlineUser onlineUser){
            logger.info("[singleSend] message = " + message + ", toUser = " + onlineUser.getNickname());
            try {
                onlineUser.getSession().getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
                logger.info("消息发送失败!" + e.getMessage());
            }
        }

    记住几个关键api:

    OnOpen:建立连接
    OnClose:关闭连接
    OnMessage:接收消息
    发送消息的核心方法是通过某个session的.getBasicRemote().sendText(message)来发送的。
    ok,websocket大概就是这样,你可以亲自啊跑一下试试,也十分欢迎大家一起来丰富这个小项目,增加一些有趣的功能,让大家欣赏,我会第一时间在github上面写上你的大名,以表感谢。
    github链接:https://github.com/MrLiu1227/WebChat.git
    没有基础的同学可以跑一个十分干净的websocket示例:https://github.com/MrLiu1227/websocket.git
  • 相关阅读:
    如何设定测试目标
    转载:Robotium之Android控件定位实践和建议(Appium/UIAutomator姊妹篇)
    Jenkins启动时报错:java.net.BindException: Address already in use: bind 解决方法
    [转载]Robotium API 翻译(三)——判断测试结果的方法assert、is、search
    什么样的项目适合开展自动化测试
    Python基础11- 函数之自定义函数
    Python基础10- 函数之内部函数与强制转换
    Android获取APK包名的几种方法
    Python基础9- 字典
    回归测试策略
  • 原文地址:https://www.cnblogs.com/liuyuan1227/p/10889436.html
Copyright © 2011-2022 走看看