JavaScript和java实现websocket

 websocket可以吧他理解成java下的socket连接,他客户端和服务端你可以相互长连接发送消息,下面介绍如何在前端和后台建立一个websocket连接

一、java后台,首先可以吧websocket理解成一个servlet,这样就需要一个servlet类:

package main.java.test.websocket;

import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.websocket.WebSocketServlet;

public class WebSocketInitServlet extends WebSocketServlet {
	private static final long serialVersionUID = -7302427588920888589L;

	/**
	 * websocket建立连接
	 */
	@Override
	public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(
			HttpServletRequest request, String arg1) {
		return new WebSocket();
	}
}
这个类只有一个覆盖方法,就是建立连接则返回一个websocket实例,websocket实例的代码:
package main.java.test.websocket;

import java.util.List;

import net.sf.json.JSONObject;
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;

import com.sun.istack.internal.logging.Logger;

public class WebSocket implements OnTextMessage {

	private static final Logger log = Logger.getLogger(WebSocket.class);
	
	/**
	 * websocket连接
	 */
	private Connection conn = null;

	/**
	 * websocket关闭事件触发
	 */
	@Override
	public void onClose(int arg0, String arg1) {
		log.info("onClose begin.  arg0:"+arg0+" arg1:"+arg1+" conn:"+conn);
		List<WebSocketService> services =  WebSocketServiceManager.getInstance().getServiesByWS(this);
		for(WebSocketService service:services){
			service.stopService();
		}
		removeSocket(this);
		removeSocketServices(this);
		
		log.info("onClose end.  arg0:"+arg0+" arg1:"+arg1+" conn:"+conn);	
	}

	/**
	 * websocket连接建立触发
	 */
	@Override
	public void onOpen(Connection conn) {
		// 如果客户端在这个MaxIdleTime中都没有活动,则它会自动结束
		log.info("WebSocket onOpen. conn:"+conn.toString()+""+ conn.getMaxIdleTime()+" class:"+conn.getClass());
		conn.setMaxIdleTime(Integer.MAX_VALUE);
		this.conn = conn;
		addSocket(this);
		System.out.println("服务端websocket连接建立");
	}

	/**
	 * websocket收到消息触发
	 */
	@Override
	public void onMessage(String data) {
		
		log.info("onMessage. receive a Messag:" + data);
		JSONObject jsonObject = JSONObject.fromObject(data);
		System.out.println("name="+jsonObject.getString("name")+"  age="+jsonObject.getString("age"));
		/*WebSocketMessage webSocketMessage = (WebSocketMessage)JSONObject.toBean(jsonObject, WebSocketMessage.class);	
		OnMessageThread onMessageThread =new OnMessageThread(this,webSocketMessage);
		new Thread(onMessageThread).start();*/
		String jsonMsg = JSONObject.fromObject(jsonObject).toString();
		sendMessage(jsonMsg) ;
	}
	
	class OnMessageThread implements Runnable{
		
		private WebSocket ws = null;
		
		private WebSocketMessage wsMessage = null;
		
		public OnMessageThread(WebSocket ws,WebSocketMessage webSocketMessage) {  
			this.ws = ws;  
			this.wsMessage = webSocketMessage;  
		}
		
		public void run(){
			//打印websocket信息
			log.info("OnMessageThread begin to run. WebSocket:"+ws);
			int msgType = wsMessage.getType();
			switch (msgType) {
		        case WebSocketConstants.START://打开业务页面,开始推送
		        	log.info("OnMessageThread run. START:"+wsMessage.getBizName());
		        	//获取对应的service实例,一般而言,该实例是单例的.但是在这里是多利的,单例会有问题
		        	WebSocketService webSocketService = WebSocketServiceFactory.getInstance().buildWebSocketService(wsMessage.getBizName());
		    		//这里用的是set方法,业务实现必须保证set方法的效果是:一个服务能够将其加入到自己要通知的目标客户端的列表当中去
		        	webSocketService.setWebSocket(ws);
		        	//与上面的方法有同样的要求:一个业务可以同时推送给多个不同的客户端,同时,不同客户端的参数可以是不同的
		    		webSocketService.setWebSocketMessage(wsMessage);
		    		
		    		//加入到manager管理的service列表中
		    		log.info("OnMessageThread run. add service to manager. BizName:"+wsMessage.getBizName()+" webSocketService[hashcode]:"+webSocketService.hashCode()+" webSocketService[className]:"+webSocketService.getClass().getName());
		    		addService(wsMessage.getBizName(), webSocketService);
		    		log.info("OnMessageThread run. notifyService the service. webSocketService[hashcode]:"+webSocketService.hashCode());
		    		webSocketService.notifyService();
		            break;
		        case WebSocketConstants.STOP://关闭页面,停止推送
		        	log.info("OnMessageThread run. STOP:"+wsMessage.getBizName());
		        	WebSocketService service = removeService(wsMessage.getBizName(),ws);
		        	if(service != null){
		        		service.stopService();
		        	}
		            break;
		        default:
		        	log.warning("----------onMessage type error-------------");
			}
			
			log.info("OnMessageThread end to run. WebSocket:"+ws);
		}  
	};
	/**
	 * websocket发送消息接口
	 * @param message
	 */
	public void sendMessage(String message){
		try{
			log.info("sendMessage. message:"+message);
			conn.sendMessage(message);
		}catch(Exception e){
			log.warning("sendMessage error,close the conn and clear the resource. msg:"+e.getMessage(),e);
			removeSocket(this);
			removeSocketServices(this);
			closeConnection();
		}
	}
	
	/**
	 * 关闭连接
	 */
	private void closeConnection(){
		conn.close();
	}
	
	/**
	 * 添加socket
	 * @param webSocket
	 */
	private void addSocket(WebSocket webSocket){
		log.info("addSocket webSocket:"+webSocket);
		new WebSocketManager().getWebSocketList().add(webSocket);
	}
	
	/**
	 * 删除socket
	 * @param webSocket
	 */
	private void removeSocket(WebSocket webSocket){
		new WebSocketManager().getWebSocketList().remove(webSocket);
	}
	
	/**
	 *这种方式太绕,应该是ws->biz->service的方式来处理。当一个ws 关闭时,直接清除对应的map就可以
	 * 添加服務对象
	 * @param bizName
	 * @param webSocketService
	 */
	private void addService(String bizName,WebSocketService webSocketService){
		WebSocketServiceManager.getInstance().addService(bizName, webSocketService);
	}
	
	private void addService(WebSocket ws,String bizName,WebSocketService webSocketService){
		WebSocketServiceManager.getInstance().addService(bizName, webSocketService);
	}
	
	/**
	 * 删除服务对象
	 * @param bizName
	 * @param webSocket
	 * @return
	 */
	private WebSocketService removeService(String bizName,WebSocket webSocket){
		WebSocketService service = WebSocketServiceManager.getInstance().removeService(bizName, webSocket);
		return service;
	}
	
	/**
	 * 刪除socket关联的所有服務
	 * @param webSocket
	 */
	private void removeSocketServices(WebSocket webSocket){
		WebSocketServiceManager.getInstance().removeServices(webSocket);
	}
}
 

 这里面只需要注意一些关于连接的一些覆盖方法,当触发是会自动进入那一个方法,

后台的代码就完了,但是既然是servlet就必须在web中配置。

<servlet>
		<servlet-name>websocket</servlet-name>
		<servlet-class>main.java.test.websocket.WebSocketInitServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>websocket</servlet-name>
		<url-pattern>/websocket.ws</url-pattern>
	</servlet-mapping>

 二、JavaScript实现

一般都是java后台为服务器,前端为客户端,

var Webchannel = {
    wso: "",
    wsUrl: "ws://" + window.location.host + "/websocket.ws",
    busiTypes: {},
    initWebsocket: function () {
        if ("WebSocket" in window) {
            wso = new WebSocket(Webchannel.wsUrl);
        } else if ("MozWebSocket" in window) {
            wso = new MozWebSocket(Webchannel.wsUrl);
        } else {
            console.log("The browser don't support the WebSocket");
        }
        wso.onopen = function () {
            console.log("connect success");
            alert("客户端websocket建立");
            debugger
            var json ={};
            json.name="dengwei";
            json.age="23";
            var jsonData= JSON.stringify(json);
        	wso.send(jsonData);
        };
        wso.onclose = function () {
        	try{ 
                wso = new WebSocket(Webchannel.wsUrl); 
            }catch(e){ 
                console.log("disconnect error"+e); 
            } 
            console.log("disconnect success");
        };
        wso.onerror = function () {
            console.log("sorry,it get error");
        };
        wso.onmessage = function (receiveMsg) {
            /*var jsonObject = eval('(' + receiveMsg.data + ')')
            var callback = Webchannel.busiTypes[jsonObject.bizName];
            callback( .data);*/
        	alert(receiveMsg.data.name);
        }
    },
    sendMsg:function(data){
    	var jsonData= JSON.stringify(data);
    	wso.send(jsonData);
    },
    startPush: function (bizName, data) {
        var json = {};
        json.bizName = bizName;
        json.data = data;
        json.type = "1";
        var jsonData = JSON.stringify(json);
        var flag = 0;
        var istrue = true;
        if (1 == wso.readyState) {
            wso.send(jsonData);
        } else {
            function isOpen() {
                if (!istrue) {
                    window.clearInterval(servalStart);
                } else {
                    if (1 == wso.readyState) {
                        wso.send(jsonData);
                        istrue = false;
                    } else {
                        flag = flag + 1;
                        if (flag > 29) {
                            if(Webchannel.wso != "" && Webchannel.wso != undefined){
                            	Webchannel.closeWebSocket();
                            	Webchannel.initWebsocket();
                            	istrue = false;
                            }
                        }
                    }
                }
            }

            servalStart = window.setInterval(isOpen, 1000);
        }
    },

    stopPush: function (bizName) {
        var json = {};
        json.bizName = bizName;
        json.data = "";
        json.type = "2";
        var jsonData = JSON.stringify(json);
        var flag = 0;
        var istrue = true;
        if (1 == wso.readyState) {
            wso.send(jsonData);
        } else {
            function isOpen() {
                if (!istrue) {
                    window.clearInterval(servalFinish);
                } else {
                    if (1 == wso.readyState) {
                        wso.send(jsonData);
                        istrue = false;
                    } else {
                        flag = flag + 1;
                        if (flag > 9) {
                            istrue = false;
                        }
                    }
                }
            }

            servalFinish = window.setInterval(isOpen, 1000);
        }
    },
    closeWebSocket: function () {
        if (1 == wso.readyState) {
            wso.close();
            wso = "";
        }
    },
    regBusitype: function (busiType, backFunction) {
        Webchannel.busiTypes[busiType] = backFunction;
    }
};
Webchannel.initWebsocket()

 这段代码就是连接服务器的websocket并进行通信,代码很简单就不解释了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值