现在前后的的聊天实现分类:
1,通过轮询的方式。
2,通过长连接的方式。
优缺点:
第一种方式实现简单,但是实现起来会有很多坑。亲身经历过的,比如轮询会造成后端服务接口压力过大,前端也会有数据拼接展示的问题。
第二种方法是比较实际且可行的方法。下面我们来详细介绍下。
技术栈:
websocket协议,java后端服务语言,小程序前端,redis缓存等技术
实现步骤:
1,具体实现我们通过websocket来实现全都后端的消息实时通知,用redis实现后端服务节点之间的消息通知,这里redis的作用相当于一个消息队列作用等价于mq。我们通过pub,sub命令实现的一个mq。
java代码:
> public class MyWebSocket {
> // websocket类的作用域是每个session回话,所有这里不能通过spring来托管,需要通过手动的方式来创建一个bean对象
> private RedisService redisService = SpringBeanUtils.getBean(RedisService.class);
> //与某个客户端的连接会话,需要通过它来给客户端发送数据
> private Session session;
> //用以记录用户和房间号的对应关系(sessionId,room)
> private static HashMap<String, String> RoomForUser = new HashMap<String, String>();
> //用以记录房间和其中用户群的对应关系(room,List<用户>)
> public static HashMap<String, CopyOnWriteArraySet<User>> UserForRoom = new HashMap<String, CopyOnWriteArraySet<User>>();
> // String uuid = UUID.randomUUID().toString();
> String uuid = "111111111";
>
> /**
> * 聊天-连接建立成功
> *
> * @param session
> */
> @OnOpen
> public void onOpen(Session session) throws IOException {
> log.info("聊天-连接建立成功");
> this.session = session;
> User user = new User(session.getId(), "", this);
> if (UserForRoom.get(uuid) == null) {
> CopyOnWriteArraySet<User> roomUsers = new CopyOnWriteArraySet<>();
> roomUsers.add(user);
> UserForRoom.put(uuid, roomUsers);
> RoomForUser.put(session.getId(), uuid);
> } else {
> UserForRoom.get(uuid).add(user);
> RoomForUser.put(session.getId(), uuid);
> }
> Map<String, String> result = new HashMap<>();
> result.put("type", "bing");
> result.put("sendUser", "系统消息");
> result.put("id", session.getId());
> this.sendMessage(JSON.toJSONString(result));
> }
>
> /**
> * 聊天-连接关闭调用的方法
> */
> @OnClose
> public void onClose() {
> log.info("聊天-连接关闭调用的方法");
> }
>
> /**
> * 聊天-收到客户端消息后调用的方法
> *
> * @param message 消息内容
> * @param session
> */
> @OnMessage
> public void onMessage(String message, Session session) {
> log.info("聊天-收到客户端消息后调用的方法-sessionid:{}", session.getId());
> Map<String, String> result = new HashMap<>();
> result.put("type", "msg");
> result.put("msg", message);
> String room = RoomForUser.get(session.getId());
> CopyOnWriteArraySet<User> users = UserForRoom.get(room);
> sendMessagesOther(users, JSON.toJSONString(result));
> // redis发送消息到其它服务器
> redisService.pub("LENDER_TOPIC", JSONObject.fromObject(new ChatMessageVo(MAC.getMAC(),room, message)).toString());
> }
>
>
>
> /**
> * 聊天-连接发生错误时的调用方法
> *
> * @param session
> * @param error
> */
> @OnError
> public void onError(Session session, Throwable error) {
> log.info("聊天-连接发生错误时的调用方法");
> }
>
> // 发现消息
> private void sendMessagesOther(CopyOnWriteArraySet<User> users, String message) {
> //群发消息
> for (User item : users) {
> if (item.getWebSocket() != this) {
> try {
> item.getWebSocket().sendMessage(message);
> } catch (IOException e) {
> e.printStackTrace();
> }
> }
> }
> }
>
> // 发信息
> public void sendMessage(String message) throws IOException {
> this.session.getBasicRemote().sendText(message);
> } }
前端js的简单代码实现:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>chat</title>
<script type="text/javascript">
var ws = null;
function WebSocketTest()
{
if ("WebSocket" in window)
{
console.log("您的浏览器支持 WebSocket!");
// 打开一个 web socket
ws = new WebSocket("ws://192.168.219.1:6011/websocket");
ws.onopen = function()
{
// Web Socket 已连接上,使用 send() 方法发送数据
console.log("socket链接成功");
};
}else
{
// 浏览器不支持 WebSocket
console.log("您的浏览器不支持 WebSocket!");
}
}
//接收到消息的回调方法
ws.onmessage = function (event) {
console.log("接收到消息的回调方法"+event)
}
function WebSocketSendTest()
{
// 发送消息
ws.send("发送消息");
console.log("发送消息...");
}
</script>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">创建 WebSocket链接</a><br>
<a href="javascript:WebSocketSendTest()">发送消息</a><br>
<a href="javascript:WebSocketCloseTest()">关闭链接</a><br>
</div>
</body>
</html>