WebSocket 实现群聊 - 简单测试例子

Posted simplejokerking

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebSocket 实现群聊 - 简单测试例子相关的知识,希望对你有一定的参考价值。

B/S中一般通信和WebSocket的区别:

  在B/S结构的应用中,传统的通信机制是请求-响应的模式,也就是说只有客户端发送请求,服务端才会给出相应的响应(不考虑程序问题或者是其他原因),服务器不能够主动的为浏览器推送消息。但是WebSocket可以实现客户端和服务端的双向通信,其原理就是在客户端和服务器端建立一个通信的管道,来实现客户端和服务器端的双向通信。

  通过在写例子的过程中,我的理解是(Java为例-注解方式):服务器端通过注解为方法注册监听事件(项目启动会自动扫描这些注解然后进行装载配置),然后客户端通过绑定到WebSocket对象上的方法共同实现客户端和服务器端的消息传输(简单理解)。

  ①服务端配置

技术分享图片
 1 package com.chat.config;
 2 
 3 import java.util.Set;
 4 import javax.websocket.Endpoint;
 5 import javax.websocket.server.ServerApplicationConfig;
 6 import javax.websocket.server.ServerEndpointConfig;
 7 
 8 public class WebSocketConfig implements ServerApplicationConfig{
 9 
10     /**
11      * 基于注解的开启方式
12      */
13     @Override
14     public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanedSockets) {
15         System.out.println("=========================");
16         System.out.println("  WebSocket装载配置...");
17         System.out.println("=========================");
18         return scanedSockets;
19     }
20 
21     /**
22      * 结余接口的开启方式
23      */
24     @Override
25     public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
26         return null;
27     }
28 
29 }
WebSocketConfig.java

  ②服务端Socket

技术分享图片
  1 package com.chat.socket;
  2 
  3 import java.io.IOException;
  4 import java.io.UnsupportedEncodingException;
  5 import java.net.URLDecoder;
  6 import java.util.ArrayList;
  7 import java.util.Iterator;
  8 import java.util.List;
  9 
 10 import javax.websocket.OnClose;
 11 import javax.websocket.OnMessage;
 12 import javax.websocket.OnOpen;
 13 import javax.websocket.Session;
 14 import javax.websocket.server.ServerEndpoint;
 15 
 16 import com.chat.message.Message;
 17 
 18 @ServerEndpoint("/chat")
 19 public class ChatSocket {
 20     
 21     private static List<String> names = new ArrayList<String>();
 22     private static List<Session> sessions = new ArrayList<Session>();
 23     //当前登录用户
 24     private static String userName ;
 25 
 26     /**
 27      * 每一个通信管道对应一个Socket实例,也是一个Session
 28      */
 29     public ChatSocket () {
 30         System.out.println("ChatSocket 创建完成.");
 31     }
 32     
 33     /**
 34      * 会话开启事件
 35      * @param session
 36      */
 37     @OnOpen
 38     public void chatOpen (Session session) {
 39         this.userName = session.getQueryString();
 40         try {
 41             userName = URLDecoder.decode(userName, "utf-8");
 42             if (null != userName && !userName.isEmpty()) {
 43                 userName = userName.split("=")[1].trim();
 44                 String msgStr = "欢迎" + userName + "加入聊天室!";
 45                 names.add(userName);//用户列表
 46                 Message msg = new Message();
 47                 msg.setNames(names);
 48                 msg.setMsg(msgStr);
 49                 sessions.add(session);
 50                 broadcast(msg);
 51             }
 52         } catch (Exception e) {
 53             e.printStackTrace();
 54         }
 55     }
 56     
 57     /**
 58      * 处理客户端发送的消息并响应
 59      * @param session
 60      * @param msg 客户端发送的消息体
 61      */
 62     @OnMessage
 63     public void ChatMsg (Session session,String msg) {
 64         String msgBody = "【" + this.userName + "】说:</br>" + msg;
 65         Message msgObj = new Message();
 66         msgObj.setMsg(msgBody); 
 67         msgObj.setNames(names);
 68         //广播客户端消息给每个登录用户
 69         this.broadcast(msgObj);
 70     }
 71     
 72     /**
 73      * 会话关闭事件
 74      */
 75     @OnClose
 76     public void close (Session session) {
 77         String msg = "欢送 " + this.userName + " 离开聊天室!";
 78         //移除当前推出的会话(管道)
 79         sessions.remove(session);
 80         Message msgObj = new Message();
 81         names.remove(this.userName);
 82         msgObj.setMsg(msg);
 83         msgObj.setNames(names);
 84         this.broadcast(msgObj);
 85     }
 86     
 87     /**
 88      * 消息广播的方法
 89      * @param msg
 90      */
 91     public void broadcast(Message msg) {
 92         for (Iterator<Session> sessionIt = sessions.iterator();sessionIt.hasNext();) {
 93             try {
 94                 sessionIt.next().getBasicRemote().sendText(msg.toJson());
 95                 System.out.println(msg.toJson());
 96             } catch (IOException e) {
 97                 e.printStackTrace();
 98             }
 99         }
100     }
101 }
ChatSocket.java

  ③格式化消息体

技术分享图片
 1 package com.chat.message;
 2 
 3 import java.util.List;
 4 
 5 import com.google.gson.Gson;
 6 
 7 public class Message {
 8 
 9     private List<String> names;
10     private String msg;
11     
12     private static Gson gson = new Gson();
13     
14     public List<String> getNames() {
15         return names;
16     }
17     public void setNames(List<String> names) {
18         this.names = names;
19     }
20     public String getMsg() {
21         return msg;
22     }
23     public void setMsg(String msg) {
24         this.msg = msg;
25     }
26     
27     public String toJson () {
28         return gson.toJson(this);
29     }
30     
31 }
Message.java

  ④应用-登录

技术分享图片
 1 package com.chat.servlet;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.annotation.WebServlet;
 8 import javax.servlet.http.HttpServlet;
 9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 import javax.servlet.http.HttpSession;
12 
13 
14 @WebServlet("/loginServlet")
15 public class LoginServlet extends HttpServlet {
16     private static final long serialVersionUID = 1L;
17 
18     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
19         this.doPost(request, response);
20     }
21 
22     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
23         String userName = null == request.getParameter("userName") ? "" : request.getParameter("userName").trim();
24         HttpSession session =  request.getSession();
25         if (!userName.isEmpty()) {
26             session.setAttribute("userName", userName);
27         }
28         response.sendRedirect("jsp/chat.jsp");
29     }
30 }
LoginServlet.java

  ⑤客户端-登录页面

技术分享图片
 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 7 <title>Login Page</title>
 8 </head>
 9 <body>
10 
11 <form action="${pageContext.request.contextPath}/loginServlet" method="get">
12     UserName:<input type="text" name="userName"/>
13     <br/>
14     <input type="submit" value="Submit"/>
15 </form>
16 </body>
17 </html>
login.jsp

  ⑥客户端-聊天页面

技术分享图片
 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 7 <title>Chat Page</title>
 8 <script type="text/javascript" src="${pageContext.request.contextPath}/plugins/jquery-1.8.3.min.js"></script>
 9 <script type="text/javascript">
10     //声明全局变量
11     var ws;
12     var userName = ‘${sessionScope.userName}‘;
13     var target = "ws://localhost:9999/ChatDemo/chat?userName=" + userName;
14     $(function () {
15         //打开页面就开启Socket连接
16         if (‘WebSocket‘ in window) {
17             ws = new WebSocket(target);
18         } else if (‘MozWebSocket‘ in window) {//火狐
19             ws = new MozWebSocket(target);
20         } else {
21             return alert("请使用支持WebSocket的浏览器!");
22         }
23         ws.onmessage = function (event) {
24             if (event) {
25                 console.dir(event);
26                 $("#userList").html("");
27                 eval("var data = " + event.data + ";");
28                 $(data.names).each(function () {
29                     $("#userList").append(this + "</br>");
30                 });
31                 $("#chatContent").append(data.msg + "<br/>");
32             }    
33         }
34         //为send按钮增加点击事件(发送消息按钮)
35         $("#sendBtn").on("click",function () {
36             //获取需要发送的消息体
37             var msgEdit = $("input[name=‘sendMsg‘]").val();
38             ws.send(msgEdit);
39             $("input[name=‘sendMsg‘]").val("");
40         });
41     });
42 </script>
43 <style type="text/css">
44     
45 </style>
46 </head>
47 <body>
48     <div id="chatContent" style="float:left;width:267px;height:240px;border:1px solid black;">
49     </div>
50     
51     <div id="userList" style="float:left;width:112px;height:240px;border:1px solid black;">
52     </div>
53     <div id="msgSendContent" style="clear: both;">
54         <input type="text" name="sendMsg" /><button id="sendBtn">Send</button>
55     </div>
56 </body>
57 </html>
chat.jsp

例子结构(非Maven)

技术分享图片

 

以上是关于WebSocket 实现群聊 - 简单测试例子的主要内容,如果未能解决你的问题,请参考以下文章

开发经验springboot整合websocket实现群聊

websocket实现简单的群聊

推荐一个.Net Core开发的Websocket群聊私聊的开源项目

Flask 实现 WebSocket 通讯---群聊和私聊

spring websocket 和socketjs实现单聊群聊,广播的消息推送详解

代码发布项目——django实现websocket(使用channels)基于channels实现群聊功能gojs插件paramiko模块