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>

  

配置类

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.jeecms.websocket.dto;

import com.jeecms.core.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

<!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) {

        }

        $('#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('');
        }
    }

    function sj() {
        return parseInt(Math.random() * 10)
    }


</script>
</body>
</html>

  

管理员消息列表页

member_admin_chat_list.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) {

        }

        $('#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('');
        }
    }

    function sj() {
        return parseInt(Math.random() * 10)
    }


</script>
</body>
</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) {

        }

        $('#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('');
        }
    }

    function sj() {
        return parseInt(Math.random() * 10)
    }


</script>
</body>
</html>

  

猜你喜欢

转载自www.cnblogs.com/pxblog/p/12596111.html
今日推荐