Jetty7.5.1+Ext4.2.1+websocket实例

        本例子是为了实现在websocket通信,由有台来推送消息来改变前台的一些状态信息,下来就来介绍一个小例子,请大家多多指教!

      在html5的规范中,websocket是一种很受欢迎的技术,作为下一代客服端与服务器异步通信方法,该方法取代了单个的TCP套接字,使用ws或wss协议,可用于任意的客户端和服务器程序。 WebSocket目前由W3C进行标准化。WebSocket已经受到Firefox 4、Chrome 4、Opera 10.70以及Safari 5等浏览器的支持。 

轮询和 WebSocket 实现方式的网络负载对比图如下,凸显出websocket的巨大优势:


下面说说websocket的整个流程吧!

WebSocket需要通过握手连接,类似于TCP它也需要客户端和服务器端进行握手连接,连接成功后才能相互通信。 以下就是一个握手时序图:

WebSocket握手的过程:当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址为url的WebServer建立握手连接的过程。两种情况为:1. Browser与WebSocket服务器通过TCP三次握手建立连接,如果这个建立连接失败,那么后面的过程就不会执行,Web应用程序将收到错误消息通知。2.在TCP建立连接成功后,Browser通过http协议传送WebSocket支持的版本号,协议的字版本号,原始地址,主机地址等等一些列字段给服务器端。

当Browser收到服务器回复的数据包后,如果数据包内容、格式都没有问题的话,就表示本次连接成功,触发onopen消息,此时Web开发者就可以在 此时通过send接口想服务器发送数据。否则,握手连接失败,Web应用程序会收到onerror消息,并且能知道连接失败的原因。  本实例实在Jetty7.5.1+Ext4.2.1上实现的目的是想Ext中使用websocket 推送后台消息,而不用浏览器去不停得请求,前台部分js代码为:

//用于展示来自后台的信息
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}) :{content}</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');
		me.store.add(message);
		if (me.el.dom) {
			me.el.dom.scrollTop = me.el.dom.scrollHeight;
		}
	}
});

Ext.onReady(function() {
	
			//创建消息展示容器
			var output = Ext.create('MessageContainer', {
						region : 'center'
					});
				Ext.cre
			
			//展示窗口
			var tip = Ext.create('Ext.window.Window', {
						title : '后台消息提示',
						layout : 'border',
						iconCls : 'user-win',
						width : 300,
						animateTarget : 'websocket_button',
						height : 200,
						border : false,
						html:'此为展示模块',
						//bodyStyle: 'background:#ffc; padding:10px;',
						y : 300,
						x : 1100
					});
			tip.show();
			var websocket;

			//初始话WebSocket
			function initWebSocket() {
				if (window.WebSocket) {
					websocket = new WebSocket(encodeURI('ws://localhost:8080/Chat/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 == 'add_height'){
							tip.setHeight(300);
						}else if(message.type == 'add_width'){
							tip.setWidth(400);
						}else if(message.type == 'alter_title'){
							tip.setTitle('<font color="#ff0">笑话一则</font>');
						}else if(message.type == 'alter_content'){
							tip.update('<p>有一天,小明在房间里读古文,爸爸进来了问:小明,你在读什么书啊?' +
										   '小明:古文,爸爸很生气的说:你再说一遍?小明大声的喊了一句:古文,' +
										   '后来,小明莫名其妙的就被爸爸打了一顿。。。</p>');
						}else if(message.type == 'hide_window'){
							tip.setVisible(false);
						}else if(message.type == 'show_window'){
							tip.setVisible(true);
						}else if(message.type == 'change_bg'){
							tip.setBodyStyle('background:#ffc; padding:10px;');
						}else if(message.type == 'change_icon'){
							tip.setIconCls('user-online');
						}
					}
				}
			};

			
			var title = 'Extjs+websocket测试';
			//信息窗口
			var win = Ext.create('Ext.window.Window', {
						title : title+ '  (已连接后台)',
						layout : 'border',
						iconCls : 'user-win',
						minWidth : 550,
						minHeight : 360,
						width : 550,
						animateTarget : 'websocket_button',
						height : 360,
						items : [output],
						
						border : false,
						y : 300,
						x : 400,
						listeners : {
							render : function() {
								initWebSocket();
							}
						}
					});
			
			win.show();
		});

代码中通过new websocket 得到链接触发onpen()提示前台已近取得连接,当连接断开或链接失败时,分别执行onclose(),onerror()给予提示,其中最重要的函数为onmessage(),由他来接收后台发送的消息,然后根据消息的type值来做出相应的反应,本例中就有多个type值,来达到修改Ext中不同属性的目的。其中ext代码为给出。

后台通过一个继承WebSocketServlet类的一个servlet类来处理ws或wss的请求,此类中实现一个doWebSocketConnect()方法,该方法返回一个Websocket对象,代码如下:

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.websocket.WebSocketServlet;

public class WebSocket  extends WebSocketServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static int ONLINE_USER_COUNT = 1;
	
	public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(
			HttpServletRequest arg0, String arg1) {
		// TODO Auto-generated method stub
		System.out.println("do websocketconnetion");
		return new OnText();
	}

}

接下来我需要新建一个实现了OnTextMessage的类OnText,在这个类中必须实现三个方法,它们是onClose(),onPen(),onMessage(),用处与前台对应,值得注意的是,在onPen()函数中我们拿到了connction对象,代码如下:

package net.haige;

import java.io.IOException;
import java.util.Date;




import net.sf.json.JSONObject;
import net.sf.json.util.NewBeanInstanceStrategy;

import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;

public class OnText implements OnTextMessage ,Runnable {
	
	public Connection conn;
	public JSONObject result;
	public static String CONSLE = "控制台";
	public static String TYPE_1 = "message";
	public static String TYPE_2 = "add_height";
	public static String TYPE_3 = "add_width";
	public static String TYPE_4 = "alter_title";
	public static String TYPE_5 = "alter_content";
	public static String TYPE_6 = "hide_window";
	public static String TYPE_7 = "show_window";
	public static String TYPE_8 = "change_bg";
	public static String TYPE_9 = "change_icon";



	public OnText(){
		System.out.println("OnText");
	};
	

	public void onClose(int arg0, String arg1) {
		// TODO Auto-generated method stub
		System.out.println("onclose");
	}
	//链接事件触发
	public void onOpen(Connection conn) {
		// TODO Auto-generated method stub
		System.out.println("onOpen");
	    this.conn = conn;
	    //向用户发送连线消息
/*		JSONObject result = new JSONObject();
		result.element("type", "message");
		result.element("from", "控制台");
		result.element("timestamp", new Date().getTime());
		result.element("content", "");*/
		String content = "已经通过websocket与后台取得了连接";
		initMessage(CONSLE, TYPE_1, content);
		sendMessage(result.toString());
		String protocal = conn.getProtocol();
		System.out.println("连接的端口号:"+conn.toString());
		new Thread(this).start();
	}
	/*
	 * 本实例不会使用到来自客服端的消息
	 */	
	public void onMessage(String message) {
		// TODO Auto-generated method stub
		System.out.println("onMessage");
	}
	//发送消息函数
	public void sendMessage(String info){
			try {
				this.conn.sendMessage(info);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
	}


	public void run() {
		// TODO Auto-generated method stub
		try {
			System.out.println("run......");
	
			//增加高度
			String content = "3秒钟后后台推送消息增加窗口高度(+100)";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_2, "");
			sendMessage(result.toString());
			
			content = "高度增加完成!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//增加宽度
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息增加窗口宽度(+100)";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_3, content);
			sendMessage(result.toString());
			content = "宽度增加完成!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改标题
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息修改窗口标题";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_4, content);
			sendMessage(result.toString());
			content = "标题修改完成!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改内容
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息修改窗口内容";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_5, content);
			sendMessage(result.toString());
			content = "内容修改完成!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改内容
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息窗口消失";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_6, content);
			sendMessage(result.toString());
			content = "窗口消失!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改内容
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息窗口再现";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_7, content);
			sendMessage(result.toString());
			content = "窗口再现!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改背景
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息窗口背景更改";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_8, content);
			sendMessage(result.toString());
			content = "窗口背景修改!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//更改图标
			Thread.sleep(2000);
			content = "3秒钟后后台推送消息窗口标题图标";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());

			Thread.sleep(3000);
			initMessage(CONSLE, TYPE_9, content);
			sendMessage(result.toString());
			content = "窗口标题图标已修改!";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
			//结束
			System.out.println("end......");
			content = "websocket消息推送在Extjs中使用事例结束";
			initMessage(CONSLE, TYPE_1, content);
			sendMessage(result.toString());
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void initMessage(String from, String type,String content){
		result = new JSONObject();
		result.element("type", type);
		result.element("from", from);
		result.element("timestamp", new Date().getTime());
		result.element("content", content);
	}
}

最后展示例子运行效果截图如下:






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值