SpringBoot+WebSocket实现简单的一对一web聊天

SpringBoot WebSocket 客服系统
本文介绍如何使用SpringBoot和WebSocket实现客服系统的前后端分离,包括后台代码配置和前端连接、消息收发的实现。
该文章已生成可运行项目,

前言

最近项目中要实现客服系统,其实网上有很多的服务商提供这种接口,但最终决定使用SpringBoot+WebSocket的方式实现。
下面我的项目的结构是使用SpringBoot+Nginx实现的前后端分离的,但是这个不重要,这里只是提出来。
SpringBoot和Nginx我就不在这里多说了,网上有很多教程。过几天我也会专门写几篇文章记录一下。

1. 后台代码

在pom.xml中添加spring-boot-starter-websocket

<!--WebSocket-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

添加配置,先在src\main\resources\application.yml中添加:

server:
  port: 8085
  servlet:
    context-path: /yblog
  max-http-header-size: 8192

最主要是最后一行,如果不加的话可能导致无法进行访问。
在启动类或者新建一个配置类,主要一个Bean,用来启动服务是也启动WebSocket服务:

//WebSocket
@Bean
public ServerEndpointExporter serverEndpointExporter() {
   
   
    return new ServerEndpointExporter();
}

注意:这个类必须有@Configuration注解
然后新建一个model来封装进行对话的对象,我一直在纠结到底要不要这个类,最后决定要,这样可以避免很多麻烦。

public class SocketUserInfo {
   
   
    //用户sessionId
    private String sessionId;

    //用户session
    private Session session;

    //目标用户sessionid
    private String targetSessionId;

    //用户角色
    private String userRole;

    public String getUserRole() {
   
   
        return userRole;
    }

    public void setUserRole(String userRole) {
   
   
        this.userRole = userRole;
    }

    public String getSessionId() {
   
   
        return sessionId;
    }

    public void setSessionId(String sessionId) {
   
   
        this.sessionId = sessionId;
    }

    public Session getSession() {
   
   
        return session;
    }

    public void setSession(Session session) {
   
   
        this.session = session;
    }

    public String getTargetSessionId() {
   
   
        return targetSessionId;
    }

    public void setTargetSessionId(String targetSessionId) {
   
   
        this.targetSessionId = targetSessionId;
    }
}

新建一个类来管理Socket会话,这个类我也不清楚该是Service还是Controller,最后我把它作为了Controller,因为我觉得它更像一个Controller。它主要完成如下场景业务:

  1. 用户连接上线:如果是一个客服上线,就保存一个客服信息,同时去查找有没有再排队中的用户,如果有就给他们俩建立会话关系;如果是一个用户上线,先建立保存用户信息,再去查找有没有空闲客服,如果有就建立会话关系,如果没有就告诉他系统繁忙,让他进入等待状态。
  2. 用户下线:如果是客户下线,就删除客服信息,为了方便,我直接让用户刷新页面重新匹配客服,其实这样做不是很好;如果是用户下线,就删除用户信息,让空闲下来的客服和排队中的用户建立会话关系
  3. 发送消息:如果是用户发的消息,就将消息推送给相应客服;如果是客服发的消息,就推送给相应用户。
//参数role判断用户角色0是客服,1是用户
@ServerEndpoint(value = "/websocket/{role}")
@Component
public class SocketController {
   
   

    //用本地线程保存session
    private static ThreadLocal<Session> sessions = new ThreadLocal<Session>();
    //保存所有连接上的用户的session
    private static Map<String, SocketUserInfo> userSessionMap = new ConcurrentHashMap<>();
    //保存在线客服的session
    private static Map<String, SocketUserInfo> serverSessionMap = new ConcurrentHashMap<>();

    //连接
    @OnOpen
    public void onOpen(Session session, @PathParam(value="role") Integer role) {
   
   

        //默认返回错误状态
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("state", "error");

        //保证各个线程里的变量相对独立于其他线程内的变量
        sessions.set(session);

        //客服上线
        if (role.equals(0)) {
   
   

            //创建一个在线客服信息
            SocketUserInfo serverInfo = new SocketUserInfo();
            serverInfo.setSessionId(session.getId());
            serverInfo.setSession(session);
            serverInfo.setUserRole("客服");

            //告诉客服连接成功
            resultMap.put("state", "success");

            //去查询是否有排队中的用户
            //如果存在排队的用户,就将用户和客服绑定
            if (findLineUser() != null){
   
   
                SocketUserInfo userInfo = userSessionMap.get(findLineUser());
                //将用户绑定到客服
                serverInfo.setTargetSessionId(userInfo.getSessionId());
                //将客服绑定到用户
                userInfo.setTargetSessionId(serverInfo.getSessionId());
                userSessionMap.put(userInfo.getSessionId(), userInfo);
                System.out.println("客户"+ serverInfo.getSessionId() + "正在为用户" + userInfo.getSessionId()+"服务");

                Map<String, String> result = new HashMap<>();
                //客服显示用户信息
                result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务!");
                sendMsg(serverInfo.getSession(), JSON.toJSONString(result));
                //告诉用户有客服为他服务
                result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务!");
本文章已经生成可运行项目
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值