首页 > Web开发 > 详细

SSH 项目中 使用websocket 实现网页聊天功能

时间:2017-08-17 00:20:18      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:发送   ref   asi   action   监听器   remote   static   scrollto   连接   

参考文章  :java使用websocket,并且获取HttpSession,源码分析    http://www.cnblogs.com/zhuxiaojie/p/6238826.html

 

1.在项目中引入依赖

websocket遵循了javaee规范,所以需要引入javaee的包

 1      <dependency>
 2         <groupId>javax.websocket</groupId>
 3         <artifactId>javax.websocket-api</artifactId>
 4         <version>1.1</version>
 5         <scope>provided</scope>
 6     </dependency>
 7     <dependency>
 8         <groupId>javax</groupId>
 9         <artifactId>javaee-api</artifactId>
10         <version>7.0</version>
11     </dependency>

 

2.编写一个处理websocket请求的类

 

  1 import java.io.IOException;
  2 import java.util.Set;
  3 import java.util.concurrent.CopyOnWriteArraySet;
  4 import java.util.concurrent.atomic.AtomicInteger;
  5 
  6 import javax.servlet.http.HttpSession;
  7 import javax.websocket.EndpointConfig;
  8 import javax.websocket.OnClose;
  9 import javax.websocket.OnError;
 10 import javax.websocket.OnMessage;
 11 import javax.websocket.OnOpen;
 12 import javax.websocket.Session;
 13 import javax.websocket.server.ServerEndpoint;
 14 
 15 import org.apache.commons.logging.Log;
 16 import org.apache.commons.logging.LogFactory;
 17 
 18 import com.itheima.bos.domain.User;
 19 import com.itheima.bos.utils.HTMLFilter;  
 20 
 21 
 22 // 进行配置  websocket 通过下面的地址链接服务器
 23 @ServerEndpoint(value = "/ws/chat" ,configurator = HttpSessionConfigurator.class)  
 24 public class ChatAnnotation {  
 25 
 26   private static final Log log = LogFactory.getLog(ChatAnnotation.class);  
 27 
 28   private static final String GUEST_PREFIX = "用户";  
 29   private static final AtomicInteger connectionIds = new AtomicInteger(0);    //统计及在线人数
 30   private static final Set<ChatAnnotation> connections =   new CopyOnWriteArraySet<ChatAnnotation>();  
 31 
 32   private final String nickname;  
 33   private Session session;  
 34   private HttpSession httpSession;//httpsession  手动添加进来的值
 35   private User user = null;
 36   
 37 
 38   public Session getSession() {
 39     return session;
 40 }
 41 
 42 public void setSession(Session session) {
 43     this.session = session;
 44 }
 45 
 46 public HttpSession getHttpSession() {
 47     return httpSession;
 48 }
 49 
 50 public void setHttpSession(HttpSession httpSession) {
 51     this.httpSession = httpSession;
 52 }
 53 
 54 public User getUser() {
 55     return user;
 56 }
 57 
 58 public void setUser(User user) {
 59     this.user = user;
 60 }
 61 
 62 public ChatAnnotation() {  
 63       nickname = GUEST_PREFIX + connectionIds.getAndIncrement();  
 64   }  
 65 
 66   /*当websocket的客户端连接到服务器时候,这个方法就会执行,并且传递一个session会话对象来 
 67    我们拿到这话session,就是可以给客户端发送消息*/  
 68   @OnOpen  
 69   public void start(Session session,EndpointConfig config) {  
 70        HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
 71       user = (User)httpSession.getAttribute("user");   //如果已经登录,在别的action中已经将一个user对象存入session中,此处直接取出
 72        if(user != null){
 73            //TODO  判断登录的用户是否已经存在于连接中
 74            this.session = session;
 75            this.httpSession = httpSession;
 76            connections.add(this);  
 77            String message = String.format(" 用户  %s  %s , 当前在线人数 %s", user.getUsername(), "加入聊天.",connectionIds);  
 78            broadcast(message);  
 79            
 80        }else{
 81            //用户未登陆
 82            try {
 83                session.close();
 84            } catch (IOException e) {
 85                e.printStackTrace();
 86            }
 87        }
 88   }  
 89 
 90     
 91   public static Set<ChatAnnotation> getConnections() {
 92     return connections;
 93 }
 94 
 95   /*客户端被关闭时候,就会自动会调用这个方法*/  
 96   @OnClose  
 97   public void end() {  
 98       connections.remove(this);  
 99       String message = String.format("- %s %s %s", user.getUsername(), "已经下线,当前用户数量是 ",connectionIds.decrementAndGet());  
100       broadcast(message);  
101   }  
102 
103   /*客户端给服务器发送消息,这个方法会自动调用,并且可以拿到发送过来的数据*/  
104   @OnMessage  
105   public void incoming(String message) {  
106       // Never trust the client  
107       String filteredMessage = String.format("%s: %s",  
108               user.getUsername(), HTMLFilter.filter(message.toString()));  
109       broadcast(filteredMessage);  
110   }  
111 
112   /*发生了异常自动执行*/  
113   @OnError  
114   public void onError(Throwable t) throws Throwable {  
115       log.error("Chat Error: " + t.toString(), t);  
116   }  
117 
118   /*广播:遍历客户端集,发送消息,注意发送要用的session,用session.getBasicRemote().sendText(msg)发送消息*/  
119   private static void broadcast(String msg) {  
120       for (ChatAnnotation client : connections) {//遍历所有  
121           try {//如果这个client已经在线  
122               synchronized (client) {  
123                   client.session.getBasicRemote().sendText(msg);//发送消息  
124               }  
125           } catch (IOException e) {//如果这个client不在线  
126               log.debug("Chat Error: 向用户"+client.getUser().getUsername()+"发送消息失败", e);  
127               connections.remove(client);  
128               try {  
129                   client.session.close();  
130               } catch (IOException e1) {  
131                   // Ignore  
132               }  
133               String message = String.format("-- %s %s", client.user.getUsername(), "已经下线.");  
134               broadcast(message);  
135           }  
136       }  
137   }
138 
139     @Override
140     public int hashCode() {
141         final int prime = 31;
142         int result = 1;
143         result = prime * result + ((user == null) ? 0 : user.hashCode());
144         return result;
145     }
146     
147     @Override
148     public boolean equals(Object obj) {
149         if (this == obj)
150             return true;
151         if (obj == null)
152             return false;
153         if (getClass() != obj.getClass())
154             return false;
155         ChatAnnotation other = (ChatAnnotation) obj;
156         if (user == null) {
157             if (other.user != null)
158                 return false;
159         } else if (!user.equals(other.user))
160             return false;
161         return true;
162     }  
163       
164 }  

 

3.编写获取httpsesion的类,和配置这些类

由于HTTP协议与websocket协议的不同,导致没法直接从websocket中获取协议,我们必须手动添加,具体细节可参考   获取httpsession 源码分析  

 1 import javax.servlet.http.HttpSession;
 2 import javax.websocket.HandshakeResponse;
 3 import javax.websocket.server.HandshakeRequest;
 4 import javax.websocket.server.ServerEndpointConfig;
 5 import javax.websocket.server.ServerEndpointConfig.Configurator;
 6 
 7 /**
 8  * 从websocket中获取用户session
 9  * 由于HTTP协议与websocket协议的不同,导致没法直接从websocket中获取协议,
10  * 下面的类中写了获取HttpSession的代码,但是如果真的放出去执行,那么会报空指值异常,因为这个HttpSession并没有设置进去。
11     需要我们自己来来设置HttpSession。这时候我们需要写一个监听器  下面有监听器的代码。
12  *
13  */
14 public class HttpSessionConfigurator extends Configurator {
15 
16     @Override
17     public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
18 
19           HttpSession httpSession = (HttpSession) request.getHttpSession();
20           // ServerEndpointConfig 继承->EndpointConfig  中一个方法  
21           //  Map<String,Object> getUserProperties();  对这个map进行赋值
22           sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
23     }
24 }

 

监听器

 1 import javax.servlet.ServletRequestEvent;
 2 import javax.servlet.ServletRequestListener;
 3 import javax.servlet.http.HttpServletRequest;
 4 
 5 public class RequestListener implements ServletRequestListener {
 6 
 7     public void requestInitialized(ServletRequestEvent sre)  {
 8         //将所有request请求都携带上httpSession
 9         ((HttpServletRequest) sre.getServletRequest()).getSession();
10     }
11     public RequestListener() {
12     }
13 
14     public void requestDestroyed(ServletRequestEvent arg0)  {
15     }
16 }

有了监听器我们需要在web.xml中配置它

1 <listener>
2       <listener-class>com.xwer.bos.web.websocket.RequestListener</listener-class>
3   </listener>

 

4. 前台页面

  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4 <meta charset="utf-8">
  5     <title>即时通讯</title>
  6     <style type="text/css">
  7         input#chat {
  8             width: 410px
  9         }
 10 
 11         #console-container {
 12             width: 400px;
 13         }
 14 
 15         #console {
 16             border: 1px solid #CCCCCC;
 17             border-right-color: #999999;
 18             border-bottom-color: #999999;
 19             height: 170px;
 20             overflow-y: scroll;
 21             padding: 5px;
 22             width: 100%;
 23         }
 24 
 25         #console p {
 26             padding: 0;
 27             margin: 0;
 28         }
 29     </style>
 30     <script type="text/javascript">
 31         var Chat = {};
 32 
 33         Chat.socket = null;
 34 
 35         Chat.connect = (function(host) {
 36             if (WebSocket in window) {
 37                 Chat.socket = new WebSocket(host);
 38             } else if (MozWebSocket in window) {
 39                 Chat.socket = new MozWebSocket(host);
 40             } else {
 41                 Console.log(Error: WebSocket is not supported by this browser.);
 42                 return;
 43             }
 44 
 45             Chat.socket.onopen = function () {
 46                 Console.log(Info: 登录成功);
 47                 document.getElementById(chat).onkeydown = function(event) {
 48                     if (event.keyCode == 13) {
 49                         Chat.sendMessage();
 50                     }
 51                 };
 52             };
 53 
 54             Chat.socket.onclose = function () {
 55                 document.getElementById(chat).onkeydown = null;
 56                 Console.log(Info: 已经下线.);
 57             };
 58 
 59             Chat.socket.onmessage = function (message) {
 60                 Console.log(message.data);
 61             };
 62         });
 63 
 64         Chat.initialize = function() {
 65             var urls=window.location.href;
 66             url = urls.substring(0,urls.lastIndexOf("/")).replace("http:","");
 67             
 68             
 69             if (window.location.protocol == http:) {
 70                 Chat.connect(ws:// + url + /ws/chat);
 71             } else {
 72                 Chat.connect(wss:// + url + /ws/chat);
 73             }
 74         };
 75 
 76         Chat.sendMessage = (function() {
 77             var message = document.getElementById(chat).value;
 78             if (message != ‘‘) {
 79                 Chat.socket.send(message);
 80                 document.getElementById(chat).value = ‘‘;
 81             }
 82         });
 83 
 84         var Console = {};
 85 
 86         Console.log = (function(message) {
 87             var console = document.getElementById(console);
 88             var p = document.createElement(p);
 89             p.style.wordWrap = break-word;
 90             p.innerHTML = message;
 91             console.appendChild(p);
 92             while (console.childNodes.length > 25) {
 93                 console.removeChild(console.firstChild);
 94             }
 95             console.scrollTop = console.scrollHeight;
 96         });
 97         
 98         //关闭WebSocket连接
 99          function closeWebSocket() {
100              Chat.socket.close();
101          }
102         
103         //发送消息
104         function sendMessage(){
105             Chat.sendMessage();
106         }
107         Chat.initialize();
108 
109     </script>
110 </head>
111 <body>
112 <noscript><h2 style="color: #ff0000">浏览器不支持websocket</h2></noscript>
113 <div>
114     <p>
115         <input type="text" placeholder="按下 enter键开始聊天 " id="chat">
116         <button onclick="sendMessage()">发送消息</button>
117     </p>
118     <div id="console-container">
119         <div id="console"></div>
120     </div>
121     
122        <hr/>
123     <button onclick="closeWebSocket()">关闭连接</button>
124   <hr/>
125 </div>
126 </body>
127 </html>

 

5. 由于使用了Struts框架,在Struts配置文件中配置,不过滤WS请求

1     <!--不拦截ws请求 -->
2     <constant name="struts.action.excludePattern" value="/ws/chat"></constant>
3         

 

 配置成功后界面如下

技术分享

 

 

 

 

 

 

 

 

SSH 项目中 使用websocket 实现网页聊天功能

标签:发送   ref   asi   action   监听器   remote   static   scrollto   连接   

原文:http://www.cnblogs.com/xwer/p/7376593.html

(0)
(0)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
© 2014 bubuko.com 版权所有 鲁ICP备09046678号-4
打开技术之扣,分享程序人生!
             

鲁公网安备 37021202000002号