1. 程式人生 > >基於融雲api開發客服聊天功能

基於融雲api開發客服聊天功能

以下所有內容均為本人自己開發總結的經驗,如有雷同,不勝榮幸!

最近公司在做一款app,app裡面涉及到與客服聊天功能。

於是公司就接入了融雲api聊天系統。

app端(前端)聊天由專業的ios andorid開發人員完成,我負責開發後臺客服聊天即可。

目前使用的是ssm 4.0框架,jdk1.8

框架就自行搭建了。能執行就行。下面就詳細聊聊接入融雲,並開發聊天。

注:融雲是收費的。各位看官如果是使用收費模式,則不需要觀看該文章,因為我是自行開發的。

涉及功能:1對1聊天,聊天記錄儲存,會話列表,未讀訊息,是否線上(這些功能屬於後臺,前端的我不管。)

1:1vs1 聊天,(從app端看來是使用者對客服1vs1,從客服對app端則是1vs n)(n:即多個使用者,所以這邊會有會話聊天列表)

因為只有1對1聊天是免費的。所以除了1對1聊天,其他功能全部本地開發,並未使用融雲api。

融雲api配置我就不說了。網上一大堆。隨便看看就ok。

配置只有一點要注意:

這個要放進來。這個是融雲的聊天格式,

不論是前端還是後端。使用者聊天都必須使用token 這是融雲要求的。所以獲得token是服務端完成的。

如果上面的圖片沒有放入到專案中,那麼你服務端獲取token是失敗的。

這個坑是摸索半天,看了半天的原始碼才搞通

String userToken = UserExample.returnToken(users.getUsers_only_md5(), usersInfo.getUsers_info_nick(),RongYunKeyEnum.APPKEY.getValue(),                     RongYunKeyEnum.APPSECRET.getValue());             req.setAttribute("userToken", userToken);

returnToken 是我在 UserExample 類裡自己封裝了方法,當引數傳進來而已。自己隨便寫就行。

服務端token寫好了。頁面端需要2個值, token 和appKey   用request 傳作用域就行

記得返回到聊天的頁面來。

融雲是用id 作為聊天的唯一物件。所以我這邊用自己資料庫的唯一列作為傳遞到融雲的id值。所以我傳遞到頁面上,方面2人聊天。

我這邊解釋下,我是本地跟本地聊天。並未涉及到和app聊天。所以我要區分,該登入是使用者還是客服。可以用2個登入方法登入頁面來實現。(identity:區分身份(users/manager))

<script type="text/javascript">     $(document).keyup(function(event){           if(event.keyCode ==13){                privateMessage();           }     });     var instance = null;     var userInfo = {         appKey : "${appKey}",         token : "${userToken}"     };     function showTips(data){         var dom = document.getElementById("show");             dom.style.display = "block";         if(data){             dom.innerHTML += "<li>" + data + "</li>";         }else{             dom.innerHTML = "";         }     }         var callbacks = {         getInstance : function(_instance){             instance = _instance;         },         receiveNewMessage : function(message){             // 判斷訊息型別             showTips("新訊息,型別為:" + message.messageType);             // showResult("新訊息",message,start);

            console.log("messageUId:" + message.messageUId + ",   messageId:" + message.messageId);             console.log(message);         },         getCurrentUser : function(userInfo){             userId = userInfo.userId;             $("#login").val(userId);             //afterConnected();         }     };     init(userInfo, callbacks); </script>

頁面上這段js 用來初始化融雲 或者說使用者是否登入成功了。可以F12檢視的。

聊天:就是。我發訊息給你,你收到訊息,你發訊息給我,我收到訊息。

var recallMessage = null, clearMessage;     function markMessage(message){         recallMessage = message;         clearMessage = message;     }

// 訊息監聽器     RongIMClient.setOnReceiveMessageListener({         // 接收到的訊息         onReceived: function (message) {             // 判斷訊息型別             console.log(message.content.content);             if("附加資訊" == message.content.extra){                 //這邊要修改成                 //是否跟當前使用者在聊天                 //判斷使用者來增加未讀數量還是顯示在當前了聊天框中                 //所以一下該function需要進行修改。                 //getNewMsgUser();             }             //有新訊息進來的時候,先進入資料庫執行,該使用者是否能接收訊息,             //如果不能接收,則進行未讀訊息數量修改,             //否則直接進入聊天介面                          var htmls = "<div class=\"leftd\">"+                     "<div style=\"float:left;\">"+                     "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                     "</div>"+                     "<div class=\"speech left\" style=\"margin-left:61px;\">"+message.content.content+"</div>"+                     "</div>";                          $("#liaotian").append(htmls);                      $("#getMessage").val(message.content.content);             //message接受到的訊息(包含傳送的資訊,也可以在extra中新增要傳遞的值,如:時間等)                          $('#liaotian').scrollTop($('#liaotian')[0].scrollHeight);         }     });

該方法是用來接收有人發訊息過來。中間有一段註釋的內容。我還在開發中,你們也可以自己想想,文字描述很清晰

//私聊     function privateMessage(){         var sendMsg = $("#sendMessage").val();         if("" == sendMsg){             alert("請輸入聊天內容");             $('#sendMessage').focus();             return;         }         var conversationtype = RongIMLib.ConversationType.PRIVATE; // 私聊         var targetId = $("#toUserId").val(); // 目標 Id         var msg = new RongIMLib.TextMessage({content:sendMsg,extra:"附加資訊"});         var conversationtype = RongIMLib.ConversationType.PRIVATE; // 單聊,其他會話選擇相應的訊息型別即可。         var pushData = "your pushInfo";//這個暫時還沒研究         RongIMClient.getInstance().sendMessage(conversationtype, targetId, msg, {                 onSuccess: function (message) {                     //傳送成功後,將該條傳送的訊息記錄到資料庫中                     //如果資料庫插入成功,則進行頁面的傳送訊息append到html聊天框裡。                                          var htmls = "<div class=\"rightd\">"+                     "<div style=\"float:right;\">"+                     "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                     "</div>"+                     "<div class=\"speech right\" style=\"margin-right:61px;\">"+message.content.content+"</div>"+                     "</div>";                                  $("#liaotian").append(htmls);                     var sendMsg = $("#sendMessage").val("");                     console.log(message.content.content);                     $('#liaotian').scrollTop($('#liaotian')[0].scrollHeight);                                      },                 onError: function (errorCode,message) {                    console.log(message.content.content);                 }             }, false, pushData         );     }

該方法就是我傳送訊息,傳送聊天內容等

//獲取會話列表     function findMsgUser(){         var currUserId = '${currUserId}';         $.get("${ctx}/webMessageUserList/selectWebMessageUserList.htmls",{only_md5:'${currUserId}'},function(data){             var objList = eval(data);             var htmls = "";             if(objList.code == 20000){                 for(i=0;i<objList.entity.length;i++){                     var b = objList.entity[i].users_only_md5;                     if(objList.entity[i].users_only_md5 != currUserId){                         htmls += "<div style=\"width:180px;height:60px;\" onclick=\"pushUser('"+objList.entity[i].users_only_md5+"')\">"+                             "<img alt=\"使用者頭像\" width=\"40px\" height=\"40px\" src=\""+objList.entity[i].users_info_photo+"\">"+                             "<label>"+objList.entity[i].users_info_nick+"</label>"+                             "&nbsp;<label style=\"color:red;\">"+objList.entity[i].web_message_user_list_read_count+"</label></div>";                     }else{                         htmls += "<div style=\"width:180px;height:60px;\" onclick=\"pushMaster('"+objList.entity[i].master_only_md5+"')\">"+                             "<img alt=\"使用者頭像\" width=\"40px\" height=\"40px\" src=\""+objList.entity[i].users_info_photo+"\">"+                             "<label>"+objList.entity[i].users_info_nick+"</label>"+                             "&nbsp;<label style=\"color:red;\">"+objList.entity[i].web_message_user_list_read_count+"</label></div>";                     }                 }             }else{                 var htmls = "<div style=\"width:180px;height:60px;\">"+                     "<img alt=\"使用者頭像\" width=\"40px\" height=\"40px\" src=\"${ctx}/img/20180917141606.png\">"+                     "<label>暫無會話使用者</label></div>";             }             $("#newMsgUser").html(htmls);         });     }

該方法是獲取會話列表。因為融雲的會話列表是收費的。所以我自己寫一個會話列表:

需要建立資料庫,然後將客服與使用者聊天建立一條會話資料,作為聊天的列表模式,不需要重複建立,需要自己判斷,

怎麼建立這個資料呢。首先。客服是不能主動找未聊天過的 使用者聊!!!!即只有app端先發起客服聊天,客服才有資格去回覆。

所以會話列表的資料建立,應該有app端發起時,在介面處去建立會話列表資料。

:目前這一塊我還沒有寫。所以自己建立的幾個臨時的資料,

而且我這邊是本地跟本地聊,即開啟2個瀏覽器去聊。所以暫時還沒去寫,不過,並不難。

//客服跟使用者聊天     function pushUser(users_only_md5){         if(toUserId != users_only_md5){             toUserId = users_only_md5;             hisHtmls = "";             $("#liaotian").html(hisHtmls);             $("#toUserId").val(users_only_md5);             getHisMsgUser(users_only_md5);         }     }

//使用者跟客服聊天     function pushMaster(master_only_md5){         if(toUserId != master_only_md5){             toUserId = master_only_md5;             hisHtmls = "";             $("#liaotian").html(hisHtmls);             $("#toUserId").val(master_only_md5);             getHisMsgMaster(master_only_md5);         }     }

有以上2個方法,是因為我用2個瀏覽器去聊天的,所以要區分開使用者和客服。

//獲取跟該使用者的歷史聊天記錄     function getHisMsgUser(users_only_md5){         if(regNull(hisHtmls)){             $.get("${ctx}/webMessage/selectWebMessageUsers.htmls",             {                 users_only_md5:users_only_md5,                 master_only_md5:'${currUserId}'             },             function(data){                 var obj = eval(data);                 pushHTML(obj.entity,"users");             });         }     }

//獲取跟該客服的歷史聊天記錄     function getHisMsgMaster(master_only_md5){         if(regNull(hisHtmls)){             $.get("${ctx}/webMessage/selectWebMessageUsers.htmls",             {                 users_only_md5:'${currUserId}',                 master_only_md5:master_only_md5             },             function(data){                 var obj = eval(data);                 pushHTML(obj.entity,"master");             });         }     }

以上2個方法的初衷,主要取決於是誰先點。使用者介面點客服聊天,和客服介面點使用者聊天。

//將獲得的聊天記錄佈局到html中     function pushHTML(list,obj){         if("error" == list){             hisHtmls = "暫無歷史聊天記錄";         }else{             list = eval(list);             for(i=list.length-1;i>=0;i--){                 if(obj != "users"){                     if(regNull(list[i].user_content)){                         //管理員傳送                         hisHtmls += "<div class=\"leftd\">"+                             "<div style=\"float:left;\">"+                             "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                             "</div>"+                             "<div class=\"speech left\" style=\"margin-right:61px;\">"+list[i].master_content+"</div>"+                             "</div>";                     }else{                         //使用者傳送                         hisHtmls += "<div class=\"rightd\">"+                             "<div style=\"float:right;\">"+                             "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                             "</div>"+                             "<div class=\"speech right\" style=\"margin-right:61px;\">"+list[i].user_content+"</div>"+                             "</div>";                     }                 }else{                     if(regNull(list[i].user_content)){                         //管理員傳送                         hisHtmls += "<div class=\"rightd\">"+                             "<div style=\"float:right;\">"+                             "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                             "</div>"+                             "<div class=\"speech right\" style=\"margin-right:61px;\">"+list[i].master_content+"</div>"+                             "</div>";                     }else{                         //使用者傳送                         hisHtmls += "<div class=\"leftd\">"+                             "<div style=\"float:left;\">"+                             "<img src=\"../img/20180917141606.png\" style=\"width:40px;height:40px;\"/>"+                             "</div>"+                             "<div class=\"speech left\" style=\"margin-right:61px;\">"+list[i].user_content+"</div>"+                             "</div>";                     }                 }             }         }         $("#liaotian").append(hisHtmls);         //該jquery是為了讓滾動條一直居底部         $('#liaotian').scrollTop($('#liaotian')[0].scrollHeight);     }

<script type="text/javascript">     /**初始化頁面所載入的資料*/     //獲取會話列表     findMsgUser(); </script>

<body>     登入使用者ID:     <input type="text" id="login" value="${currUserId}" readonly="readonly"/> 目標ID:     <input type="text" id="toUserId" value="" readonly="readonly"/>     <input type="text" id="identity" value="${identity}" readonly="readonly"/></p>     <div style="width:610px;height:500px;">         <div id="liaotian" style="border: 1px solid red;width:400px;height:500px;overflow-x: hidden;overflow-y: auto;float:left;">              </div>         <div id="newMsgUser" style="border:1px solid red;width:200px;height:500px;float:right;overflow-x: hidden;overflow-y: auto;">                      </div>     </div>     </p>     <div style="width:400px;height:50px">         <div style="width:300px;height:49px;float: left;">             <textarea id="sendMessage" rows="" cols=""                 style="width: 320px;height:49px"></textarea>         </div>         <div style="width:80px;height:49px;float:right;">             <input type="button" id="push" value="傳送"                 style="width:80px;height:49px;" onclick="privateMessage()" />         </div>     </div> </body>

<script src="${ctx}/rong/RongIMLib-2.3.3.min.js"></script> <script src="//cdn.ronghub.com/RongEmoji-2.2.4.min.js"></script> <script src="//cdn.ronghub.com/RongIMVoice-2.2.4.min.js"></script> <script src="${ctx}/rong/init.js"></script> <script src="${ctx}/js/jquery-2.1.4.min.js"></script> <script src="${ctx}/common/common.js"></script> <style type="text/css"> div.speech {     margin: 10px 0;     padding: 8px;     table-layout: fixed;     word-break: break-all;     position: relative;     background: -webkit-gradient(linear, 50% 0%, 50% 100%, from(#ffffff),         color-stop(0.1, #ececec), color-stop(0.5, #dbdbdb),         color-stop(0.9, #dcdcdc), to(#8c8c8c));     border: 1px solid #989898;     -webkit-border-radius: 8px;     -moz-border-radius: 8px;     border-radius: 8px; }

div.speech:before {     content: '';     position: absolute;     width: 0;     height: 0;     left: 15px;     top: -20px;     border: 10px solid;     border-color: transparent transparent #989898 transparent; }

div.speech:after {     content: '';     position: absolute;     width: 0;     height: 0;     left: 17px;     top: -16px;     border: 8px solid;     border-color: transparent transparent #ffffff transparent; }

div.speech.right {     box-shadow: -2px 2px 5px #CCC;     margin-right: 10px;     width: 75%;     float: right;     background: -webkit-gradient(linear, 50% 0%, 50% 100%, from(#e4ffa7),         color-stop(0.1, #bced50), color-stop(0.4, #aed943),         color-stop(0.8, #a7d143), to(#99BF40)); }

div.speech.right:before {     content: '';     position: absolute;     width: 0;     height: 0;     top: 9px;     bottom: auto;     left: auto;     right: -10px;     border-width: 9px 0 9px 10px;     border-color: transparent #989898; }

div.speech.right:after {     content: '';     position: absolute;     width: 0;     height: 0;     top: 10px;     bottom: auto;     left: auto;     right: -8px;     border-width: 8px 0 8px 9px;     border-color: transparent #bced50; }

div.speech.left {     box-shadow: 2px 2px 2px #CCCCCC;     margin-left: 10px;     width: 75%;     float: left;     background: -webkit-gradient(linear, 50% 0%, 50% 100%, from(#ffffff),         color-stop(0.1, #eae8e8), color-stop(0.4, #E3E3E3),         color-stop(0.8, #DFDFDF), to(#D9D9D9)); }

div.speech.left:before {     content: '';     position: absolute;     width: 0;     height: 0;     top: 9px;     bottom: auto;     left: -10px;     border-width: 9px 10px 9px 0;     border-color: transparent #989898; }

div.speech.left:after {     content: '';     position: absolute;     width: 0;     height: 0;     top: 10px;     bottom: auto;     left: -8px;     border-width: 8px 9px 8px 0;     border-color: transparent #eae8e8; }

.leftimg {     float: left;     margin-top: 10px; }

.rightimg {     float: right;     margin-top: 10px; }

.leftd {     clear: both;     float: left; }

.rightd {     clear: both;     float: right; }

.clear {     clear: both; }

.speed .left {     float: left; }

.speed .right {     float: right; } </style> <script type="text/javascript">     //記錄常量     var hisHtmls = "";     var toUserId = ""; </script>

頁面的樣式不是很好看,講究用用。

還有好幾個功能。目前正在開發中,等開發好了之後在更新上來。

以上的功能,目前已完成聊天,會話列表,聊天記錄等。但是聊天記錄還想還沒儲存到本地資料庫,

之後開發 聊天記錄存,未讀數量,是否線上。等功能。

等寫完在更新吧。

希望以上一點小小的功能  能與大家一起學習,一起分享。

該文件的程式碼順序我並沒有去整理,我是一段擷取一段註釋來描述該功能。如果看官需要複製程式碼,請注意下html的順序,

理論上,程式碼是沒有問題。但是需要修改一些部分引數,因為我是連資料庫的。所以你們自行建立的資料庫表字段,需要放到該頁面上來。替換了 即可正常聊天。