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>
  • 相关阅读:
    使用ASP.Net MVC5 Web API OData和Sencha Touch 开发WebAPP
    @MarkFan 口语练习录音 20140401
    Listening Carefully SP1403S
    Listening Carefully SP1403
    团队股权分配
    Sencha Architect 安装与使用
    离乡与理想 Demo
    PowerDesigner创建物理模型
    SOA 面向服务架构 阅读笔记(六)
    SOA 面向服务架构 阅读笔记(五)
  • 原文地址:https://www.cnblogs.com/pxblog/p/12596111.html
Copyright © 2011-2022 走看看