zoukankan      html  css  js  c++  java
  • JAVA结合WebSocket实现简单客服聊天功能

    说明:该示例只简单的实现了客服聊天功能。

              1、聊天记录没有保存到数据库中,一旦服务重启,消息记录将会没有,如果需要保存到数据库中,可以扩展

              2、页面样式用的网上模板,样式可以自己进行修改

              3、只能由用户主要发起会话,管理员无法主动进行对话

              4、页面之间跳转代码没有包含在里面,请自己书写,在管理员消息列表页中,需要把该咨询的用户ID带到客服回复页面中

              5、${websocket_url} 这个为项目的URL地址

    效果截图:

    客服回复页面

    (member_admin_chat.html)

    管理员消息列表页

    (member_admin_chat_list.html)

      用户咨询页面

    (member_chat.html)


    代码:

    页面所需要用到的基础样式、图片,下载链接:https://www.lanzous.com/ias1kcb

    pom.xml

              <dependency>
    			<groupId>javax</groupId>
    			<artifactId>javaee-api</artifactId>
    			<version>8.0</version>
    			<scope>provided</scope>
    		</dependency>
    

     

    或者jar包

    tomcat7-websocket.jar

    websocket-api.jar 

    配置类

    WebSocketConfig.java

    package com.config;
    
    import javax.websocket.Endpoint;
    import javax.websocket.server.ServerApplicationConfig;
    import javax.websocket.server.ServerEndpointConfig;
    import java.util.Set;
    
    public class WebSocketConfig implements ServerApplicationConfig {
        @Override
        public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
            return null;
        }
    
        @Override
        public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
    
            //在这里会把含有@ServerEndpoint注解的类扫描加载进来 ,可以在这里做过滤等操作
    
            return scanned;
        }
    }
    

      

     消息DTO类(使用了lombok,这里不在多做说明)

    ChatDTO.java

    package com.websocket.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    
    /**
     * @author 。
     */
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    public class ChatDTO {
    
        /**
         * 用户ID
         */
        private String userId;
    
        /**
         * 用户发送信息
         */
        private String message;
    
        /**
         * 发送日期
         * 消息时间格式(yyyy-MM-dd)
         */
        private String createDate;
    
        /**
         * 发送时间
         * 消息时间格式(yyyy-MM-dd HH:mm:ss)
         */
        private String createTime;
    
        
    }
        
    

      

    用户DTO类

    ChatUserDTO.java

    package com.websocket.dto;
    
    import com.entity.CmsUser;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    /**
     * @author 。
     */
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    public class ChatUserDTO {
    
        /**
         * 用户id
         */
        private String userId;
    
        /**
         * 用户名
         */
        private String userName;
    
    
        /**
         * 用户图片
         */
        private String userImg;
    
    
        public ChatUserDTO convertUser(CmsUser user){
            ChatUserDTO chatUserDTO=new ChatUserDTO();
            chatUserDTO.setUserId(user.getId()+"")
                    .setUserName(user.getUsername())
                    .setUserImg(user.getUserImg());
            return chatUserDTO;
        }
    }
    

      

    ChatWebSocket.java

    package com.websocket;
    
    
    import com.service.RedisService;
    import com.util.DateFormatUtils;
    import com.entity.CmsUser;
    import com.manager.CmsUserMng;
    import com.enums.ChatTypeEnum;
    import com.websocket.Constants;
    import com.websocket.dto.ChatDTO;
    import com.websocket.dto.ChatUserDTO;
    import net.sf.json.JSONArray;
    import net.sf.json.JSONObject;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.web.context.ContextLoader;
    import org.springframework.web.context.WebApplicationContext;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.*;
    
    /**
     * @author*/
    @ServerEndpoint(value = "/chat_websocket")
    public class ChatWebSocket {
    
        private RedisService redisService;
    
        private CmsUserMng cmsUserMng;
    
    
        public ChatWebSocket() {
            WebApplicationContext webctx = ContextLoader.getCurrentWebApplicationContext();
            this.redisService = (RedisService) webctx.getBean("redisService");
            this.cmsUserMng = (CmsUserMng) webctx.getBean("cmsUserMng");
        }
    
        /**
         * 存储用户id
         */
        public static Map userMap = new HashMap();
    
    
        /**
         * 聊天记录
         */
        public static Map chatRecordMap = new HashMap();
    
    
        /**
         * 管理员列表session
         */
        public static Session adminSession;
    
    
        /**
         * 创建
         *
         * @param session
         */
        @OnOpen
        public void onOpen(Session session) {
            Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
            List<String> strs = requestParameterMap.get("msg");
            if (strs != null && strs.size() > 0) {
                String json = strs.get(0);
                //从聊天集中去掉该集合
                JSONObject object = JSONObject.fromObject(json);
                String userId = object.getString("user_id");
                String chatType = object.getString("chat_type");
    
                /*--------------管理员列表-----------------------*/
                if (ChatTypeEnum.adminListChatType.getKey().equalsIgnoreCase(chatType)) {
                    adminSession = session;
                    List list = getUserList(userMap);
                    //遍历所有聊天用户集合的id
                    chat_list_show(adminSession, list);
                    return;
    
                }
    
                /*--------------管理员聊天框打开-----------------------*/
                if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) {
                    //从集合中获取用户对应的数据加入信息列表中
                    List sessions = (List) userMap.get(userId);
                    if (sessions == null) {
                        sessions = new ArrayList();
                    }
                    sessions.add(session);
                    userMap.put(userId, sessions);
    
    
                }
    
                /*--------------用户聊天框打开-----------------------*/
                if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) {
                    //判断是否建立聊天通道
                    List sessions = (List) userMap.get(userId);
                    if (sessions == null) {
                        sessions = new ArrayList();
                    }
                    sessions.add(session);
                    userMap.put(userId, sessions);
    
    
    
                }
    
                //聊天记录信息存放
                List chatRecords = (List) chatRecordMap.get(userId);
                if (chatRecords != null) {
                    chat((List<Session>) userMap.get(userId), chatRecords);
                }
    
    
            }
        }
    
        /**
         * 发送消息
         *
         * @param json {userId:'',message:'',create_time:'',create_date:'',chat_type:'admin_list/admin_chat/user_chat'}
         *             admin_list:表示客服列表数据请求
         *             admin_chat:表示客服回复页面请求
         *             user_chat表示用户消息页面请求
         *
         *
         * @throws Exception
         */
        @OnMessage
        public void onMessage(Session session, String json) {
            JSONObject object = JSONObject.fromObject(json);
            //用户ID
            String userId = object.getString("user_id");
            //用户发送的信息
            String message = object.getString("message");
            //请求类型
            String chatType = object.getString("chat_type");
    
    
    
            /*--------------管理员聊天-----------------------*/
            if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) {
                //把管理员加入用户建立的聊天管道中
    
                //用户聊天
                //封装请求参数,时间为当前时间
                ChatDTO chatDTO = new ChatDTO();
                //userId=0表示是客服的回复
                chatDTO.setUserId("0")
                        .setMessage(message)
                        .setCreateDate(DateFormatUtils.formatDate(new Date()))
                        .setCreateTime(DateFormatUtils.formatDateTime(new Date()));
                //聊天记录信息存放
                List chatRecords = (List) chatRecordMap.get(userId);
                if (chatRecords == null) {
                    chatRecords = new ArrayList();
                }
                chatRecords.add(JSONObject.fromObject(chatDTO));
                chatRecordMap.put(userId, chatRecords);
                chat((List<Session>) userMap.get(userId), chatRecords);
    
            }
            /*--------------用户聊天-----------------------*/
            if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) {
    
                //封装请求参数,时间为当前时间
                ChatDTO chatDTO = new ChatDTO();
                chatDTO.setUserId(userId)
                        .setMessage(message)
                        .setCreateDate(DateFormatUtils.formatDate(new Date()))
                        .setCreateTime(DateFormatUtils.formatDateTime(new Date()));
                String key = chatDTO.getUserId();
    
                //聊天记录信息存放
                List chatRecords = (List) chatRecordMap.get(key);
                if (chatRecords == null) {
                    chatRecords = new ArrayList();
                }
                chatRecords.add(JSONObject.fromObject(chatDTO));
                chatRecordMap.put(key, chatRecords);
                chat((List<Session>) userMap.get(key), chatRecords);
                if (adminSession != null) {
                    List list = getUserList(userMap);
                    //遍历所有聊天用户集合的id
                    chat_list_show(adminSession, list);
    
                }
            }
    
    
    
    
        }
    
        /**
         * 关闭
         */
        @OnClose
        public void onClose(Session session) {
    
            Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
            List<String> strs = requestParameterMap.get("msg");
            if (strs != null && strs.size() > 0) {
                String json = strs.get(0);
                JSONObject object = JSONObject.fromObject(json);
                String userId = object.getString("user_id");
                String chatType = object.getString("chat_type");
    
    
                /*--------------管理员聊天框关闭-----------------------*/
                if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) {
    
    
    
    
                }
    
                /*--------------用户聊天框关闭-----------------------*/
                if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) {
    
    
    
                }
    
    
            }
    
        }
    
    
        /**
         * 发生错误
         *
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error) {
            System.out.println("发生错误");
            error.printStackTrace();
        }
    
        /**
         * 消息广播
         *
         * @param sessions
         * @param messages
         */
        public void chat(List<Session> sessions, List messages) {
            for (Iterator it = sessions.iterator(); it.hasNext(); ) {
                Session session = (Session) it.next();
                try {
                    if (session.isOpen()) {
                        //当当前会话没有被关闭 发送消息
                        session.getBasicRemote().sendText(JSONArray.fromObject(messages) + "");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        /**
         * 聊天列表显示
         */
        public void chat_list_show(Session session, List list) {
            try {
                if (session.isOpen()) {
                    //当当前会话没有被关闭 发送消息
                    session.getBasicRemote().sendText(JSONArray.fromObject(list) + "");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        /**
         * 通过id获取用户数据
         *
         * @return
         */
        public List getUserList(Map userMap) {
            List list = new ArrayList();
            for (Object str : userMap.keySet()) {
                ChatUserDTO chatUserDTO = new ChatUserDTO();
                CmsUser user = cmsUserMng.findById(Integer.valueOf(str + ""));
                list.add(chatUserDTO.convertUser(user));
            }
            return list;
        }
    
    
    }

      

     用户咨询页面

    member_chat.html

      1 <!doctype html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8"/>
      5     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
      6     <meta name="viewport"
      7           content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
      8     <title>客服咨询</title>
      9     <link rel="stylesheet" type="text/css" href="/${res}/chat/css/chat.css"/>
     10     <script src="/${res}/js/jquery.1.9.1.js"></script>
     11     <script src="/${res}/chat/js/flexible.js"></script>
     12 </head>
     13 <body>
     14 
     15 
     16 <header class="header">
     17     <a class="back" href="javascript:history.back()"></a>
     18     <h5 class="tit">客服</h5>
     19 </header>
     20 <div id="message">
     21 
     22 </div>
     23 <div id="footer">
     24     <img src="/${res}/chat/images/hua.png" alt=""/>
     25     <input class="my-input" type="text"/>
     26     <p class="send">发送</p>
     27 </div>
     28 <script>
     29 
     30     //聊天
     31     var ws;
     32     var obj = {
     33         user_id: '${user.id}',
     34         message: '',
     35         chat_type: "user_chat"
     36     }
     37     var target = "ws:${websocket_url!}/chat_websocket?msg=" + encodeURI(JSON.stringify(obj));
     38 
     39 
     40     var canSend = false;
     41     $(function () {
     42 
     43         //处理浏览器兼容性
     44         if ('WebSocket' in window) {
     45             ws = new WebSocket(target);
     46         } else if ('MozWebSocket' in window) {
     47             ws = new MozWebSocket(target);
     48         } else {
     49             alert('WebSocket is not supported by this browser.');
     50             return;
     51         }
     52 
     53         ws.onopen = function () {
     54 
     55         };
     56         ws.onmessage = function (event) {
     57             var data = JSON.parse(event.data);
     58             console.log(data)
     59             $('#message').html("");
     60             for (var i = 0; i < data.length; i++) {
     61                 if (data[i].userId != '${user.id}') {
     62                     reply("/${res}/chat/images/touxiangm.png", data[i].message);
     63                 } else {
     64                     ask("/${res}/chat/images/touxiang.png", data[i].message);
     65                 }
     66             }
     67         };
     68 
     69         ws.onclose = function (event) {
     70             alert("连接断开,请重新刷新页面");
     71             location.reload();
     72             1
     73         }
     74         $('#footer').on('keyup', 'input', function () {
     75             if ($(this).val().length > 0) {
     76                 $(this).next().css('background', '#114F8E').prop('disabled', true);
     77                 canSend = true;
     78             } else {
     79                 $(this).next().css('background', '#ddd').prop('disabled', false);
     80                 canSend = false;
     81             }
     82         })
     83         $('#footer .send').click(send)
     84         $("#footer .my-input").keydown(function (e) {
     85             if (e.keyCode == 13) {
     86                 return send();
     87             }
     88         });
     89     })
     90 
     91     /* 对方消息div */
     92     function reply(headSrc, str) {
     93         var html = "<div class='reply'><div class='msg'><img src=" + headSrc + " /><span class='name'>客服</span><p><i class='msg_input'></i>" + str + "</p></div></div>";
     94         return upView(html);
     95     }
     96 
     97     /* 自己消息div */
     98     function ask(headSrc, str) {
     99         var html = "<div class='ask'><div class='msg'><img src=" + headSrc + " />" + "<p><i class='msg_input'></i>" + str + "</p></div></div>";
    100         return upView(html);
    101     }
    102 
    103     function upView(html) {
    104         var message = $('#message');
    105         message.append(html);
    106         var h = message.outerHeight() - window.innerHeight;
    107         window.scrollTo(0, document.body.scrollHeight)
    108         return;
    109     }
    110 
    111     function send() {
    112         if (canSend) {
    113             var input = $("#footer .my-input");
    114             var val = input.val()
    115             var obj = {
    116                 user_id: '${user.id}',
    117                 message: val,
    118                 chat_type: "user_chat"
    119             }
    120             ws.send(JSON.stringify(obj));
    121             //ask("/${res}/chat/images/touxiangm.png", val);
    122             input.val('');
    123         }
    124     }
    125 </script>
    126 </body>
    127 </html>

    管理员消息列表页

    member_admin_chat_list.html

    <!DOCTYPE html>
    <html >
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui">
        <title>聊天列表 - ${site.name}</title>
        <script src="${resSys}/jquery.js" type="text/javascript"></script>
        <script src="${resSys}/front.js" type="text/javascript"></script>
        <link rel="stylesheet" href="/${res}/bootstrap/css/bootstrap.css">
        <script src="/${res}/bootstrap/js/bootstrap.js"></script>
    
    
        <!--[if lt IE 9]>
        <script src="/${res}/js/html5shiv.min.js"></script>
        <script src="/${res}/js/respond.min.js"></script>
        <![endif]-->
    
    </head>
    
    <style>
        .list-group-item span{
            margin-right: 10px;
        }
    </style>
    
    <body>
    [#include "../file/file_nav.html" /]
    
    
    <div>
        <ul class="list-group" id="userList">
            <li class="list-group-item">
                <img src="/${res}/chat/images/touxiang.png" alt=""/>
                <span class="badge">14</span>
                Cras justo odio
            </li>
        </ul>
    </div>
    
    
    
    
    </body>
    
    <script>
    
        var ws;
        var obj={
            user_id:'',
            message:'',
            chat_type:"admin_list"
        }
        var  target="ws:${websocket_url}/chat_websocket?msg="+encodeURI(JSON.stringify(obj));
    
        $(function () {
    
            //处理浏览器兼容性
            if ('WebSocket' in window) {
                ws = new WebSocket(target);
            } else if ('MozWebSocket' in window) {
                ws = new MozWebSocket(target);
            } else {
                alert('WebSocket is not supported by this browser.');
                return;
            }
    
    
            ws.onmessage = function (event) {
               var data=JSON.parse(event.data);
                var html="";
                if (data!=null&&data.length>0){
                    for (var i=0;i<data.length;i++){
                        var user=data[i];
                        html+="<a href='${base}/member/to_admin_chat_"+user.userId+".jspx'>"
                        html+="<li class='list-group-item'>";
                        html+="<img src='/${res}/chat/images/touxiang.png' />";
                        if (user.countmsg!=undefined){
                            html+="<span class='badge'>"+user.countmsg+"</span>"
                        }
                        html+=user.userName;
                        html+="</li>";
                        html+="</a>";
                    }
                }else {
                    html="<li style='text-align: center'>没有消息</li>";
                }
                $("#userList").html(html);
    
            };
    
            ws.onclose=function (event) {
    
            }
    
        })
    </script>
    </html>

    管理员消息回复页面

    member_admin_chat.html

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
        <meta name="viewport"
              content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
        <title>客服咨询</title>
        <link rel="stylesheet" type="text/css" href="/${res}/chat/css/chat.css"/>
        <script src="/${res}/js/jquery.1.9.1.js"></script>
        <script src="/${res}/chat/js/flexible.js"></script>
    </head>
    <body>
    
    
    <header class="header">
        <a class="back" href="javascript:history.back()"></a>
        <h5 class="tit">客服</h5>
    </header>
    <div id="message">
    
    </div>
    <div id="footer">
        <img src="/${res}/chat/images/hua.png" alt=""/>
        <input class="my-input" type="text"/>
        <p class="send">发送</p>
    </div>
    <script>
    
        //聊天
        var ws;
        var obj = {
            user_id: '${user.id}',
            message: '',
            chat_type: "user_chat"
        }
        var target = "ws:${websocket_url!}/chat_websocket?msg=" + encodeURI(JSON.stringify(obj));
    
    
        var canSend = false;
        $(function () {
    
            //处理浏览器兼容性
            if ('WebSocket' in window) {
                ws = new WebSocket(target);
            } else if ('MozWebSocket' in window) {
                ws = new MozWebSocket(target);
            } else {
                alert('WebSocket is not supported by this browser.');
                return;
            }
    
            ws.onopen = function () {
    
            };
            ws.onmessage = function (event) {
                var data = JSON.parse(event.data);
                console.log(data)
                $('#message').html("");
                for (var i = 0; i < data.length; i++) {
                    if (data[i].userId != '${user.id}') {
                        reply("/${res}/chat/images/touxiangm.png", data[i].message);
                    } else {
                        ask("/${res}/chat/images/touxiang.png", data[i].message);
                    }
                }
            };
    
            ws.onclose = function (event) {
                alert("连接断开,请重新刷新页面");
                location.reload();
            }
            $('#footer').on('keyup', 'input', function () {
                if ($(this).val().length > 0) {
                    $(this).next().css('background', '#114F8E').prop('disabled', true);
                    canSend = true;
                } else {
                    $(this).next().css('background', '#ddd').prop('disabled', false);
                    canSend = false;
                }
            })
            $('#footer .send').click(send)
            $("#footer .my-input").keydown(function (e) {
                if (e.keyCode == 13) {
                    return send();
                }
            });
        })
    
        /* 对方消息div */
        function reply(headSrc, str) {
            var html = "<div class='reply'><div class='msg'><img src=" + headSrc + " /><span class='name'>客服</span><p><i class='msg_input'></i>" + str + "</p></div></div>";
            return upView(html);
        }
    
        /* 自己消息div */
        function ask(headSrc, str) {
            var html = "<div class='ask'><div class='msg'><img src=" + headSrc + " />" + "<p><i class='msg_input'></i>" + str + "</p></div></div>";
            return upView(html);
        }
    
        function upView(html) {
            var message = $('#message');
            message.append(html);
            var h = message.outerHeight() - window.innerHeight;
            window.scrollTo(0, document.body.scrollHeight)
            return;
        }
    
        function send() {
            if (canSend) {
                var input = $("#footer .my-input");
                var val = input.val()
                var obj = {user_id: '${user.id}', message: val, chat_type: "user_chat"}
                ws.send(JSON.stringify(obj));
                //ask("/${res}/chat/images/touxiangm.png", val);
                input.val('');
            }
        }
    
    </script>
    </body>
    </html>
  • 相关阅读:
    python模块—socket
    mac os系统的快捷键
    教你如何将UIImageView视图中的图片变成圆角
    关于ASP.NET MVC
    iOS 日期格式的转换
    将App通过XCode上传到AppStore 出现这个错误“An error occurred uploading to the iTunes Store”的解决方法
    关于MAC OS下面两个软件的功能改进——Dictionary和Fit 输入法
    分享一下上个星期的香港行程
    【博客园IT新闻】博客园IT新闻 iPhone 客户端发布
    解决Entity Framework Code First 的问题——Model compatibility cannot be checked because the database does not contain model metadata
  • 原文地址:https://www.cnblogs.com/pxblog/p/12596111.html
Copyright © 2011-2022 走看看