> 文章列表 > 商城项目-客服功能

商城项目-客服功能

商城项目-客服功能

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

客服功能因为要实现即时通信,我主要是基于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<WebSocketUtil> webSocketSet = new CopyOnWriteArraySet<WebSocketUtil>();private Session session;private String key;private static Map<String,Session> map = new HashMap<>();
//    private static Map<Integer, List<Integer>> storeMap=new HashMap<>();private static RedisUtil redisUtil;private static ChatDao chatDao;@Autowiredpublic void setRedisUtil(RedisUtil redisUtil){WebSocketUtil.redisUtil = redisUtil;}@Autowiredpublic void setChatDao(ChatDao chatDao){WebSocketUtil.chatDao = chatDao;}/* 连接建立成功调用的方法*/@OnOpenpublic 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());}/* 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);  //从set中删除System.out.println("有一连接关闭!当前在线人数为" + webSocketSet.size());}/* 收到客户端消息后调用的方法 @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message,@PathParam("id") String id) {}/* 发生错误时调用/@OnErrorpublic 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<Integer> 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<Integer> list=null;if(redisUtil.hasKey("chatService:"+storeId)){Set<String> 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);}}}}