制作背景为老师和学生交流,但是交流的范围为班级的某一个任课老师和本班的学生,执行的操作是老师向学生询问是否听懂了,学生进行回复。这是一个项目中的一部分,主要用于线上教学时的学生回应。
WebSocketRoom配置类
@Slf4j
public class WebSocketRoom {
public static Map<String, ConcurrentHashMap<String, Session>> rooms = new ConcurrentHashMap();
public static void close(String roomId,String sessionId) throws IOException {//sessionId就是account
log.info("{}从{}房间断开了链接",sessionId,roomId);
Map<String, Session> sessions=rooms.get(roomId);//获取当前房间的信息
for (String account : sessions.keySet()) {
Session session = sessions.get(account);//获取当前hashmap中的value值
if (session.getId().equals(sessionId)) {
sessions.remove(account);//如果当前池中有key对应的value值,则进行清除操作
break;
}
}
}
public static void sendMessage(String roomId,String account, String message) {//一对一发送,用于学生回复老师是否听懂
log.info("在房间{}中,{}发送消息{}",roomId,account,message);
rooms.get(roomId).get(roomId).getAsyncRemote().sendText(message);//获取需要发送的用户,并发送信息
}
public static void sendMessage(String roomId,String message) {//对当前所有的链接进行发送,用于老师向学生提问是否听懂
for (String sessionId : rooms.get(roomId).keySet()) {
log.info("已经向"+sessionId+"发送消息"+message);
rooms.get(roomId).get(sessionId).getAsyncRemote().sendText(message);//获取需要发送的用户,并发送信息
}
}
public static String sendMessage(String roomId) {//获取当前房间所有的用户
String allMember="";
for (String account : rooms.get(roomId).keySet()) {
if(allMember=="")
allMember=account;
else
allMember=allMember+","+account;//获取用户账号并拼接
}
return allMember;
}
}
其实和第一个wesocket配置类相似,只不过是在操作前先要找到对应房间号的map,之后再进行其他的操作,配备上房间内的群发和一对一发送。这里面需要注意ConcurrentHashMap要声明为静态变量。每个用户的发送信息的前提是知道接收者的session地址是什么,这就需要一个公共的存储区域,方便去寻找。所以声明为static类型(静态变量也称为类变量,属于类对象所有,位于方法区,为所有对象共享,共享一份内存,一旦值被修改,则其他对象均对修改可见)这要就可以保证能够拿到正确的数据了,同时方法也声明为static类型,用于操作链接池。
这里面定了不同入参的sendMessage用于群发和一对一发送
WebSocketServiceImp类的编写
@Slf4j
@Service
@Component
@ServerEndpoint("/webSocketRoom/{account}/{roomId}")
@DependsOn("springContextUtils")
public class WebSocketRoomServiceImpl {
/** 记录当前在线连接数 */
// private static AtomicInteger onlineCount = new AtomicInteger(0);
private Session session;
//为这个变量添加set方法
public static void setApplicationContext(ApplicationContext applicationContext) {
WebSocketRoomServiceImpl.applicationContext = applicationContext;
}
@OnOpen
public void onOpen(Session session, @PathParam("account") String account,@PathParam("roomId") String roomId) throws IOException {
if(WebSocketRoom.rooms.get(roomId)==null&&account.equals(roomId)){//如果房间号和账号时相同,说明是老师账号,则创建房间
ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();//创建新的连接池
WebSocketRoom.rooms.put(roomId,sessions);
}else if(WebSocketRoom.rooms.get(roomId)==null&&!account.equals(roomId))//如果房间号不存在且账号和房间号不一致则关闭连接
{
log.info("{}加入的{}房间不存在",account,roomId);
this.onClose(session,account,roomId);
return;
}
WebSocketRoom.rooms.get(roomId).put(account, session);//加入用户到连接池中
log.info("有账号加入:{},当前在线人数为:{}", account, WebSocketRoom.rooms.get(roomId).size());
// String nowNumber=roomId+"当前在线人数"+WebSocketRoom.rooms.get(roomId).size();
// String nowNumber= WebSocketRoom.sendMessage(roomId);
log.info("当前所有的用户:"+WebSocketRoom.sendMessage(roomId));
this.onMessage(roomId,account,WebSocketRoom.sendMessage(roomId));//发送当前加入的账号
}
@OnClose
public void onClose(Session session,@PathParam("account") String account,@PathParam("roomId") String roomId) throws IOException {
if(WebSocketRoom.rooms.get(roomId)==null){
session.close();//关闭当前用户链接
return;
}
log.info("有账号退出:{},当前在线人数为:{}", account, WebSocketRoom.rooms.get(roomId).size());
WebSocketRoom.close(roomId,session.getId());//从链接池中删除用户信息
session.close();//关闭当前用户链接
log.info("当前所有的用户:"+WebSocketRoom.sendMessage(roomId));
this.onMessage(roomId,account,WebSocketRoom.sendMessage(roomId));//发送当前加入的账号
if(WebSocketRoom.rooms.get(roomId).size()==0)
{
log.info("{}房间已经销毁",roomId);
WebSocketRoom.rooms.remove(roomId);
}
}
@OnError
public void onError(Throwable t) throws Throwable {
log.error("webScoketRoom报错: " + t.toString());
}
@OnMessage
public void onMessage(@PathParam("roomId") String roomId,@PathParam("account") String account,String message){
message=account+":"+message;
if(roomId.equals(account)){
log.info("{}执行了一对多发送操作{}",account,roomId);
WebSocketRoom.sendMessage(roomId,message);//发送消息群发
}
else{
log.info("{}执行了一对一发送操作{}",account,roomId);
WebSocketRoom.sendMessage(roomId,account,message);//学生向老师发送消息
}
}
public void send(Session toSession,String message){
try {
log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
toSession.getBasicRemote().sendText(message);
} catch (Exception e) {
log.error("服务端发送消息给客户端失败:{}", e);
}
}
}
首先是@OnOpen注解,他的意思是在链接建立的时候调用的方法。我们在这个方法中对用户信息进行操作,因为环境是老师和学生,那么能够创建班级聊天室的的应该是老师。先判断房间号在连接池中有没有,如果有则加入。如果没有则判断房间号和用户账号是否一致,如果一致则认为是老师账号,先将房间加入到链接池中,在将老师的账号加入到链接池中。
之后是@OnMessage,这个注解是对接受到的消息进行处理,因为操作要求的原因,我们需要判断当前账号是否为老师账号,如果是则执行群发操作对班级中所有的学生都发消息,如果是学生则执行一对一操作用于学生回答老师的询问
|