商城项目-客服功能

最近一段时间我们在完善项目,我们在写的项目是一个商城项目。上次考核的时候考虑到进度问题,客服功能只做了一半,这次项目我对它进行了完善。

客服功能因为要实现即时通信,我主要是基于websocket实现的,它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。因为是第一次去写类似的功能,所以在实现过程中遇到了很多问题。

离线消息

因为客服和用户并不是一直在线的,但是在用户离线的时候别人向他发送的消息他也应该接收到。所以在发送信息的时候我加了一个判断,当用户离线的时候将接收到的信息存到redis里面,在用户连接websocket的查询redis判断用户是否有离线的信息,如果有,在登录的时候一起发送过来。

发送消息

Session userSession = map.get("user:" + userId);
if (userSession != null) {
            userSession.getAsyncRemote().sendText(msgJson);
        }
        {
            String userKey = "msg@" + message.getUserId() + ":offLine";
            redisUtil.lLeftPush(userKey, msgJson);
        }

登录时判断

String chatKey= "msg@" +userId + ":offLine";
while(redisUtil.hasKey(chatKey)&&redisUtil.lLen(chatKey)!=0){
    String msg = redisUtil.lRightPop(chatKey);
    session.getAsyncRemote().sendText(msg);
}

角色绑定:

因为店铺与客服是一对多的关系,一个店铺里面可以有多个客服在线,当用户与客服进行聊天时,要保证一个客服和一个用户进行聊天,否则不符合逻辑。所以写项目的时候我给聊天列表设置了一个状态,客服可以查看所有的聊天列表,然后选择性进行接取业务,当一个聊天列表被一个客服接取后,其他客服不能进入这个聊天列表与用户进行聊天。

因为店铺与客服的一对多的关系,所以在用户反馈的时候该店铺的所有客服都可以看到聊天记录。我在用户给店铺发送信息的时候,先查询店铺里面有哪些客服,再查询客服的session,遍历给客服发送消息。

@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketUtil {

    private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();

    private Session session;

    private String key;

    private static Map map = new HashMap<>();
//    private static Map> storeMap=new HashMap<>();

    private static RedisUtil redisUtil;

    private static ChatDao chatDao;

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil){
        WebSocketUtil.redisUtil = redisUtil;
    }

    @Autowired
    public void setChatDao(ChatDao chatDao){
        WebSocketUtil.chatDao = chatDao;
    }

    /**
     * 连接建立成功调用的方法
     */

    @OnOpen
    public void onOpen(Session session,@PathParam("userId")Integer userId) {
        this.session = session;
        this.key="user:"+userId;
        map.put(key, session);
        String chatKey= "msg@" +userId + ":offLine";
        while(redisUtil.hasKey(chatKey)&&redisUtil.lLen(chatKey)!=0){
            String msg = redisUtil.lRightPop(chatKey);
            session.getAsyncRemote().sendText(msg);
        }
        webSocketSet.add(this);
        //加入set中
        System.out.println("有新连接加入:"+userId+",当前在线人数为" + webSocketSet.size());
        this.session.getAsyncRemote().sendText("恭喜"+userId+"成功连接上WebSocket(其频道号:"+userId+")-->当前在线人数为:"+webSocketSet.size());
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        System.out.println("有一连接关闭!当前在线人数为" + webSocketSet.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message,@PathParam("id") String id) {
    }
    /**
     * 发生错误时调用
     *
     */
    @OnError
    public void onError( Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }
    /**
     * 群发自定义消息
     * */
    public  void broadcast(String message){
        for (WebSocketUtil item : webSocketSet) {
            //同步异步说明参考:http://blog.csdn.net/who_is_xiaoming/article/details/53287691
            //this.session.getBasicRemote().sendText(message);
            item.session.getAsyncRemote().sendText(message);//异步发送消息.
        }
    }

    public void sendMessage(Integer userId, Integer storeId, Message message) {
        Session userSession = map.get("user:" + userId);
        String msgJson = JSON.toJSONString(message);
        String userListKey = "userList:" + userId + "@chat";
        String storeListKey = "storeList:" + storeId + "@chat";
        int userList = (int) Double.parseDouble(redisUtil.zScore(userListKey, storeId + "") + "");
        int storeList = (int) Double.parseDouble(redisUtil.zScore(storeListKey, userId + "") + "");
        //发送给用户.
        if (userSession != null) {
            userSession.getAsyncRemote().sendText(msgJson);
        }
        {
            String userKey = "msg@" + message.getUserId() + ":offLine";
            redisUtil.lLeftPush(userKey, msgJson);
        }
//        List list = storeMap.get(storeId);
        String userKey = "msg@" + userList + ":message";
        redisUtil.lLeftPush(userKey, msgJson);
        String storeKey = "msg@" + storeList + ":message";
        redisUtil.lLeftPush(storeKey, msgJson);
        Integer chatListId;
        if (message.getMessageStatus() == 0) {
            chatListId = storeId;
        } else {
            chatListId = userId;
        }
        String numKey = "chat@No:" + chatListId + "num";
        if (redisUtil.hasKey(numKey)) {
            redisUtil.incrBy(numKey, 1);
        } else {
            redisUtil.set(numKey, "1");
        }
        List list=null;
        if(redisUtil.hasKey("chatService:"+storeId)){
            Set strings = redisUtil.setMembers("chatService:" + storeId);
             list = strings.stream().map(Integer::parseInt).collect(Collectors.toList());
        }
        if (list != null) {
            for (Integer id :
                    list) {
                Session chatSession = map.get("user:" + id);
                String chatKey;
                if (chatSession != null) {
                    chatSession.getAsyncRemote().sendText(msgJson);
                } else {
                    chatKey = "msg@" + message.getUserId() + ":offLine";
                    redisUtil.lLeftPush(chatKey, msgJson);
                }
            }
        }
    }

你可能感兴趣的:(java,数据库,websocket)