本项目是基于websocket的实时聊天系统,由于在项目开发中需要使用到在线聊天功能,所以学了websocket来实现了这个功能。能够实时推送聊天记录,使用Redis保存聊天记录和聊天列表。用户上线后可以查看与别人的聊天记录和最近的聊天用户。在网上搜索了很久,都没有看到合适的项目,所以自己写了一套。
效果图
消息 封装类 ChatMessage.java
/**
* {@code @Description}: 聊天信息封装
*/
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Data
public class ChatMessage {
// 接收者用户名
private String recipientUsername;
// 接收者头像地址
private String recipienHeadUrl;
// 接收者网名
private String recipienName;
// 发送者用户名
private String senderUsername;
// 发送者头像地址
private String senderName;
// 发送者网名
private String senderHeadUrl;
// 消息
private String message;
// 发送时间
private String date;
}
聊天列表封装类 ChatList.java
/**
* {@code @Description}: 描述
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ChatList {
// 用户名
private String username;
// 头像地址
private String recipienHeadUrl;
// 网名
private String screenName;
}
消息推送类 ChatWebSocketServer.java
@Component("chat")
@ServerEndpoint(value = "/chat/{recipientUsername}/{sender}")
public class ChatWebSocketServer {
private static RedisTemplate redisTemplate;
@Autowired
@Qualifier("myredis")
public void setRedisTemplate(RedisTemplate redisTemplate){
this.redisTemplate = redisTemplate;
}
private final static Logger log = LoggerFactory.getLogger(ChatWebSocketServer.class);
private Session session;
private static ConcurrentHashMap<String, ChatWebSocketServer> websocketMap = new ConcurrentHashMap<>();
private String recipientUsername;
@OnOpen
public void onOpen(Session session,@PathParam("recipientUsername") String recipientUsername,@PathParam("sender") String sender)
{
this.session = session;
websocketMap.put(recipientUsername,this); //加入map中
this.recipientUsername=recipientUsername;
try {
memor(recipientUsername,sender);
} catch (Exception e) {
log.error("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if(websocketMap.get(this.recipientUsername)!=null){
websocketMap.remove(this.recipientUsername); //从map中删除
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
// 自定义消息推送
public void sendMessage(ChatMessage chatMessage) {
if(StringUtils.isNotBlank(chatMessage.getMessage())){
ChatWebSocketServer webSocketServer = websocketMap.get(chatMessage.getRecipientUsername());
if (webSocketServer != null) {
try {
webSocketServer.sendMessage("chat:"+chatMessage.toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 将信息保存在Redis
redisTemplate.opsForList().leftPush("chat:"+chatMessage.getRecipientUsername()+":"+chatMessage.getSenderUsername(),"chat:"+JSON.toJSONString(chatMessage));
// redisTemplate.opsForList().leftPush("chat:"+chatMessage.getSenderUsername()+":"+chatMessage.getRecipientUsername(),"chat:"+JSON.toJSONString(chatMessage));
// 保存会话列表
redisTemplate.opsForSet().add("chatList:"+chatMessage.getRecipientUsername(),JSON.toJSONString(new ChatList(chatMessage.getSenderUsername(),chatMessage.getSenderHeadUrl(),chatMessage.getSenderName())));
redisTemplate.opsForSet().add("chatList:"+chatMessage.getSenderUsername(),JSON.toJSONString(new ChatList(chatMessage.getRecipientUsername(),chatMessage.getRecipienHeadUrl(),chatMessage.getRecipienName())));
// 回显消息
ChatWebSocketServer webSocket = websocketMap.get(chatMessage.getSenderUsername());
if (webSocket!=null) {
try {
webSocket.sendMessage("chat:"+chatMessage.toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
// 推送缓存信息
public void memor(String recipientUsername, String sender){
List range = redisTemplate.opsForList().range("chat:"+recipientUsername+":"+sender, 0, -1);
List range1 = redisTemplate.opsForList().range("chat:"+sender+":"+recipientUsername, 0, -1);
range.addAll(range1);
if (range!=null&&range.size()>0) {
List<ChatMessage>chatMessageList = new ArrayList<>();
Iterator iterator = range.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
ChatMessage chatMessage = JSON.parseObject(String.valueOf(next).replace("chat:", ""),ChatMessage.class);
chatMessageList.add(chatMessage);
}
// 按时间排序
chatMessageList.sort((ChatMessage c1,ChatMessage c2)->{
return c1.getDate().compareTo(c2.getDate());
});
// 发送
Iterator<ChatMessage> iterator1 = chatMessageList.iterator();
while (iterator1.hasNext()) {
try {
ChatWebSocketServer webSocketServer = websocketMap.get(recipientUsername);
if (webSocketServer != null) {
ChatMessage next = iterator1.next();
webSocketServer.sendMessage("chat:"+String.valueOf(next));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}