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<String, Object> 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<String, Set<Session>> rooms = new ConcurrentHashMap();

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

private static final Map<String, Session> sessionContainer = new ConcurrentHashMap();
private static Map<String, Object> messageJsonMap = new ConcurrentHashMap();
// 头像容器
private static Map<String, Map<String, Object>> headImgMap = new ConcurrentHashMap();

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


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

                        //存储的是整个房间内所有人的头像信息及昵称,不是核心功能可以删除
map.put("user1", headimgurl);
map.put("user1NickName", ux.getNick());
HashMap<String, String> userhead = new HashMap<>();
userhead.put("openid", openid);
userhead.put("headimgurl", headimgurl);
ArrayList<Map<String, String>> 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<Session> 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<String> 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<Map<String, Object>> updateRoomNameTo5(List<Map<String, Object>> roomlist) {
for (Map<String, Object> 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<String, Object> map = (Map<String, Object>) 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<String, Object> map = (Map<String, Object>) 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<String, Object> map = headImgMap.get(roomName);
ArrayList<Map<String, String>> array = (ArrayList<Map<String, String>>) map.get("userList");
HashMap<String, String> 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<String, Object> map = headImgMap.get(roomName);
ArrayList<Map<String, String>> array = (ArrayList<Map<String, String>>) map.get("userList");


for (Map<String, String> 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<String, Object> 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<String> list = Arrays.asList(openidArray);


Map<String, Object> map = headImgMap.get(RoomName);
ArrayList<Map<String, String>> array = (ArrayList<Map<String, String>>) map.get("userList");
for (Map<String, String> 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端代码:

<!DOCTYPE html><html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>网络聊天室</title>  
</head>  
<style type="text/css">  
    .msg_board {  
        width: 322px;  
        height: 100px;  
        border: solid 1px darkcyan;  
        padding: 5px;  
        overflow-y: scroll;  
        // 文字长度大于div宽度时换行显示  
        word-break: break-all;  
    }  
    /*set srcoll start*/  
    ::-webkit-scrollbar  
    {  
        width: 10px;  
        height: 10px;  
        background-color: #D6F2FD;  
    }  
    ::-webkit-scrollbar-track  
    {  
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);  
        /*border-radius: 5px;*/  
        background-color: #D6F2FD;  
    }  
    ::-webkit-scrollbar-thumb  
    {  
        height: 20px;  
        /*border-radius: 10px;*/  
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);  
        background-color: #89D7F7;  
    }  
    /*set srcoll end*/  
</style>  
<body>  
<label>房间名</label>  
<input id="input_roomName" size="10" maxlength="10">  
<input type="button"  value="进入聊天室" onclick="initWebSocket()" /> 
<input type="button" value="退出聊天室" onclick="closeWs()" /><br>  
<div class="msg_board"></div>  
<input id="input_msg" size="43" maxlength="40">  
<input type="button" value="发送" onclick="send_msg()" />  
</body>  
<script type="text/javascript">  
 //loadXMLDoc()
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{
//  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
console.log('1111111111')
//document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
//xmlhttp.open('get', 'http://192.168.100.152:8080/dengluuser?openid=oyhoJ085mB-GcJZA3_Un9cPex2Rc' );
//xmlhttp.send();
}
    var webSocket;  
  
    function send_msg() {  
        if (webSocket != null) {  
            var input_msg = document.getElementById("input_msg").value.trim();  
            if (input_msg == "") {  
                return;  
            }  
            
            webSocket.send(input_msg);  
       
            // 清除input框里的信息  
            document.getElementById("input_msg").value = "";  
        } else {  
            alert("您已掉线,请重新进入聊天室...");  
        }  
    };  
  
    function closeWs() {  
        webSocket.close();  
    };  
  
    function initWebSocket() {  
        var roomName = document.getElementById("input_roomName").value;  
var demoString = 'demoString';
        // 房间名不能为空  
        if (roomName == null || roomName == "") {  
            alert("请输入房间名");  
            return;  
        }  
        if ("WebSocket" in window) {  
          /*  alert("您的浏览器支持 WebSocket!");   */
          
            if (webSocket == null) {  
                 //var url = "ws://kf.hzjnet.com/chat/" + roomName; 
// var url = "ws://39.104.56.14:8083/chat/" + roomName; 
//var url = "ws://192.168.100.152:8080/chat/" + roomName;
                 var url = "ws://https://39.104.56.140/chat/" + roomName;  
                // 打开一个 web socket  
                webSocket = new WebSocket(url);  
               
            } else {  
                alert("您已进入聊天室...");  
            }  
  
            webSocket.onopen = function () {  
                alert("已进入聊天室,畅聊吧...");  
                
            };  
  
            webSocket.onmessage = function (evt) {  
                var msg_board = document.getElementsByClassName("msg_board")[0];  
                var received_msg = evt.data;  
                var old_msg = msg_board.innerHTML;  
                msg_board.innerHTML = old_msg + received_msg + "<br>";  
                // 让滚动块往下移动  
                msg_board.scrollTop = msg_board.scrollTop + 40;  
            };  
  
            webSocket.onclose = function () {  
                // 关闭 websocket,清空信息板  
                alert("连接已关闭...");  
                webSocket = null;  
                document.getElementsByClassName("msg_board")[0].innerHTML = "";  
            };  
        }  
        else {  
            // 浏览器不支持 WebSocket  
            alert("您的浏览器不支持 WebSocket!");  
        }  
    }  
</script>  
</html>


猜你喜欢

转载自blog.csdn.net/xiehongking/article/details/80980432