websocket+Spring+小程序前端/html前端 实现多人多房间聊天

服务端:


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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.server.standard.SpringConfigurator;


import com.alibaba.fastjson.JSON;
import com.laoyouqian.yqqtp.bean.UserInfo;
import com.laoyouqian.yqqtp.bean.UserWXEx;
import com.laoyouqian.yqqtp.by.common.ChatRoomServiceImpl;
import com.laoyouqian.yqqtp.common.UserServiceImpl;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * writer: holien Time: 2017-08-01 13:00 Intent: webSocket服务器
 */
@ServerEndpoint(value = "/chat/{roomName}/{openid}", configurator = SpringConfigurator.class)//不添加此处代码则不能使用spring框架的注入功能,也就是@Autowired
@Controller
public class WxSocketServer {


@Autowired
private ChatRoomServiceImpl chatRoomServiceImpl;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private UserServiceImpl userServiceImpl;
/*
* public static ApplicationContext context = new
* ClassPathXmlApplicationContext("applicationContext.xml"); private static
* UserServiceImpl us = context.getBean(UserServiceImpl.class);
*/


// 使用map来收集session,key为roomName,value为同一个房间的用户集合
// concurrentMap的key不存在时报错,不是返回null

private static final Map> rooms = new ConcurrentHashMap();

        //sessionContainer 使用map格式存储session,这边使用的是微信的opneid,也可自行决定,方便与单独发送消息

private static final Map sessionContainer = new ConcurrentHashMap();
private static Map messageJsonMap = new ConcurrentHashMap();
// 头像容器
private static Map> headImgMap = new ConcurrentHashMap();

        //客户端与服务端创建连接触发
@OnOpen
public void connect(@PathParam("roomName") String roomName, @PathParam("openid") String openid, Session session)
throws Exception {


// 添加头像等信息到headImgMap
HashMap map = new HashMap<>();
UserWXEx ux = getUserWXExOnRedisByOpenid(openid);
String headimgurl = ux.getHeadimgurl();
// 将session按照房间名来存储,将各个房间的用户隔离
System.out.println(openid + "加入房间" + roomName);
if (!rooms.containsKey(roomName)) {
// 创建房间不存在时,创建房间
Set room = new HashSet<>();
// 添加用户
room.add(session);
rooms.put(roomName, room);

                        //存储的是整个房间内所有人的头像信息及昵称,不是核心功能可以删除
map.put("user1", headimgurl);
map.put("user1NickName", ux.getNick());
HashMap userhead = new HashMap<>();
userhead.put("openid", openid);
userhead.put("headimgurl", headimgurl);
ArrayList> arrayList = new ArrayList<>();
arrayList.add(userhead);
map.put("userList", arrayList);
headImgMap.put(roomName, map);
System.err.println(session.getId() + "创建房间号:" + roomName);
} else {
// 房间已存在,直接添加用户到相应的房间
rooms.get(roomName).add(session);
System.err.println(session.getId() + "加入房间号:" + roomName);
putUserheadImg(roomName, headimgurl, openid);
}


System.err.println("房间初始化start==============================================");
// 设置session到map便于单独给用户发送消息
sessionContainer.put(openid, session);
System.out.println("a client has connected!");
// 给新进用户发送房间初始化信息如房间内所有人的头像
messageJsonMap.clear();
// 1 :群发消息 2:获取当前房间所有人的头像等信息

String jsonString = "";
if (headImgMap.containsKey(roomName)) {

System.err.println("获取当前房间所有人的头像等信息.....");

                        //这边为什么要使用json格式发送主要是为了前台可以更具actionType来了解后台所要做的操作

messageJsonMap.put("actionType", "2");
messageJsonMap.put("RoomAllUserInfo", headImgMap.get(roomName));
jsonString = JSON.toJSONString(messageJsonMap);
// 一进房间只给自己传房间内所有用户的头像等信息
// session.getBasicRemote().sendText(jsonString);
// 可能会有问题!!!!!!一进房间给所有房间内所有用户传房间内所有用户的头像等信息------按照房间名进行广播
broadcast(roomName, jsonString);
}
// 新用户进来后向聊天室内所有用户发送新用户的头像等消息包括自己
messageJsonMap.clear();
messageJsonMap.put("actionType", "5");
messageJsonMap.put("newAddUserHeadimgurl", ux.getHeadimgurl());
messageJsonMap.put("newAddUserOpenid", openid);
jsonString = JSON.toJSONString(messageJsonMap);
broadcast(roomName, jsonString);
System.err.println("房间初始化end==============================================");
}


        //链接断开后触发

@OnClose
public void disConnect(@PathParam("roomName") String roomName, @PathParam("openid") String openid,
Session session) {
removeUserheadImg(roomName, openid);
// 房间id
int id = Integer.parseInt(roomName);

                //通过房间号码获取到该房间内的所有用户session
Set set = rooms.get(roomName);
set.remove(session);
// 如果房间已经没人 将房间状态设置为0 1:为正在进行的房间 0:已关闭
System.out.println("当前房间id:" + roomName + " 在线人数:" + set.size());
if (0 == set.size()) {
rooms.remove(roomName);
int num = chatRoomServiceImpl.updateChatRoomStateById(id, 0);
System.out.println("成功关闭房间:" + id + "关闭房间" + num);
} else {
try {
String jsonString = "";
if (headImgMap.containsKey(roomName)) {
System.err.println("获取当前房间所有人的头像等信息.....");
messageJsonMap.put("actionType", "2");
messageJsonMap.put("RoomAllUserInfo", headImgMap.get(roomName));
jsonString = JSON.toJSONString(messageJsonMap);
// 可能会有问题!!!!!!一进房间给所有房间内所有用户传房间内所有用户的头像等信息------按照房间名进行广播
broadcast(roomName, jsonString);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
System.out.println("a client has disconnected!");
}

       //接收用户发送的消息
@OnMessage
public void receiveMsg(@PathParam("roomName") String roomName, @PathParam("openid") String openid, String msg,
Session session) throws Exception {


UserWXEx wxUser = getUserWXExOnRedisByOpenid(openid);
messageJsonMap.clear();
messageJsonMap.put("msg", msg);
// actionType 1 :代表群发消息
messageJsonMap.put("actionType", "1");
messageJsonMap.put("nickName", wxUser.getNick());
messageJsonMap.put("avatarUrl", wxUser.getHeadimgurl());
messageJsonMap.put("gender", wxUser.getSex() + "");
String jsonString = JSON.toJSONString(messageJsonMap);
System.err.println(jsonString);
// Map map = redisTemplate.opsForValue().get(openid);
// 此处应该有html过滤
// msg = session.getId() + ":" + msg;
msg = wxUser.getNick().isEmpty() ? "游客" + session.getId() : wxUser.getNick() + ":" + msg;
System.out.println(msg);
// 接收到信息后进行广播
if (!roomName.isEmpty() && roomName != "") {
broadcast(roomName, jsonString);
}
}


// 按照房间名进行广播
public static void broadcast(String roomName, String msg) throws Exception {
if (rooms.containsKey(roomName)) {
for (Session session : rooms.get(roomName)) {
session.getBasicRemote().sendText(msg);
}
}
// System.out.println(uss);
}


/**
* 修改房间号 如int 23 改为 String 00023

* @return
*/
public static String updateChatRoomName(Integer roomName) {
String newRoomName = roomName.toString();
for (int i = 0; i < 6 - newRoomName.length(); i++) {
newRoomName = "0" + newRoomName;
}
return newRoomName;
}


/**
* 修改房间号 如 String 00023 改为int 23

* @return
*/
public static Integer updateChatRoomName(String roomName) {
return Integer.parseInt(roomName);


}


/**
* 修改房间号 例如 23 改为 00023

* @param roomlist
* @return
*/
public static List> updateRoomNameTo5(List> roomlist) {
for (Map map : roomlist) {
map.put("id", updateChatRoomName((int) map.get("id")));
}
return roomlist;
}


// 根据openid获取session
public static Session getSessionByOpenid(String openid) {
return sessionContainer.get(openid);
}


/**
* 根据openid获取在登录时存储在redis中的用户信息

* @param openid
* @return
*/
public UserInfo getUserInfoOnRedisByOpenid(String openid) {


Map map = (Map) redisTemplate.opsForValue().get(openid);
if (map == null ) {
UserInfo user = userServiceImpl.findByOpenId(openid);
map.put("user",user );
redisTemplate.opsForValue().set(openid, map);
return user;
}else{
UserInfo user = (UserInfo) map.get("user");
if (user == null) {
user = userServiceImpl.findByOpenId(openid);;
map.put("user", user);
redisTemplate.opsForValue().set(openid, map);
}
return user;
}

}


/**
* 根据openid获取在登录时存储在redis中的用户信息

* @param openid
* @return
*/
public UserWXEx getUserWXExOnRedisByOpenid(String openid) {

// UserWXEx userWXEx = userServiceImpl.findOpenId(openid);
Map map = (Map) redisTemplate.opsForValue().get(openid);
if(map == null){
UserWXEx findOpenId = userServiceImpl.findOpenId(openid);
map.put("wxuser",findOpenId );
redisTemplate.opsForValue().set(openid, map);
return findOpenId;
}else{
UserWXEx ux = (UserWXEx) map.get("wxuser");
if (ux == null) {
ux = userServiceImpl.findOpenId(openid);
map.put("wxuser", ux);
redisTemplate.opsForValue().set(openid, map);
}
return ux;
}
}


// 将用户头像存储到
public void putUserheadImg(String roomName, String heaurl, String openid) {
// 判断当前是否有该房间
Map map = headImgMap.get(roomName);
ArrayList> array = (ArrayList>) map.get("userList");
HashMap hashMap = new HashMap<>();
hashMap.put("openid", openid);
hashMap.put("headimgurl", heaurl);
array.add(hashMap);
map.put("userList", array);
headImgMap.put(roomName, map);
}


// 用户断线或退出时将房间用户头像列表内的数据删除
public void removeUserheadImg(String roomName, String openid) {
// 判断当前是否有该房间
Map map = headImgMap.get(roomName);
ArrayList> array = (ArrayList>) map.get("userList");


for (Map map2 : array) {
if (openid == map2.get("openid").toString()) {
array.remove(map2);
break;
}
}


map.put("userList", array);
headImgMap.put(roomName, map);
}


/**
* 更新头像容器
*/
public static void setHeadImgMapUser1OrUser2(boolean isUser1, UserWXEx ux, String roomName) {
Map map = headImgMap.get(roomName);
System.out.println("map.toString()" + map.toString());
if (isUser1) {


map.put("user1", ux.getHeadimgurl());
map.put("user1NickName", ux.getNick());
} else {
map.put("user2", ux.getHeadimgurl());
map.put("user2NickName", ux.getNick());
}
headImgMap.put(roomName, map);
}


/**
* 将游戏结果发送至聊天房间 但是排除openidArray数组里面的openid不发送

* @param RoomName
* @param openidArray
*/
public static void sendGameresultsByRoomNameProhibitArray(String RoomName, String msg, String... openidArray) {


String openid = "";
List list = Arrays.asList(openidArray);


Map map = headImgMap.get(RoomName);
ArrayList> array = (ArrayList>) map.get("userList");
for (Map map2 : array) {
openid = (String) map2.get("openid");


if (!list.contains(openid)) {
try {


getSessionByOpenid(openid).getBasicRemote().sendText(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("将游戏结果发送至聊天房间出现异常" + openid);
e.printStackTrace();
}


}
}
}


}


小程序端前台:注* 小程序与后台交互必须是https协议

wx.connectSocket({
url: 'wss://' + getApp().globalData.WebSocketUrl + '/chat/' + titles + '/' + getApp().globalData.openid
})
wx.onSocketError( function (res) {
console.log( 'WebSocket连接打开失败,请检查!')
})
wx.onSocketMessage( function (res) {
console.log( '收到服务器内容:' + res.data)
}
wx.onSocketOpen( function (res) {
console.log( 'WebSocket连接已打开!')
socketOpen = true
})
html端代码:

  
  
      
    网络聊天室  
  
  
  
  
  
 

  
  
  
  
  
  


你可能感兴趣的:(websocket+Spring+小程序前端/html前端 实现多人多房间聊天)