融云api开发Java后台客服聊天功能(一)

以下所有内容均为本人自己开发总结的经验,如有雷同,不胜荣幸!

最近公司在做一款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的顺序,

理论上,代码是没有问题。但是需要修改一些部分参数,因为我是连数据库的。所以你们自行创建的数据库表字段,需要放到该页面上来。替换了 即可正常聊天。

猜你喜欢

转载自blog.csdn.net/qq_35243979/article/details/82910225