Tomcat 7,Java,WebSocket 기반 서버 푸 시 채 팅 방 인 스 턴 스

18897 단어 자바채 팅 방
머리말
HTML 5 WebSocket 은 서버 와 브 라 우 저의 양 방향 통신 을 실현 했다.양 방향 통신 은 서버 메시지 전송 개발 을 더욱 간단하게 한다.가장 흔히 볼 수 있 는 것 은 인 스 턴 트 메 신 저 와 정보의 실시 간성에 대한 요구 가 비교적 높 은 응용 이다.예전 의 서버 메시지 푸 시 는 대부분'폴 링'과'긴 연결'기술 을 사 용 했 는데 이 두 가지 기술 은 서버 에 상당 한 비용 을 들 이 고 실시 성 이 그리 높 지 않 았 다.웹 소켓 기술 은 적은 비용 만 들 고 실시 간 으로 매우 높다.웹 소켓 기술 을 활용 해 채 팅 방 을 개발 하 는 방법 에 대해 설명 한다.이 인 스 턴 스 에서 사용 하 는 것 은 Tomcat 7 서버 입 니 다.모든 서버 가 WebSocket 의 실현 에 대해 다 르 기 때문에 이 인 스 턴 스 는 Tomcat 서버 에서 만 실 행 될 수 있 습 니 다.그러나 현재 Spring 은 WebSocket 의 API 를 출시 하여 각 서버 의 실현 을 호 환 할 수 있 습 니 다.관련 자 료 를 찾 아 볼 수 있 습 니 다.여기 서 소개 하지 않 겠 습 니 다.아래 그림 은 채 팅 방 의 효과 그림 입 니 다:

이 사례 에서 메시지 의 실시 간 푸 시 를 실현 하고 채 팅 사용자 의 상하 선 알림 도 실현 했다.다음은 어떻게 실현 되 는 지 구체 적 으로 설명 하 겠 습 니 다.
백그라운드 처리
Tomcat 에서 웹 소켓 을 실현 하 는 것 은 주로 org.apache.catalina.websocket.Message Inbound 와 같은 종류 입 니 다.이 종 류 는{TOMCAT 에 있 습 니 다.HOME}/lib/catalina.jar 에 있 기 때문에 개발 할 때 catalina.jar 와 tomcat-coyote.jar 를 도입 해 야 합 니 다.아래 코드 는 클 라 이언 트 연결 주소 에 노출 된 Servlet 입 니 다.

package com.ibcio; 
 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServletRequest; 
 
import org.apache.catalina.websocket.StreamInbound; 
 
@WebServlet(urlPatterns = { "/message"}) 
//         ws://          WebSocketServlet    
public class WebSocketMessageServlet extends org.apache.catalina.websocket.WebSocketServlet { 
 
  private static final long serialVersionUID = 1L; 
   
  public static int ONLINE_USER_COUNT = 1; 
   
  public String getUser(HttpServletRequest request){ 
    return (String) request.getSession().getAttribute("user"); 
  } 
 
  //   Servlet    ,    createWebSocketInbound,          WebSocket     
  @Override 
  protected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) { 
    return new WebSocketMessageInbound(this.getUser(request)); 
  } 
} 
이 Servlet 는 일반적인 Servlet 과 는 조금 다 릅 니 다.계승 하 는 WebSocketServlet 클래스 이 며,createWebSocketInbound 방법 을 다시 써 야 합 니 다.이 클래스 에서 Session 의 user 속성 은 사용자 가 index.jsp 에 들 어 갈 때 설정 한 것 으로 현재 사용자 의 닉네임 을 기록 합 니 다.다음은 자신 이 구현 한 WebSocket 연결 대상 클래스 WebSocketmessage Inbound 클래스 의 코드 입 니 다.

 package com.ibcio; 
 
import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.nio.CharBuffer; 
 
import net.sf.json.JSONObject; 
 
import org.apache.catalina.websocket.MessageInbound; 
import org.apache.catalina.websocket.WsOutbound; 
 
public class WebSocketMessageInbound extends MessageInbound { 
 
  //          
  private final String user; 
 
  public WebSocketMessageInbound(String user) { 
    this.user = user; 
  } 
 
  public String getUser() { 
    return this.user; 
  } 
 
  //           
  @Override 
  protected void onOpen(WsOutbound outbound) { 
    //       ,          
    JSONObject result = new JSONObject(); 
    result.element("type", "user_join"); 
    result.element("user", this.user); 
    //                   
    WebSocketMessageInboundPool.sendMessage(result.toString()); 
     
    result = new JSONObject(); 
    result.element("type", "get_online_user"); 
    result.element("list", WebSocketMessageInboundPool.getOnlineUser()); 
    //              
    WebSocketMessageInboundPool.addMessageInbound(this); 
    //                 
    WebSocketMessageInboundPool.sendMessageToUser(this.user, result.toString()); 
  } 
 
  @Override 
  protected void onClose(int status) { 
    //       ,          
    WebSocketMessageInboundPool.removeMessageInbound(this); 
    JSONObject result = new JSONObject(); 
    result.element("type", "user_leave"); 
    result.element("user", this.user); 
    //                 
    WebSocketMessageInboundPool.sendMessage(result.toString()); 
  } 
 
  @Override 
  protected void onBinaryMessage(ByteBuffer message) throws IOException { 
    throw new UnsupportedOperationException("Binary message not supported."); 
  } 
 
  //                 
  @Override 
  protected void onTextMessage(CharBuffer message) throws IOException { 
    //            
    WebSocketMessageInboundPool.sendMessage(message.toString()); 
  } 
} 
코드 에서 주로 onOpen,onClose,onTextMessage 방법 을 실현 하여 사용자 의 온라인,오프라인,메 시 지 를 보 내 는 것 을 처리 합 니 다.이 클래스 에는 WebSocketmessage Inbound Pool 연결 풀 클래스 가 있 습 니 다.이 클래스 는 현재 온라인 사용자 의 연결 을 관리 하 는 데 사 용 됩 니 다.다음은 이 종류의 코드 입 니 다.

package com.ibcio; 
 
import java.io.IOException; 
import java.nio.CharBuffer; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Set; 
 
public class WebSocketMessageInboundPool { 
 
  //     MAP   
  private static final Map<String,WebSocketMessageInbound > connections = new HashMap<String,WebSocketMessageInbound>(); 
   
  //          
  public static void addMessageInbound(WebSocketMessageInbound inbound){ 
    //     
    System.out.println("user : " + inbound.getUser() + " join.."); 
    connections.put(inbound.getUser(), inbound); 
  } 
   
  //          
  public static Set<String> getOnlineUser(){ 
    return connections.keySet(); 
  } 
   
  public static void removeMessageInbound(WebSocketMessageInbound inbound){ 
    //     
    System.out.println("user : " + inbound.getUser() + " exit.."); 
    connections.remove(inbound.getUser()); 
  } 
   
  public static void sendMessageToUser(String user,String message){ 
    try { 
      //           
      System.out.println("send message to user : " + user + " ,message content : " + message); 
      WebSocketMessageInbound inbound = connections.get(user); 
      if(inbound != null){ 
        inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); 
      } 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } 
  } 
   
  //           
  public static void sendMessage(String message){ 
    try { 
      Set<String> keySet = connections.keySet(); 
      for (String key : keySet) { 
        WebSocketMessageInbound inbound = connections.get(key); 
        if(inbound != null){ 
          System.out.println("send message to user : " + key + " ,message content : " + message); 
          inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); 
        } 
      } 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } 
  } 
} 
프런트 디 스 플레이
위의 코드 는 바로 채 팅 방 배경 에 있 는 코드 입 니 다.주로 3 개의 대상 으로 구성 되 어 있 습 니 다.Servlet,연결 대상,연결 풀,아래 는 바로 프론트 데스크 의 코드 입 니 다.프론트 데스크 의 코드 는 주로 서버 와 연결 되 고 사용자 목록 과 정보 목록 을 보 여 줍 니 다.프론트 데스크 의 전 시 는 Ext 프레임 워 크 를 사 용 했 습 니 다.Ext 에 익숙 하지 않 은 학생 들 은 Ext 를 초보 적 으로 이해 할 수 있 습 니 다.다음은 index.jsp 의 코드 입 니 다.

<%@ page language="java" pageEncoding="UTF-8" import="com.ibcio.WebSocketMessageServlet"%> 
<% 
  String user = (String)session.getAttribute("user"); 
  if(user == null){ 
    //        
    user = "  " + WebSocketMessageServlet.ONLINE_USER_COUNT; 
    WebSocketMessageServlet.ONLINE_USER_COUNT ++; 
    session.setAttribute("user", user); 
  } 
  pageContext.setAttribute("user", user); 
%> 
<html> 
<head> 
  <title>WebSocket    </title> 
  <!--   CSS   --> 
  <link rel="stylesheet" type="text/css" href="ext4/resources/css/ext-all.css"> 
  <link rel="stylesheet" type="text/css" href="ext4/shared/example.css" /> 
  <link rel="stylesheet" type="text/css" href="css/websocket.css" /> 
   
  <!--   Ext JS   ,      webscoket. --> 
  <script type="text/javascript" src="ext4/ext-all-debug.js"></script> 
  <script type="text/javascript" src="websocket.js"></script> 
  <script type="text/javascript"> 
    var user = "${user}"; 
  </script> 
</head> 
 
<body> 
  <h1>WebSocket   </h1> 
  <p>  HTML5     API Ext           ,     ,     :</p> 
  <ul class="feature-list" style="padding-left: 10px;"> 
    <li>      ,      ,      </li> 
    <li>  WebSocket      ,     ,      ,       </li> 
    <li>  Ext      </li> 
    <li>        </li> 
  </ul> 
  <div id="websocket_button"></div> 
</body> 
</html> 
페이지 의 전 시 는 주로 웹 socket.js 에서 제 어 됩 니 다.다음은 웹 socket.jsd 의 코드 입 니 다.

//            
Ext.define('MessageContainer', { 
 
  extend : 'Ext.view.View', 
 
  trackOver : true, 
 
  multiSelect : false, 
 
  itemCls : 'l-im-message', 
 
  itemSelector : 'div.l-im-message', 
 
  overItemCls : 'l-im-message-over', 
 
  selectedItemCls : 'l-im-message-selected', 
 
  style : { 
    overflow : 'auto', 
    backgroundColor : '#fff' 
  }, 
 
  tpl : [ 
      '<div class="l-im-message-warn">​         、    、    。          。</div>', 
      '<tpl for=".">', 
      '<div class="l-im-message">', 
      '<div class="l-im-message-header l-im-message-header-{source}">{from} {timestamp}</div>', 
      '<div class="l-im-message-body">{content}</div>', '</div>', 
      '</tpl>'], 
 
  messages : [], 
 
  initComponent : function() { 
    var me = this; 
    me.messageModel = Ext.define('Leetop.im.MessageModel', { 
          extend : 'Ext.data.Model', 
          fields : ['from', 'timestamp', 'content', 'source'] 
        }); 
    me.store = Ext.create('Ext.data.Store', { 
          model : 'Leetop.im.MessageModel', 
          data : me.messages 
        }); 
    me.callParent(); 
  }, 
 
  //                
  receive : function(message) { 
    var me = this; 
    message['timestamp'] = Ext.Date.format(new Date(message['timestamp']), 
        'H:i:s'); 
    if(message.from == user){ 
      message.source = 'self'; 
    }else{ 
      message.source = 'remote'; 
    } 
    me.store.add(message); 
    if (me.el.dom) { 
      me.el.dom.scrollTop = me.el.dom.scrollHeight; 
    } 
  } 
}); 
이 코드 는 주로 메 시 지 를 보 여 주 는 용 기 를 실현 합 니 다.다음은 페이지 로 딩 이 완 료 된 후에 실 행 된 코드 입 니 다.

  Ext.onReady(function() { 
      //        
      var input = Ext.create('Ext.form.field.HtmlEditor', { 
            region : 'south', 
            height : 120, 
            enableFont : false, 
            enableSourceEdit : false, 
            enableAlignments : false, 
            listeners : { 
              initialize : function() { 
                Ext.EventManager.on(me.input.getDoc(), { 
                      keyup : function(e) { 
                        if (e.ctrlKey === true 
                            && e.keyCode == 13) { 
                          e.preventDefault(); 
                          e.stopPropagation(); 
                          send(); 
                        } 
                      } 
                    }); 
              } 
            } 
          }); 
      //         
      var output = Ext.create('MessageContainer', { 
            region : 'center' 
          }); 
 
      var dialog = Ext.create('Ext.panel.Panel', { 
            region : 'center', 
            layout : 'border', 
            items : [input, output], 
            buttons : [{ 
                  text : '  ', 
                  handler : send 
                }] 
          }); 
      var websocket; 
 
      //   WebSocket 
      function initWebSocket() { 
        if (window.WebSocket) { 
          websocket = new WebSocket(encodeURI('ws://localhost:8080/WebSocket/message')); 
          websocket.onopen = function() { 
            //     
            win.setTitle(title + ' (   )'); 
          } 
          websocket.onerror = function() { 
            //     
            win.setTitle(title + ' (      )'); 
          } 
          websocket.onclose = function() { 
            //     
            win.setTitle(title + ' (      )'); 
          } 
          //     
          websocket.onmessage = function(message) { 
            var message = JSON.parse(message.data); 
            //          
            if (message.type == 'message') { 
              output.receive(message); 
            } else if (message.type == 'get_online_user') { 
              //         
              var root = onlineUser.getRootNode(); 
              Ext.each(message.list,function(user){ 
                var node = root.createNode({ 
                  id : user, 
                  text : user, 
                  iconCls : 'user', 
                  leaf : true 
                }); 
                root.appendChild(node); 
              }); 
            } else if (message.type == 'user_join') { 
              //     
                var root = onlineUser.getRootNode(); 
                var user = message.user; 
                var node = root.createNode({ 
                  id : user, 
                  text : user, 
                  iconCls : 'user', 
                  leaf : true 
                }); 
                root.appendChild(node); 
            } else if (message.type == 'user_leave') { 
                //     
                var root = onlineUser.getRootNode(); 
                var user = message.user; 
                var node = root.findChild('id',user); 
                root.removeChild(node); 
            } 
          } 
        } 
      }; 
 
      //      
      var onlineUser = Ext.create('Ext.tree.Panel', { 
            title : '    ', 
            rootVisible : false, 
            region : 'east', 
            width : 150, 
            lines : false, 
            useArrows : true, 
            autoScroll : true, 
            split : true, 
            iconCls : 'user-online', 
            store : Ext.create('Ext.data.TreeStore', { 
                  root : { 
                    text : '    ', 
                    expanded : true, 
                    children : [] 
                  } 
                }) 
          }); 
      var title = '   :' + user; 
      //     
      var win = Ext.create('Ext.window.Window', { 
            title : title + ' (   )', 
            layout : 'border', 
            iconCls : 'user-win', 
            minWidth : 650, 
            minHeight : 460, 
            width : 650, 
            animateTarget : 'websocket_button', 
            height : 460, 
            items : [dialog,onlineUser], 
            border : false, 
            listeners : { 
              render : function() { 
                initWebSocket(); 
              } 
            } 
          }); 
 
      win.show(); 
 
      //     
      function send() { 
        var message = {}; 
        if (websocket != null) { 
          if (input.getValue()) { 
            Ext.apply(message, { 
                  from : user, 
                  content : input.getValue(), 
                  timestamp : new Date().getTime(), 
                  type : 'message' 
                }); 
            websocket.send(JSON.stringify(message)); 
            //output.receive(message); 
            input.setValue(''); 
          } 
        } else { 
          Ext.Msg.alert('  ', '     ,      !'); 
        } 
      } 
    }); 
위의 코드 는 페이지 가 불 러 온 후 서버 에 자동 으로 연결 되 고 디 스 플레이 인터페이스 를 만 드 는 코드 입 니 다.
주의 하 다.
주의해 야 할 두 가 지 는 배치 가 끝 난 후에 tomcat 응용 디 렉 터 리 에 있 는 lib 디 렉 터 리 에 있 는 catalina.jar 와 tomcat-coyote.jar 를 삭제 해 야 합 니 다.예 를 들 어 프로젝트 의 lib 디 렉 터 리 는 D:\workspace\WebSocket\WebRoot\WEB-INF\lib 이 고 배 치 된 응용 lib 디 렉 터 리 는 D:\tools\apache-tomcat-7.0.32\\webapps\WebSocket\WEB-INF\lib 입 니 다.배치 디 렉 터 리 의 lib 디 렉 터 리 에 jar 두 개 를 연결 하면 됩 니 다.그렇지 않 으 면 Could not initialize class.com.ibcio.WebSocketmessageServlet 오류 가 발생 했 습 니 다.기억 하 십시오.
연결 이 되 지 않 는 다 면 최신 tomcat 를 다운로드 하 십시오.그 버 전의 tomcatcreateWebSocketInbound 는 request 인자 가 없 는 것 을 잊 었 습 니 다.현재 이 코드 는 이 인자 가 있 습 니 다.7.0.3XX 버 전 은 모두 이 인자 가 있 습 니 다.기억 하 십시오.
총결산
웹 소켓 을 이용 하여 서버 푸 시 를 개발 하 는 것 은 매우 편리 하 다.이것 은 간단 한 응용 이 고 사실은 웹 RTC 와 결합 하여 영상 채 팅 과 음성 채 팅 을 실현 할 수 있다.
인 스 턴 스 다운로드
다운로드 주소:demo
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기