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 (這個只是自己網上下載的樣式demo,可以根據自己的來)

 

pom.xml

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

 

或者jar包

javax.websocket-api-1.0.jar

下載地址:https://yvioo.lanzous.com/i3AXkhl3s3c

 

 

 

配置類

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;
    }


}

 

 聊天枚舉類

ChatTypeEnum.java

 

package com.websocket;
/**
 * @author*/

public enum ChatTypeEnum {

    adminListChatType("admin_list", "管理員列表"),
    adminChatType("admin_chat", "管理員聊天"),
    userChatType("user_chat", "用戶聊天"),
    chatCountType("chat_count","消息數目");


    private String key;

    public String value;

    ChatTypeEnum() {
    }

    ChatTypeEnum(String key, String value) {
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

 

 

 用戶咨詢頁面

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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM