进阶版代码在原始版基础上改的,这里就不在发整个项目了
没有看过原始版的可以先去看下,把项目下载下来,网盘和博客都有https://blog.csdn.net/qq_45777315/article/details/107669617
我还是比较喜欢先奉上效果,看是不是你们想要的
根据用户uid建立通信,实现永久唯一通信id,及时用户下线重连还是可以继续通信
最细讲解,代码+注释+数据库表
表结构 user 用户表和 chatting 聊天记录表
用户表
聊天记录表
代码
两个新表的实体类需要创建,具体的setget不要忘了,也可以直接用lombok
新建一个UserService,进行连接数据库操作
代码上的静态调用的注释需要注意,因为不是静态方法可能在spring运行时,没有及时注入
静态调用方法https://blog.csdn.net/qq_45777315/article/details/107369039
import org.springframework.stereotype.Service;
import zyh.dd.entity.User;
import zyh.dd.mapper.UserMapper;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author: 云
* @version: 1.0
*/
@Service
public class UserService {
//调用mapper
@Resource
UserMapper userMapper;
//静态调用
public static UserService userService;
@PostConstruct
public void init(){
userService = this;
}
/**
* 聊天
*/
//查询用户信息 sql select * from user where uid=#{uid}
public static User selectUser(int uid){
return userService.userMapper.selectUser(uid);
}
//添加消息记录 sql INSERT INTO chatting(fid,tid,message,`type`,stime,`status`)
public static int instUser(int fid,int tid,String message,String type,int status){
return userService.userMapper.instUser(fid,tid,message,type,status);
}
}
剩下的就全是 MyWebScoket 修改了
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import zyh.dd.entity.SocketEntity;
import zyh.dd.entity.User;
import zyh.dd.service.UserService;
import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* zyh
* 2020/07/29
*/
/**
* 虽然@component默认是单例模式的,但在spring boot 中还是会为每一个webscoket连接初始化一个bean,所以这里使用一个静态的set保存spring boot创建的bean--MyWebscoket
*/
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class MyWebScoket {
//用户的Service层 数据库操作
@Autowired
UserService userService;
public static MyWebScoket myWebScoket;
@PostConstruct
public void init() {
myWebScoket = this;
}
//用来存储每个客户端对应的MyWebScoket对象
private static CopyOnWriteArraySet<MyWebScoket> webScoketset = new CopyOnWriteArraySet<MyWebScoket>();
//用来记录sessionid和session之间的绑定关系。
private static Map<String, Session> map = new HashMap<String, Session>();
private Session session;//当前会话的session
private String name;
private String userId;
User user = null;//用户实体类
/**
* 成功建立连接调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
//查询 发送人用户信息
user = UserService.selectUser(Integer.parseInt(userId));
//存储信息
this.session = session;
//取用户的唯一uid 强转下类型
this.userId = String.valueOf(user.getUid());
//取用户的名字
this.name = user.getUsername();
//用户的唯一uid 和
map.put(String.valueOf(user.getUid()), session);
webScoketset.add(this);//加入set中
this.session.getAsyncRemote().sendText(user.getUsername() + "上线了" + "我的频道号是" + user.getUid() + ",当前连接人数为:" + webScoketset.size());
}
/**
* 连接关闭调用的方法
*
* @param session
*/
@OnClose
public void onClose(Session session) {
webScoketset.remove(this);//加入set中
Boolean aa = map.remove(String.valueOf(user.getUid()), session);
}
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 收到客户消息后调用的方法
*
* @param session
*/
@OnMessage
public void OnMessage(String message, Session session) throws IOException {
//message不是普通的string,而是我们定义的SocketEntity,json字符串
SocketEntity socketEntity = new ObjectMapper().readValue(message, SocketEntity.class);
//解析json
JSONObject jsonObject = JSONObject.fromObject(message);
//单聊
if (socketEntity.getType() == 1) {
//单聊:需要找到发送者和接收者即可
socketEntity.setFromUser(String.valueOf(user.getUid()));//发送者
//确定发送人
Session fromsession = map.get(socketEntity.getFromUser());
//确定受信人
Session tosession = map.get(socketEntity.getToUser());
//通道保持畅通
if (tosession != null) {
// 存储聊天记录 已读 存进聊天记录表
UserService.instUser(user.getUid(), Integer.parseInt(socketEntity.getToUser()),jsonObject.get("message").toString(),jsonObject.get("type").toString(),1);
fromsession.getAsyncRemote().sendText(name + ":" + socketEntity.getMessage());//发送消息
tosession.getAsyncRemote().sendText(name + ":" + socketEntity.getMessage());//发送消息
} else {
// 存储聊天记录 未读 存进聊天记录表
UserService.instUser(user.getUid(), Integer.parseInt(socketEntity.getToUser()),jsonObject.get("message").toString(),jsonObject.get("type").toString(),0);
fromsession.getAsyncRemote().sendText("系统消息:对方不在线或者您输入的频道号有误");//发送消息
}
} else {
// 广播群发给每一个客户端
broadcast(socketEntity, name);
}
}
/**
* 群发消息
*
* @param socketEntity
*/
private void broadcast(SocketEntity socketEntity, String name) {
for (MyWebScoket myWebScoket : webScoketset) {
//发送消息
myWebScoket.session.getAsyncRemote().sendText(name + ":" + socketEntity.getMessage());
}
}
}