最近一段时间我们在完善项目,我们在写的项目是一个商城项目。上次考核的时候考虑到进度问题,客服功能只做了一半,这次项目我对它进行了完善。
客服功能因为要实现即时通信,我主要是基于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;
@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<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);
}
}
}
}
28万+

被折叠的 条评论
为什么被折叠?



