websocket
用户
用户这是为了区分发送的消息是给谁的和谁发的
实体类
package com.nice.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ImUser {
/**
* 因为使用的是uuid所以使用string
**/
private String id;
private String username;
private String password;
private LocalDateTime createTime;
}
注册
Controller
@PostMapping("register")
/**
* 注册
*/
public Res register(@RequestBody ImUser imUser) {
return imService.register(imUser);
}
service
public Res register(ImUser imUser) {
ImUser allByUsername = imUserMapper.getAllByUsername(imUser.getUsername());
if (allByUsername != null) {
return Res.failure("用户创建失败!");
}
if (StringUtils.isEmpty(imUser.getId())) {
imUser.setId(IdUtil.simpleUUID());
imUser.setCreateTime(LocalDateTime.now());
imUser.setStatus(ImUser.OFFLINE);
}
int insert1 = this.imUserMapper.insert(imUser);
if (insert1 != 1) {
return Res.failure("用户创建失败!");
}
return Res.ok(imUser, imUser.getUsername() + " 注册成功!");
}
登录
Controller
/**
* 登录
*
* @param imUser
* @return
*/
@PostMapping("login")
public Res login(@RequestBody ImUser imUser) {
return imService.getUser(imUser);
}
service
public Res<ImUser> getUser(ImUser imUser) {
ImUser allByUsernameAndPassword = imUserMapper.getAllByUsernameAndPassword(imUser.getUsername(), imUser.getPassword());
if (allByUsernameAndPassword == null) {
return Res.failure("账号或密码错误");
}
return Res.ok(allByUsernameAndPassword, "登录成功");
}
获取用户列表
因为不是正式的就没有出现用户添加好友的部分就只有发送消息的,所以就需要获取用户列表
Controller
@GetMapping("getUser")
public Res getUser() {
return imService.getUser();
}
Service
public Res getUser() {
List<ImUser> all = imUserMapper.getAll();
return Res.ok(all, "用户列表");
}
WebSocketServer
核心代码
获取连接
package com.nice.websocket;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nice.entity.ImGroupUser;
import com.nice.entity.ImMessage;
import com.nice.entity.ImOfflineMessage;
import com.nice.entity.ImUser;
import com.nice.mapper.ImGroupUserMapper;
import com.nice.mapper.ImMessageMapper;
import com.nice.mapper.ImOfflineMessageMapper;
import com.nice.mapper.ImUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
@ServerEndpoint("/im/{id}")
@Component
@Slf4j
public class WebSocketServer {
private static Integer ONLINE = 0;
public static ConcurrentHashMap<String, WebSocketServer> WEBSOCKET_MAP = new ConcurrentHashMap<>();
private Session session;
private String userId;
private static ImGroupUserMapper imGroupUserMapper;
private static ImMessageMapper imMessageMapper;
private static ImUserMapper imUserMapper;
private static ImOfflineMessageMapper imOfflineMessageMapper;
public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {
WebSocketServer.imGroupUserMapper = applicationContext.getBean(ImGroupUserMapper.class);
WebSocketServer.imMessageMapper = applicationContext.getBean(ImMessageMapper.class);
WebSocketServer.imUserMapper = applicationContext.getBean(ImUserMapper.class);
WebSocketServer.imOfflineMessageMapper = applicationContext.getBean(ImOfflineMessageMapper.class);
}
/**
* 建立连接
*
* @param session
* @param id
*/
@OnOpen
public void onOpen(Session session, @PathParam("id") String id) {
this.userId = id;
this.session = session;
WebSocketServer webSocketServer = WEBSOCKET_MAP.get(this.userId);
if (webSocketServer == null) {
WEBSOCKET_MAP.put(this.userId, this);
} else {
ImMessage imMessage = new ImMessage();
imMessage.setMsgType(ImMessage.TYPE_SYSTEM);
imMessage.setContent(ImMessage.MSG_TYPE_FORCE_LEAVE);
imMessage.setToId(this.userId);
imMessage.setSendTime(LocalDateTime.now());
// 使用发送消息
Future<Void> future = WebSocketServer.send2One(this.userId, imMessage);
if (future != null && future.isDone()) {
WEBSOCKET_MAP.put(this.userId, this);
}
}
sendNoMessage(id);
ImUser imUser = new ImUser();
imUser.setId(id);
imUser.setStatus(ImUser.ONLINE);
log.info(imUser.getId() + "上线了");
imUserMapper.updateById(imUser);
}
}
@ServerEndpoint(“/im/{id}”)这个是websocket的注解
发送消息
未在线的是发不过去的,所以将未发送的消息存储起来
/**
* 发送消息
*
* @param data
*/
@OnMessage
public void onMessage(String data) {
log.info("消息{}", data);
ImMessage imMessage = JSON.parseObject(data, ImMessage.class);
imMessage.setSendTime(LocalDateTime.now());
imMessage.setId(IdUtil.simpleUUID());
imMessageMapper.insert(imMessage);
WebSocketServer.send2One(imMessage.getToId(), imMessage);
}
/**
* 发送消息
*
* @param userId
* @param imMessage
* @return
*/
public static Future<Void> send2One(String userId, ImMessage imMessage) {
WebSocketServer webSocketServer = WEBSOCKET_MAP.get(userId);
// 判断用户是否在线不在线则在上线后发送消息给用户
if (webSocketServer == null) {
ImOfflineMessage imOfflineMessage = new ImOfflineMessage();
imOfflineMessage.setId(IdUtil.simpleUUID());
imOfflineMessage.setUserId(imMessage.getToId());
imOfflineMessage.setMessageId(imMessage.getId());
imOfflineMessage.setIsSend(ImOfflineMessage.UNREAD);
imOfflineMessageMapper.insert(imOfflineMessage);
return null;
} else {
return webSocketServer.session.getAsyncRemote().sendText(JSON.toJSONString(imMessage));
}
}
处理未发送的消息
当用户上线后进行发送未发送的消息
/**
* 发送未发送消息
*
* @param userId
*/
public void sendNoMessage(String userId) {
List<ImOfflineMessage> imOfflineMessages = imOfflineMessageMapper.selectList(new LambdaQueryWrapper<ImOfflineMessage>().eq(ImOfflineMessage::getUserId, userId).eq(ImOfflineMessage::getIsSend, ImOfflineMessage.UNREAD));
for (ImOfflineMessage imOffline : imOfflineMessages) {
ImMessage imMessage = imMessageMapper.selectById(imOffline.getMessageId());
log.info("{}--消息{}", userId, imMessage);
imOffline.setIsSend(ImOfflineMessage.SENT);
imOfflineMessageMapper.updateById(imOffline);
send2One(userId, imMessage);
}
}
关闭连接
/**
* 关闭连接
*/
@OnClose
public void onClose() {
WEBSOCKET_MAP.remove(this.userId);
// 用户下线
ImUser imUser = imUserMapper.selectById(this.userId);
imUser.setStatus(ImUser.OFFLINE);
log.info(imUser.getUsername() + "下线了");
imUserMapper.updateById(imUser);
// 发送用户下线广播
ImMessage imMessage = new ImMessage();
imMessage.setFromId(imUser.getId());
imMessage.setFromName(imUser.getUsername());
imMessage.setType(ImMessage.TYPE_SYSTEM);
imMessage.setMsgType(ImMessage.MSG_TYPE_LEAVE);
imMessage.setContent(imUser.getUsername() + " 离开了");
imMessage.setSendTime(LocalDateTime.now());
LambdaQueryWrapper<ImGroupUser> query = new LambdaQueryWrapper();
query.eq(ImGroupUser::getUserId, this.userId);
List<ImGroupUser> imGroupUsers = imGroupUserMapper.selectList(query);
if (CollUtil.isNotEmpty(imGroupUsers)) {
for (ImGroupUser imGroupUser : imGroupUsers) {
imMessage.setToId(imGroupUser.getGroupId());
WebSocketServer.send2Group(this.getUserByGroupId(imGroupUser.getGroupId()), imMessage);
}
}
}
Postman测试ws
切换请求方式http切换成ws