package com.bim.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bim.common.utils.StringUtil;
import com.bim.dao.redis.RedisClientTemplate;
import com.bim.service.ChatService;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @ClassName: WebSocket
* @Author: hxw
* @Date: 2019/5/22
* @Time: 11:44
**/
@Component
@ServerEndpoint(value = "/websocket/{username}",configurator=MyEndpointConfigure.class)
@SuppressWarnings("all")
public class WebSocket{
@Autowired
private RedisClientTemplate redisClientTemplate;
@Autowired
private ChatService chatService;
public static final String WEBSOCKER_CLIENT = "webSocket.";
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 在线人数
*/
private static int onlineNumber = 0;
/**
* 会话
*/
private Session session;
/**
* 用户名称
*/
private String username;
private static Map<String,WebSocket> clients = new ConcurrentHashMap<>();
private static Map<String,String> clientsUser = new ConcurrentHashMap<>();
public WebSocket(){
}
public WebSocket(Session session,String username){
this.session = session;
this.username = username;
}
/**
* 建立连接
* @param session
*/
@OnOpen
public void onOpen(@PathParam("username") String username, Session session)
{
onlineNumber++; //在线人数+1
WebSocket webSocket = new WebSocket(session,username);
if(clientsUser != null && clientsUser.size() > 0){
Set<String> setUser = clientsUser.keySet();//获取所有sessionId
for(String sessionId : setUser){
String name = clientsUser.get(sessionId);
if(username.equals(name)){//如果存在则删除上一个session
Map<String,Object> map1 = Maps.newHashMap();
map1.put("messageType",2);
map1.put("messageInfo","被踢");
clientsUser.remove(sessionId);
WebSocket socket = clients.get(name);
sendMessage(JSON.toJSONString(map1),socket,name);
}
}
}
//把自己的信息加入在线名单
clients.put(username,webSocket);
clientsUser.put(session.getId(),username);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4普通消息
//先给所有人发送上线通知
Map<String,Object> map1 = Maps.newHashMap();
map1.put("messageType",1);
map1.put("username",username);
Map<String,Object> mapUser = chatService.queryUserInfoByChatId(username);//通过聊天id查询业务系统标识
sendMessageAll(JSON.toJSONString(map1),mapUser.get("appId").toString(),username);
//获取自己的离线消息
long size = redisClientTemplate.llen(username);//获取队列长度
for(int i = 0;i<size;i++){
String message = redisClientTemplate.rpop(username,String.class);
if(StringUtil.isNotEmpty(message)){
sendMessageTo(message,username);
}
}
//获取排除自己的在线名单
Set<String> set = clients.keySet();
Map<String ,Object> map2 = new HashMap<>();
map2.put("messageType",3);
map2.put("onlineUsers",set);
sendMessageTo(JSON.toJSONString(map2),username);
} catch (Exception e){
e.printStackTrace();
logger.info(username+"上线的时候通知所有人发生了错误");
}
}
@OnError
public void onError(Session session, Throwable error) {
logger.info("服务端发生了错误"+error.getMessage());
}
/**
* 连接关闭
*/
@OnClose
public void onClose(Session session)
{
onlineNumber--;//在线人数-1
//删除自己
String name = clientsUser.get(session.getId());//通过sessionId获取用户聊天id
if(StringUtil.isNotEmpty(name)){
clients.remove(name);//通过聊天id删除session
clientsUser.remove(session.getId());//通过sessionId删除用户聊天id
//messageType 1代表上线 2代表下线 3代表在线名单 4普通消息
//先给所有人发送下线通知
Map<String,Object> map1 = Maps.newHashMap();
map1.put("messageType",2);
map1.put("onlineUsers",clients.keySet());
map1.put("username",name);
Map<String,Object> mapUser = chatService.queryUserInfoByChatId(name);//通过聊天id查询业务系统标识
sendMessageAll(JSON.toJSONString(map1),mapUser.get("appId").toString(),name);
}
}
/**
* 收到客户端的消息
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session)
{
JSONObject jsonObject = JSON.parseObject(message);
String textMessage = jsonObject.getString("message");//消息内容
String fromusername = jsonObject.getString("username");//发送者
String tousername = jsonObject.getString("to"); //发送给谁(群组id或者用户id)
Integer channelType = jsonObject.getInteger("channelType");//会话类型0 系统消息 1群组消息 2个人消息
String appId = jsonObject.getString("appId");
//如果不是发给所有,那么就发给某一个人
//messageType 1代表上线 2代表下线 3代表在线名单 4普通消息
Map<String,Object> map1 = Maps.newHashMap();
map1.put("messageType",4);
map1.put("textMessage",textMessage);
map1.put("fromusername",fromusername);
map1.put("sendTime",StringUtil.getNowDate("yyyy-MM-dd HH:mm:ss"));
map1.put("channelType",channelType);
if( 0 == channelType){ //系统消息
map1.put("tousername","所有人");
sendMessageAll(JSON.toJSONString(map1),appId,fromusername);
}else if(1 == channelType){ //群组消息
map1.put("tousername",tousername);
sendMessageGroup(JSON.toJSONString(map1),tousername,fromusername);
} else if(2 == channelType) { //个人消息
map1.put("tousername",tousername);
sendMessageTo(JSON.toJSONString(map1),tousername);
}
}
/**
* 点对点聊天
* @param message 消息内容
* @param toUserName 发送给谁
* @throws IOException
*/
public void sendMessageTo(String message, String toUserName){
WebSocket item= clients.get(toUserName);
sendMessage(message,item,toUserName);
}
/**
* 群聊
* @param message 消息内容
* @param groupId 群组id
* @param name 发送者聊天id
*/
public void sendMessageGroup(String message,String groupId,String name){
//通过群组id查询到群组所有人
List<Map<String,Object>> listMap = chatService.queryUserByGroupId(groupId);
if(listMap != null && listMap.size() > 0){
fo